diff --git a/app/scripts/deploy-cloudrun.sh b/app/scripts/deploy-cloudrun.sh new file mode 100644 index 0000000..b62b84b --- /dev/null +++ b/app/scripts/deploy-cloudrun.sh @@ -0,0 +1,154 @@ +#!/bin/bash + +# Exit on error +set -e + +# Configuration +PROJECT_ID="sapient-terrain-419221" +ARTIFACT_REGION="us" # Multi-region for Artifact Registry +CLOUDRUN_REGION="us-central1" +SERVICE_NAME="bastienlaw-remix-prod" +ARTIFACT_REGISTRY="docker.pkg.dev" +REPOSITORY="bastienlaw" +HEALTH_CHECK_PATH="/_health" # Define health check path separately + +# Parse command line arguments +SKIP_BUILD=false +SKIP_PUSH=false +SKIP_DEPLOY=false + +while [[ $# -gt 0 ]]; do + case $1 in + --skip-build) + SKIP_BUILD=true + shift + ;; + --skip-push) + SKIP_PUSH=true + shift + ;; + --skip-deploy) + SKIP_DEPLOY=true + shift + ;; + --help) + echo "Usage: $0 [options]" + echo "Options:" + echo " --skip-build Skip Docker build step" + echo " --skip-push Skip pushing to Artifact Registry" + echo " --skip-deploy Skip Cloud Run deployment" + exit 0 + ;; + *) + echo "Unknown option: $1" + exit 1 + ;; + esac +done + +# Ensure we're in the right directory +cd "$(dirname "$0")/.." + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${YELLOW}Starting deployment process...${NC}" + +# Check required tools only if needed +if [ "$SKIP_BUILD" = false ] || [ "$SKIP_PUSH" = false ]; then + if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: docker is not installed${NC}" + exit 1 + fi +fi + +if [ "$SKIP_PUSH" = false ] || [ "$SKIP_DEPLOY" = false ]; then + if ! command -v gcloud &> /dev/null; then + echo -e "${RED}Error: gcloud CLI is not installed${NC}" + exit 1 + fi +fi + +# Authentication and configuration (only if needed) +if [ "$SKIP_PUSH" = false ] || [ "$SKIP_DEPLOY" = false ]; then + echo -e "${YELLOW}Checking Google Cloud authentication...${NC}" + + # Check for existing credentials + if ! gcloud auth print-identity-token &>/dev/null; then + echo -e "${YELLOW}No valid credentials found. Logging in...${NC}" + gcloud auth login --update-adc + gcloud auth application-default set-quota-project ${PROJECT_ID} + else + echo -e "${GREEN}Using existing credentials${NC}" + fi + + # Get and verify the current user + CURRENT_USER=$(gcloud config get-value account) + if [ -z "$CURRENT_USER" ]; then + echo -e "${RED}Error: No active Google Cloud account${NC}" + exit 1 + fi + echo -e "${YELLOW}Current user: ${CURRENT_USER}${NC}" + + # Set the project + gcloud config set project ${PROJECT_ID} +fi + +# Docker authentication (only if needed) +if [ "$SKIP_PUSH" = false ]; then + echo -e "${YELLOW}Checking Docker authentication...${NC}" + # Check if Docker credentials exist + if ! docker-credential-gcloud list | grep -q "${ARTIFACT_REGION}-docker.pkg.dev"; then + echo -e "${YELLOW}Configuring Docker authentication...${NC}" + gcloud auth configure-docker ${ARTIFACT_REGION}-${ARTIFACT_REGISTRY} --quiet + else + echo -e "${GREEN}Docker credentials already configured${NC}" + fi +fi + +# Set up image name +IMAGE_NAME="${ARTIFACT_REGION}-${ARTIFACT_REGISTRY}/${PROJECT_ID}/${REPOSITORY}/${SERVICE_NAME}:latest" + +# Build Docker image if not skipped +if [ "$SKIP_BUILD" = false ]; then + echo -e "${YELLOW}Building Docker image...${NC}" + docker build -t ${IMAGE_NAME} . +fi + +# Push to Artifact Registry if not skipped +if [ "$SKIP_PUSH" = false ]; then + echo -e "${YELLOW}Pushing image to Artifact Registry...${NC}" + docker push ${IMAGE_NAME} +fi + +# Deploy to Cloud Run if not skipped +if [ "$SKIP_DEPLOY" = false ]; then + echo -e "${YELLOW}Deploying to Cloud Run...${NC}" + gcloud run deploy ${SERVICE_NAME} \ + --image ${IMAGE_NAME} \ + --project ${PROJECT_ID} \ + --region ${CLOUDRUN_REGION} \ + --platform managed \ + --allow-unauthenticated \ + --port 3000 \ + --set-env-vars="NODE_ENV=production" \ + --min-instances=0 \ + --max-instances=10 \ + --memory=512Mi \ + --cpu=1 \ + --timeout=300 \ + --concurrency=80 \ + --session-affinity \ + --cpu-throttling \ + --execution-environment=gen2 \ + --service-account="${SERVICE_NAME}-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --tag=latest \ + --ingress=all \ + --labels="env=prod,app=bastienlaw" \ + --use-http2 +fi + +echo -e "${GREEN}Process completed successfully!${NC}" \ No newline at end of file diff --git a/app/scripts/push-image.sh b/app/scripts/push-image.sh new file mode 100644 index 0000000..d7aa6be --- /dev/null +++ b/app/scripts/push-image.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +# Exit on error +set -e + +# Configuration +PROJECT_ID="sapient-terrain-419221" +ARTIFACT_REGION="us" # Multi-region for Artifact Registry +REPOSITORY="bastienlaw" +IMAGE_NAME="bastienlaw-remix" +TAG="latest" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Ensure we're in the right directory +cd "$(dirname "$0")/.." + +# Check if docker is installed +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: docker is not installed${NC}" + exit 1 +fi + +# Check if gcloud is installed +if ! command -v gcloud &> /dev/null; then + echo -e "${RED}Error: gcloud CLI is not installed${NC}" + exit 1 +fi + +# First, create the repository if it doesn't exist +echo -e "${YELLOW}Ensuring Artifact Registry repository exists...${NC}" +gcloud artifacts repositories create ${REPOSITORY} \ + --repository-format=docker \ + --location=${ARTIFACT_REGION} \ + --description="Repository for Bastien Law website" \ + --quiet || true + +# Full image name for Artifact Registry +FULL_IMAGE_NAME="${ARTIFACT_REGION}-docker.pkg.dev/${PROJECT_ID}/${REPOSITORY}/${IMAGE_NAME}:${TAG}" + +echo -e "${YELLOW}Configuring Docker authentication...${NC}" +gcloud auth configure-docker ${ARTIFACT_REGION}-docker.pkg.dev + +echo -e "${YELLOW}Building Docker image...${NC}" +docker build -t ${IMAGE_NAME}:${TAG} . + +echo -e "${YELLOW}Tagging image for Artifact Registry...${NC}" +docker tag ${IMAGE_NAME}:${TAG} ${FULL_IMAGE_NAME} + +echo -e "${YELLOW}Pushing image to Artifact Registry...${NC}" +docker push ${FULL_IMAGE_NAME} + +echo -e "${GREEN}Successfully pushed image to Artifact Registry:${NC}" +echo -e "${GREEN}${FULL_IMAGE_NAME}${NC}" \ No newline at end of file diff --git a/app/scripts/setup-service-account.sh b/app/scripts/setup-service-account.sh new file mode 100644 index 0000000..0916b2a --- /dev/null +++ b/app/scripts/setup-service-account.sh @@ -0,0 +1,81 @@ +#!/bin/bash + +# Exit on error +set -e + +# Configuration +PROJECT_ID="sapient-terrain-419221" +SERVICE_NAME="bastienlaw-remix-prod" +USER_EMAIL="jimmy.briggs@noclocks.dev" +ARTIFACT_REGION="us" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +echo -e "${YELLOW}Setting up service account and permissions...${NC}" + +# Create service account if it doesn't exist +gcloud iam service-accounts create ${SERVICE_NAME}-sa \ + --display-name="Bastien Law Remix Production Service Account" \ + --project=${PROJECT_ID} || true + +# Grant necessary roles to service account +echo -e "${YELLOW}Granting roles to service account...${NC}" + +# Cloud Run roles +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="serviceAccount:${SERVICE_NAME}-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/run.invoker" + +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="serviceAccount:${SERVICE_NAME}-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/run.developer" + +# Artifact Registry roles +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="serviceAccount:${SERVICE_NAME}-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/artifactregistry.reader" + +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="serviceAccount:${SERVICE_NAME}-sa@${PROJECT_ID}.iam.gserviceaccount.com" \ + --role="roles/artifactregistry.writer" + +# Grant user permissions +echo -e "${YELLOW}Granting permissions to user...${NC}" + +# Service Account User role +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="user:${USER_EMAIL}" \ + --role="roles/iam.serviceAccountUser" + +# Cloud Run Admin role +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="user:${USER_EMAIL}" \ + --role="roles/run.admin" + +# Artifact Registry Admin role +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="user:${USER_EMAIL}" \ + --role="roles/artifactregistry.admin" + +# Service Account Token Creator role +gcloud projects add-iam-policy-binding ${PROJECT_ID} \ + --member="user:${USER_EMAIL}" \ + --role="roles/iam.serviceAccountTokenCreator" + +# Create Artifact Registry repository if it doesn't exist +echo -e "${YELLOW}Creating Artifact Registry repository...${NC}" +gcloud artifacts repositories create bastienlaw \ + --repository-format=docker \ + --location=${ARTIFACT_REGION} \ + --description="Repository for Bastien Law website" \ + --project=${PROJECT_ID} || true + +# Configure Docker authentication +echo -e "${YELLOW}Configuring Docker authentication...${NC}" +gcloud auth configure-docker ${ARTIFACT_REGION}-docker.pkg.dev --quiet + +echo -e "${GREEN}Setup completed successfully!${NC}" \ No newline at end of file diff --git a/app/scripts/test-docker.sh b/app/scripts/test-docker.sh new file mode 100644 index 0000000..79dda33 --- /dev/null +++ b/app/scripts/test-docker.sh @@ -0,0 +1,106 @@ +#!/bin/bash + +# Exit on error +set -e + +# Configuration +IMAGE_NAME="bastienlaw-test" +CONTAINER_NAME="bastienlaw-test" +PORT=3000 + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' + +# Ensure we're in the right directory +cd "$(dirname "$0")/.." + +# Function to cleanup on exit +cleanup() { + echo -e "\n${YELLOW}Cleaning up...${NC}" + docker stop ${CONTAINER_NAME} 2>/dev/null || true + docker rm ${CONTAINER_NAME} 2>/dev/null || true + echo -e "${GREEN}Cleanup complete${NC}" +} + +# Register cleanup function to run on script exit +trap cleanup EXIT + +echo -e "${YELLOW}Starting local Docker test...${NC}" + +# Check if docker is installed +if ! command -v docker &> /dev/null; then + echo -e "${RED}Error: docker is not installed${NC}" + exit 1 +fi + +# Stop and remove existing container if it exists +echo -e "${YELLOW}Removing any existing test containers...${NC}" +docker stop ${CONTAINER_NAME} 2>/dev/null || true +docker rm ${CONTAINER_NAME} 2>/dev/null || true + +# Build the image +echo -e "${YELLOW}Building Docker image...${NC}" +docker build -t ${IMAGE_NAME}:latest . + +# Run the container +echo -e "${YELLOW}Starting container...${NC}" +docker run -d \ + --name ${CONTAINER_NAME} \ + -p ${PORT}:${PORT} \ + -e NODE_ENV=production \ + ${IMAGE_NAME}:latest + +# Wait for container to start +echo -e "${YELLOW}Waiting for container to start...${NC}" +sleep 5 + +# Check container status +if [ "$(docker inspect -f {{.State.Running}} ${CONTAINER_NAME})" != "true" ]; then + echo -e "${RED}Container failed to start${NC}" + echo -e "${YELLOW}Container logs:${NC}" + docker logs ${CONTAINER_NAME} + exit 1 +fi + +# Test health endpoint +echo -e "${YELLOW}Testing health endpoint...${NC}" +HEALTH_CHECK=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:${PORT}/_health) +if [ "$HEALTH_CHECK" == "200" ]; then + echo -e "${GREEN}Health check passed${NC}" +else + echo -e "${RED}Health check failed with status: ${HEALTH_CHECK}${NC}" + echo -e "${YELLOW}Container logs:${NC}" + docker logs ${CONTAINER_NAME} + exit 1 +fi + +# Test main application endpoint +echo -e "${YELLOW}Testing main application endpoint...${NC}" +APP_CHECK=$(curl -s -o /dev/null -w "%{http_code}" http://localhost:${PORT}) +if [ "$APP_CHECK" == "200" ]; then + echo -e "${GREEN}Application check passed${NC}" +else + echo -e "${RED}Application check failed with status: ${APP_CHECK}${NC}" + echo -e "${YELLOW}Container logs:${NC}" + docker logs ${CONTAINER_NAME} + exit 1 +fi + +# Show container resource usage +echo -e "${YELLOW}Container resource usage:${NC}" +docker stats ${CONTAINER_NAME} --no-stream + +# Show container logs +echo -e "${YELLOW}Container logs:${NC}" +docker logs ${CONTAINER_NAME} + +echo -e "${GREEN}All tests passed successfully!${NC}" +echo -e "${YELLOW}Container is still running for manual testing at http://localhost:${PORT}${NC}" +echo -e "${YELLOW}Run 'docker stop ${CONTAINER_NAME}' when finished testing${NC}" + +# Keep the script running to maintain the container +echo -e "${YELLOW}Press Ctrl+C to stop the container and cleanup${NC}" +while true; do sleep 1; done \ No newline at end of file