{"id":165766,"date":"2026-04-12T11:27:29","date_gmt":"2026-04-12T08:27:29","guid":{"rendered":"https:\/\/computingforgeeks.com\/deploy-google-cloud-run-terraform\/"},"modified":"2026-04-12T11:27:29","modified_gmt":"2026-04-12T08:27:29","slug":"deploy-google-cloud-run-terraform","status":"publish","type":"post","link":"https:\/\/computingforgeeks.com\/deploy-google-cloud-run-terraform\/","title":{"rendered":"Deploy to Google Cloud Run with Terraform (2026 Guide)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">Cloud Run is Google&#8217;s answer to &#8220;I have a container and I want it on the internet in ninety seconds, with HTTPS, with autoscaling, and without thinking about servers.&#8221; You push an image, Cloud Run provisions the infrastructure, scales to zero when nobody is calling it, scales up when traffic arrives, and you pay per request plus per second of compute time actually consumed. No Kubernetes cluster to manage, no node pools to size, no idle VMs burning money overnight. For many workloads that would have lived on a small GKE cluster or a Compute Engine VM behind a load balancer, Cloud Run is the simpler and cheaper answer.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">This guide walks through building a container image with Cloud Build (no local Docker required), pushing it to Artifact Registry, deploying to Cloud Run via gcloud, testing canary releases with tagged revisions and traffic splitting, the full Terraform equivalent for teams who want everything in code, environment variables and secrets integration, VPC connectors for private backend access, the cost model so you know exactly what you are paying for, and cleanup. Every command was run on a real GCP project in europe-west1 with the real output captured. If you also run workloads on AWS, the closest AWS equivalent is a Fargate-backed ECS service behind an ALB, which needs about ten times more configuration to achieve the same result.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><em>Tested April 2026 on Google Cloud Run (managed) in europe-west1 with gcloud 521 and Cloud Build<\/em><\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cloud Run vs GKE vs Cloud Functions: When to Pick Cloud Run<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Before deploying anything, settle whether Cloud Run is the right fit. Three GCP compute products overlap, and the decision depends on your workload shape.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead><tr><th>Dimension<\/th><th>Cloud Run<\/th><th>GKE Autopilot<\/th><th>Cloud Functions<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>Deployment unit<\/td><td>Container image<\/td><td>Container image (pods)<\/td><td>Source code (zip\/repo)<\/td><\/tr>\n<tr><td>Scale to zero<\/td><td>Yes (default)<\/td><td>No (minimum 1 pod unless using scale-to-zero add-ons)<\/td><td>Yes<\/td><\/tr>\n<tr><td>Cold start<\/td><td>~500ms to 2s (first request)<\/td><td>No cold start (pods always warm)<\/td><td>~200ms to 5s depending on runtime<\/td><\/tr>\n<tr><td>Request timeout<\/td><td>Up to 60 minutes<\/td><td>No limit<\/td><td>Up to 60 minutes (v2)<\/td><\/tr>\n<tr><td>Concurrency<\/td><td>Up to 1000 concurrent requests per instance<\/td><td>Pod-level, no per-instance limit<\/td><td>1 request per instance (v1), 1000 (v2)<\/td><\/tr>\n<tr><td>Persistent connections<\/td><td>WebSockets, gRPC, SSE supported<\/td><td>Full Kubernetes networking<\/td><td>HTTP only (v1), gRPC (v2)<\/td><\/tr>\n<tr><td>Pricing model<\/td><td>Per request + per second of vCPU\/memory<\/td><td>Per vCPU\/memory\/second (always on)<\/td><td>Per invocation + per second of vCPU\/memory<\/td><\/tr>\n<tr><td>Best for<\/td><td>HTTP APIs, web apps, microservices, async workers<\/td><td>Stateful workloads, complex networking, multi-container pods<\/td><td>Event handlers, webhooks, small transformations<\/td><\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud Run is the default pick for any containerized workload that responds to HTTP, gRPC, or event triggers and does not need persistent local state. GKE wins when you need sidecar containers, service mesh, StatefulSets, or the full Kubernetes API surface. Cloud Functions is for the small event-driven jobs where you do not want to think about containers at all. For an overview of all three with a real cost comparison, see our <a href=\"https:\/\/computingforgeeks.com\/gcp-costs-explained\/\">GCP Costs Explained<\/a> guide.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Prerequisites<\/h2>\n\n\n\n<ul class=\"wp-block-list\">\n<li>A GCP project with billing enabled<\/li>\n<li><code>gcloud<\/code> CLI 520+ authenticated (tested on v521.0.0)<\/li>\n<li>Cloud Run, Cloud Build, and Artifact Registry APIs enabled<\/li>\n<\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Enable the APIs in one shot:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud services enable \\\n  run.googleapis.com \\\n  cloudbuild.googleapis.com \\\n  artifactregistry.googleapis.com \\\n  --project=PROJECT_ID<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Build the Container Image with Cloud Build<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">You do not need Docker installed locally. Cloud Build runs in the cloud, builds the image from your source, and pushes it straight to Artifact Registry. First, create an Artifact Registry repository to hold the images:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud artifacts repositories create my-app-repo \\\n  --repository-format=docker \\\n  --location=europe-west1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Write a minimal Go application. The only requirement Cloud Run has is that the container listens on the port specified by the <code>PORT<\/code> environment variable (defaults to 8080):<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>vim main.go<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code code\"><code>package main\n\nimport (\n\t\"fmt\"\n\t\"net\/http\"\n\t\"os\"\n)\n\nfunc main() {\n\tport := os.Getenv(\"PORT\")\n\tif port == \"\" {\n\t\tport = \"8080\"\n\t}\n\thttp.HandleFunc(\"\/\", func(w http.ResponseWriter, r *http.Request) {\n\t\tfmt.Fprintf(w, \"Hello from Cloud Run! Version: 1.0.0\\n\")\n\t})\n\thttp.HandleFunc(\"\/health\", func(w http.ResponseWriter, r *http.Request) {\n\t\tw.WriteHeader(200)\n\t\tfmt.Fprintf(w, \"ok\\n\")\n\t})\n\tfmt.Printf(\"Listening on port %s\\n\", port)\n\thttp.ListenAndServe(\":\"+port, nil)\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The Dockerfile uses a multi-stage build that produces a distroless image under 10 MB. Smaller images mean faster cold starts on Cloud Run because the image pull happens on every scale-from-zero event:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>vim Dockerfile<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code code\"><code>FROM golang:1.24-alpine AS build\nWORKDIR \/app\nCOPY main.go .\nRUN CGO_ENABLED=0 go build -o server main.go\n\nFROM gcr.io\/distroless\/static-debian12\nCOPY --from=build \/app\/server \/server\nCMD [\"\/server\"]<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Submit the build. Cloud Build uploads the source, runs the Dockerfile, and pushes the resulting image to Artifact Registry. The entire process happens in GCP, no local Docker daemon involved:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud builds submit \\\n  --tag europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Build output ends with a SUCCESS line and the full image path:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>ID                                    CREATE_TIME                DURATION  SOURCE     IMAGES                                                                STATUS\nad1faee9-0d2f-4171-b177-5e7617a2debf  2026-04-12T08:20:06+00:00  1M8S      gs:\/\/...   europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v1          SUCCESS<\/code><\/pre>\n\n\n\n<h2 class=\"wp-block-heading\">Deploy to Cloud Run<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">One command creates the service, provisions the HTTPS endpoint, and routes traffic:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run deploy hello-app \\\n  --image=europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v1 \\\n  --platform=managed \\\n  --region=europe-west1 \\\n  --port=8080 \\\n  --allow-unauthenticated \\\n  --min-instances=0 \\\n  --max-instances=3 \\\n  --memory=256Mi \\\n  --cpu=1<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Key flags worth understanding. <code>--allow-unauthenticated<\/code> makes the endpoint public (skip this for internal APIs and add IAM invoker bindings instead). <code>--min-instances=0<\/code> enables scale-to-zero, which is the default and what makes Cloud Run cheap for low-traffic services. <code>--max-instances=3<\/code> caps the horizontal scale so a traffic spike does not produce an unexpected bill. Deployment output:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>Service [hello-app] revision [hello-app-00001-9xv] has been deployed and is serving 100 percent of traffic.\nService URL: https:\/\/hello-app-PROJECT_NUMBER.europe-west1.run.app<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Test the endpoint:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>curl https:\/\/hello-app-PROJECT_NUMBER.europe-west1.run.app\/<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Response from the live service:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>Hello from Cloud Run! Version: 1.0.0<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">HTTPS with a valid Google-managed certificate, autoscaling, and a public URL. Total time from <code>gcloud run deploy<\/code> to a responding endpoint: about thirty seconds.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Canary Deployments with Tagged Revisions<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud Run&#8217;s traffic splitting is one of its strongest features and it works without any external tool. Each deploy creates a new revision. You can tag revisions and route a percentage of traffic to each, which is the simplest canary deployment pattern in any cloud. Update the app to v2 and build a new image:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud builds submit \\\n  --tag europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v2<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Deploy v2 without routing any traffic to it yet. The <code>--no-traffic<\/code> flag creates the revision but leaves all traffic on v1. The <code>--tag=canary<\/code> flag assigns a named tag so you can address the revision directly via a dedicated URL:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run deploy hello-app \\\n  --image=europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v2 \\\n  --region=europe-west1 \\\n  --no-traffic \\\n  --tag=canary<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The canary revision gets its own URL that you can test before sending real traffic to it:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>The revision can be reached directly at https:\/\/canary---hello-app-4humrjh2wq-ew.a.run.app<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Test the canary endpoint and verify v2 responds correctly:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>curl https:\/\/canary---hello-app-4humrjh2wq-ew.a.run.app\/<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code code\"><code>Hello from Cloud Run! Version: 2.0.0 (canary)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Now split traffic. Send 80% to v1 and 20% to the canary:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run services update-traffic hello-app \\\n  --region=europe-west1 \\\n  --to-tags=canary=20<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The traffic configuration is now:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>Traffic:\n  80% hello-app-00001-9xv\n  20% hello-app-00002-zuh\n       canary: https:\/\/canary---hello-app-4humrjh2wq-ew.a.run.app<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the canary looks good, promote it to 100%:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run services update-traffic hello-app \\\n  --region=europe-west1 \\\n  --to-latest<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">If the canary is broken, roll back by sending all traffic to v1:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run services update-traffic hello-app \\\n  --region=europe-west1 \\\n  --to-revisions=hello-app-00001-9xv=100<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The rollback is instant. No new build, no redeploy, just a traffic routing change that takes effect in under two seconds. This is faster than any Kubernetes rollback because there is no pod scheduling involved.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Environment Variables and Secrets<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Most real applications need configuration (database URLs, API keys, feature flags). Cloud Run injects environment variables at deploy time and can mount secrets from <a href=\"https:\/\/computingforgeeks.com\/google-cloud-secret-manager-tutorial\/\">Google Cloud Secret Manager<\/a> as either environment variables or mounted files:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run deploy hello-app \\\n  --image=europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v1 \\\n  --region=europe-west1 \\\n  --set-env-vars=\"APP_ENV=production,LOG_LEVEL=info\" \\\n  --set-secrets=\"DB_PASSWORD=db-password:latest\"<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>--set-secrets<\/code> flag pulls the value from Secret Manager at runtime and injects it as an environment variable. The format is <code>ENV_VAR_NAME=SECRET_NAME:VERSION<\/code>. The Cloud Run service agent must have <code>roles\/secretmanager.secretAccessor<\/code> on the secret. For production, prefer specific version numbers over <code>latest<\/code> to avoid the alias gotcha documented in our <a href=\"https:\/\/computingforgeeks.com\/google-cloud-secret-manager-tutorial\/\">Secret Manager tutorial<\/a>.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">VPC Connector: Access Private Resources<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">By default Cloud Run services can only reach the public internet. If your service needs to talk to a Cloud SQL instance on a private IP, a Memorystore Redis cluster, or any VPC-internal resource, you need a Serverless VPC Access connector. The connector bridges Cloud Run into your VPC:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud compute networks vpc-access connectors create run-connector \\\n  --region=europe-west1 \\\n  --network=default \\\n  --range=10.8.0.0\/28 \\\n  --min-instances=2 \\\n  --max-instances=3<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Then attach the connector to the service:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run deploy hello-app \\\n  --image=europe-west1-docker.pkg.dev\/PROJECT_ID\/my-app-repo\/hello-app:v1 \\\n  --region=europe-west1 \\\n  --vpc-connector=run-connector \\\n  --vpc-egress=private-ranges-only<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">The <code>--vpc-egress=private-ranges-only<\/code> flag routes RFC1918 traffic through the connector and everything else directly to the internet. Use <code>all-traffic<\/code> if you also want public internet egress to go through your VPC (for Cloud NAT or firewall control). The connector has a small monthly cost ($0.01 per hour per instance, so roughly $15 to $22 per month for a 2-3 instance connector). Free tier does not cover it.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Terraform Version<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">The full Cloud Run deployment in Terraform for teams who want everything in code. Uses the <code>google_cloud_run_v2_service<\/code> resource which is the current v2 API:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>vim cloudrun.tf<\/code><\/pre>\n\n\n\n<pre class=\"wp-block-code code\"><code>resource \"google_artifact_registry_repository\" \"app\" {\n  location      = var.region\n  repository_id = \"my-app-repo\"\n  format        = \"DOCKER\"\n}\n\nresource \"google_cloud_run_v2_service\" \"hello\" {\n  name     = \"hello-app\"\n  location = var.region\n\n  deletion_protection = false\n\n  template {\n    containers {\n      image = \"${var.region}-docker.pkg.dev\/${var.project_id}\/${google_artifact_registry_repository.app.repository_id}\/hello-app:v1\"\n\n      ports {\n        container_port = 8080\n      }\n\n      resources {\n        limits = {\n          cpu    = \"1\"\n          memory = \"256Mi\"\n        }\n      }\n    }\n\n    scaling {\n      min_instance_count = 0\n      max_instance_count = 3\n    }\n  }\n\n  traffic {\n    type    = \"TRAFFIC_TARGET_ALLOCATION_TYPE_LATEST\"\n    percent = 100\n  }\n}\n\nresource \"google_cloud_run_v2_service_iam_member\" \"public\" {\n  name     = google_cloud_run_v2_service.hello.name\n  location = google_cloud_run_v2_service.hello.location\n  role     = \"roles\/run.invoker\"\n  member   = \"allUsers\"\n}\n\noutput \"service_url\" {\n  value = google_cloud_run_v2_service.hello.uri\n}<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Apply with <code>terraform init &amp;&amp; terraform apply -var project_id=PROJECT_ID<\/code>. The important detail is <code>deletion_protection = false<\/code>. Without it, <code>terraform destroy<\/code> refuses to delete the service, which is a safety feature in production but annoying in labs. The <code>google_cloud_run_v2_service_iam_member<\/code> resource with <code>allUsers<\/code> is what makes the endpoint publicly accessible, equivalent to the <code>--allow-unauthenticated<\/code> flag in gcloud.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">What Cloud Run Actually Costs<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud Run pricing has three components, and a generous free tier that covers most demos and low-traffic production APIs forever.<\/p>\n\n\n\n<figure class=\"wp-block-table\"><table>\n<thead><tr><th>Component<\/th><th>Price (europe-west1)<\/th><th>Free tier (monthly)<\/th><\/tr><\/thead>\n<tbody>\n<tr><td>CPU<\/td><td>$0.00002400 per vCPU-second<\/td><td>180,000 vCPU-seconds<\/td><\/tr>\n<tr><td>Memory<\/td><td>$0.00000250 per GiB-second<\/td><td>360,000 GiB-seconds<\/td><\/tr>\n<tr><td>Requests<\/td><td>$0.40 per million<\/td><td>2 million requests<\/td><\/tr>\n<\/tbody>\n<\/table><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">The free tier translates to roughly: an app with 1 vCPU and 256 MiB serving 2 million requests per month with each request averaging 90ms of CPU time costs nothing. Past the free tier, the same workload costs single-digit dollars per month. Cloud Run only bills when a request is being processed (or when min-instances > 0, in which case idle instances bill at a reduced CPU rate of 10% of the active rate). For a detailed breakdown of all the GCP cost traps including Cloud Run&#8217;s connector costs, see our <a href=\"https:\/\/computingforgeeks.com\/gcp-costs-explained\/\">GCP Costs Explained<\/a> guide.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Cleanup<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud Run services with min-instances=0 cost nothing when idle, but the Artifact Registry repository stores images that bill for storage. Clean everything up:<\/p>\n\n\n\n<pre class=\"wp-block-code code\"><code>gcloud run services delete hello-app --region=europe-west1 --quiet\ngcloud artifacts repositories delete my-app-repo --location=europe-west1 --quiet<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">Both deletions are instant. No cluster to tear down, no nodes to drain, no NAT gateway to wait for.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">FAQ<\/h2>\n\n\n\n<h3 class=\"wp-block-heading\">Does Cloud Run support WebSockets?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Cloud Run supports WebSockets, gRPC, and server-sent events (SSE) on the managed platform. The request timeout is configurable up to 60 minutes. For long-lived connections like WebSockets, set <code>--session-affinity<\/code> so subsequent requests from the same client hit the same instance, and increase the timeout accordingly.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How do I connect Cloud Run to Cloud SQL on a private IP?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Two options. The recommended approach is a Serverless VPC Access connector that bridges Cloud Run into your VPC. The legacy approach is the Cloud SQL Auth Proxy sidecar, which Cloud Run supports as a second container in the service spec. The VPC connector is simpler and avoids the Auth Proxy overhead. For the full Cloud SQL setup, see our Cloud SQL PostgreSQL guide.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Can Cloud Run pull secrets from Secret Manager?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">Yes. Use the <code>--set-secrets<\/code> flag to inject Secret Manager values as environment variables or mounted files at deploy time. The Cloud Run service agent needs <code>roles\/secretmanager.secretAccessor<\/code> on the target secret. Pin to a specific version number rather than <code>latest<\/code> to avoid the alias gotcha documented in our <a href=\"https:\/\/computingforgeeks.com\/google-cloud-secret-manager-tutorial\/\">Secret Manager tutorial<\/a>.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">What is the AWS equivalent of Cloud Run?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">The closest match is an ECS Fargate service behind an Application Load Balancer. Both run containers without managing servers. Cloud Run is significantly simpler to set up (one <code>gcloud run deploy<\/code> command vs Fargate + ALB + target groups + task definition + service), has built-in HTTPS with managed certificates, and includes traffic splitting for canary deployments. Fargate offers more networking flexibility and integrates deeper with the AWS ecosystem. For workloads that need scale-to-zero, Cloud Run&#8217;s model is also comparable to AWS Lambda container images, though Lambda has a 15-minute execution timeout while Cloud Run allows up to 60 minutes.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">How fast is the cold start?<\/h3>\n\n\n\n<p class=\"wp-block-paragraph\">With a distroless Go image under 10 MB, cold starts typically range from 500ms to 1.5 seconds including image pull and container initialization. Larger images (Python with dependencies, Java with Spring Boot) can take 3 to 8 seconds on a cold start. To eliminate cold starts for latency-sensitive services, set <code>--min-instances=1<\/code> and accept the always-on cost for that one instance.<\/p>\n\n\n\n<script type=\"application\/ld+json\">\n{\n  \"@context\": \"https:\/\/schema.org\",\n  \"@type\": \"FAQPage\",\n  \"mainEntity\": [\n    {\"@type\":\"Question\",\"name\":\"Does Cloud Run support WebSockets?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Yes. Cloud Run supports WebSockets, gRPC, and SSE. Request timeout is configurable up to 60 minutes. Use --session-affinity for long-lived connections.\"}},\n    {\"@type\":\"Question\",\"name\":\"How do I connect Cloud Run to Cloud SQL on a private IP?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Use a Serverless VPC Access connector to bridge Cloud Run into your VPC. The legacy approach is the Cloud SQL Auth Proxy sidecar. VPC connector is simpler.\"}},\n    {\"@type\":\"Question\",\"name\":\"Can Cloud Run pull secrets from Secret Manager?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"Yes. Use --set-secrets to inject Secret Manager values as env vars or mounted files. The Cloud Run service agent needs roles\/secretmanager.secretAccessor on the target secret.\"}},\n    {\"@type\":\"Question\",\"name\":\"What is the AWS equivalent of Cloud Run?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"ECS Fargate behind an ALB. Cloud Run is simpler (one command vs Fargate + ALB + target groups), includes HTTPS with managed certs, and has built-in traffic splitting. For scale-to-zero, also comparable to Lambda container images.\"}},\n    {\"@type\":\"Question\",\"name\":\"How fast is the cold start?\",\"acceptedAnswer\":{\"@type\":\"Answer\",\"text\":\"With a small Go image, 500ms to 1.5s. Larger Python\/Java images 3-8s. Set --min-instances=1 to eliminate cold starts for latency-sensitive services.\"}}\n  ]\n}\n<\/script>\n\n\n\n<h2 class=\"wp-block-heading\">Where to Go Next<\/h2>\n\n\n\n<p class=\"wp-block-paragraph\">Cloud Run is usually the starting point for containerized workloads on GCP because it removes the infrastructure overhead entirely. The natural next steps are connecting it to a database (<a href=\"https:\/\/computingforgeeks.com\/google-cloud-secret-manager-tutorial\/\">Secret Manager<\/a> for credentials, Cloud SQL Auth Proxy or VPC connector for the connection), setting up CI\/CD with <a href=\"https:\/\/computingforgeeks.com\/gcp-workload-identity-federation-github-actions\/\">GitHub Actions and Workload Identity Federation<\/a> so deploys happen on push without JSON keys, and adding a custom domain with a Google-managed SSL certificate. When the workload outgrows Cloud Run (you need sidecars, StatefulSets, or the full Kubernetes API), the upgrade path is <a href=\"https:\/\/computingforgeeks.com\/gke-workload-identity-federation-complete-guide\/\">GKE Autopilot<\/a> with the same container image. The <a href=\"https:\/\/cloud.google.com\/run\/docs\" target=\"_blank\" rel=\"noreferrer noopener\">official Cloud Run documentation<\/a> is the reference worth bookmarking.<\/p>\n\n","protected":false},"excerpt":{"rendered":"<p>Tested Cloud Run guide: build with Cloud Build, push to Artifact Registry, deploy, canary with traffic splitting, Terraform version, VPC connectors, secrets integration, and real cost breakdown.<\/p>\n","protected":false},"author":3,"featured_media":165767,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2680,316,36939],"tags":[212,36175,559],"cfg_series":[39811],"class_list":["post-165766","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-cloud","category-containers","category-gcp","tag-automation","tag-gcp","tag-terraform","cfg_series-gcp-platform"],"_links":{"self":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/165766","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/comments?post=165766"}],"version-history":[{"count":0,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/posts\/165766\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media\/165767"}],"wp:attachment":[{"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/media?parent=165766"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/categories?post=165766"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/tags?post=165766"},{"taxonomy":"cfg_series","embeddable":true,"href":"https:\/\/computingforgeeks.com\/wp-json\/wp\/v2\/cfg_series?post=165766"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}