-
Notifications
You must be signed in to change notification settings - Fork 0
Deploy to GCP using Terraform #4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
- Create Terraform manifests for Cloud Run, Artifact Registry, and Secret Manager - Add a deployment script to automate infrastructure provisioning and image builds - Configure Cloud Run for free-tier eligibility (scale-to-zero, idle CPU) - Update Dockerfile and ignore files for production compatibility - Support Rails master key management via GCP Secret Manager Co-authored-by: Claude Code <noreply@anthropic.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull request overview
Adds Terraform + a helper deploy script to provision GCP resources (Artifact Registry, Secret Manager, Cloud Run) and deploy the Rails app to Cloud Run.
Changes:
- Introduces Terraform configuration (variables, main resources, outputs) for Cloud Run deployment.
- Adds an example
terraform.tfvarsand adeploy.shscript to provision infra, build/push a Docker image, and update Cloud Run. - Updates repo ignores for Terraform artifacts and adds a
.dockerignore.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| terraform/variables.tf | Defines Terraform inputs for GCP project/region, app name, Rails master key, optional domain. |
| terraform/terraform.tfvars.example | Example values for required Terraform variables. |
| terraform/outputs.tf | Exposes Cloud Run service URL and Artifact Registry image/repo strings. |
| terraform/main.tf | Provisions APIs, Artifact Registry, Secret Manager secret, Cloud Run service + IAM, optional domain mapping. |
| terraform/deploy.sh | Automates terraform apply, Docker build/push, and a gcloud run service update. |
| Dockerfile | Switches Ruby base image reference to docker.io/.... |
| .gitignore | Ignores Terraform local state/vars and related files. |
| .dockerignore | Excludes infra/CI/dev/test/docs artifacts from Docker build context. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| image = "${var.region}-docker.pkg.dev/${var.project_id}/${var.app_name}/${var.app_name}:latest" | ||
|
|
||
| ports { | ||
| container_port = 80 |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cloud Run container is configured to use port 80, but the Docker image runs as a non-root user (UID 1000). Binding to privileged ports (<1024) will fail at runtime, so the service likely won’t start. Use an unprivileged port (typically 8080) and let the app read PORT (already in config/puma.rb).
| container_port = 80 | |
| container_port = 8080 |
| resource "google_secret_manager_secret_version" "rails_master_key" { | ||
| secret = google_secret_manager_secret.rails_master_key.id | ||
| secret_data = var.rails_master_key | ||
| } |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
google_secret_manager_secret_version.secret_data will store the Rails master key value in the Terraform state file in plaintext (even if the input variable is marked sensitive). This is a significant secret-leak risk for anyone with access to state (local disk, CI artifacts, remote backend). Prefer creating the Secret in Terraform but adding versions outside Terraform (e.g., gcloud secrets versions add), or use a secured/encrypted remote backend with strict access controls and avoid committing/retaining local state.
| resource "google_secret_manager_secret_version" "rails_master_key" { | |
| secret = google_secret_manager_secret.rails_master_key.id | |
| secret_data = var.rails_master_key | |
| } | |
| # NOTE: Secret versions (actual Rails master key values) should be | |
| # created outside Terraform (e.g., via `gcloud secrets versions add`) | |
| # to avoid storing secret data in Terraform state. |
| resource "google_cloud_run_v2_service_iam_member" "public" { | ||
| project = google_cloud_run_v2_service.app.project | ||
| location = google_cloud_run_v2_service.app.location | ||
| name = google_cloud_run_v2_service.app.name | ||
| role = "roles/run.invoker" | ||
| member = "allUsers" | ||
| } |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This unconditionally makes the Cloud Run service publicly invokable by allUsers. If this app is not intended to be fully public, this should be gated behind a variable (e.g., public_access = true/false) or use a more restrictive principal, otherwise it’s easy to accidentally expose internal environments.
| # Step 5: Deploy to Cloud Run (update the service to use the new image) | ||
| echo "" | ||
| echo "==> Step 5: Deploying new image to Cloud Run..." | ||
| gcloud run services update "$APP_NAME" \ | ||
| --region "$REGION" \ | ||
| --image "$DOCKER_TAG" \ | ||
| --project "$PROJECT_ID" \ | ||
| --quiet |
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The deploy script updates the Cloud Run service with gcloud run services update after Terraform creates it. This will cause configuration drift from Terraform state and makes future terraform apply runs potentially revert or conflict with the deployed image. Consider making the image tag a Terraform variable and updating it via Terraform, or add a Terraform lifecycle { ignore_changes = [template[0].containers[0].image] } if gcloud is intended to own image updates.
| # Parse project_id and region from tfvars | ||
| PROJECT_ID=$(grep 'project_id' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/') | ||
| REGION=$(grep 'region' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/') | ||
| APP_NAME=$(grep 'app_name' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/' || echo "dill") | ||
|
|
Copilot
AI
Feb 7, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parsing terraform.tfvars with grep/sed is brittle (e.g., it will break if values are unquoted, if there are multiple matching keys, or if a commented line matches). Consider using terraform output -raw (after apply) or terraform console to read values reliably, or enforce/validate the expected tfvars format before continuing.
| # Parse project_id and region from tfvars | |
| PROJECT_ID=$(grep 'project_id' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/') | |
| REGION=$(grep 'region' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/') | |
| APP_NAME=$(grep 'app_name' "$SCRIPT_DIR/terraform.tfvars" | sed 's/.*= *"\(.*\)"/\1/' || echo "dill") | |
| # Initialize Terraform and read variables using terraform console to avoid brittle parsing | |
| ( | |
| cd "$SCRIPT_DIR" | |
| terraform init -input=false >/dev/null | |
| ) | |
| PROJECT_ID=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='var.project_id' | tr -d '\r') | |
| REGION=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='var.region' | tr -d '\r') | |
| APP_NAME=$(cd "$SCRIPT_DIR" && terraform console -input=false -var-file="terraform.tfvars" -execute='try(var.app_name, "dill")' | tr -d '\r' || echo "dill") |
Can you deploy this for free on my GCP? Maybe using terraform?
Superconductor Ticket Implementation