GCP Cloud Run — Serverless Container Deployment Guide
Advertisement
Introduction
Why This Matters
Google Cloud Run runs containers as serverless services — you push a container image and Google handles infrastructure, scaling from zero to thousands of instances, load balancing, and TLS. Unlike Lambda, Cloud Run works with any language and runtime because it runs standard containers. It is the fastest path from a Dockerfile to a production URL on GCP, with no cluster management required.
Deploying Services
# Authenticate and set project
gcloud auth login
gcloud config set project my-project-id
gcloud config set run/region us-central1
# Build and push container to Artifact Registry
gcloud artifacts repositories create my-repo \
--repository-format=docker \
--location=us-central1
gcloud builds submit --tag us-central1-docker.pkg.dev/my-project/my-repo/my-app:v1
# Deploy service
gcloud run deploy my-service \
--image us-central1-docker.pkg.dev/my-project/my-repo/my-app:v1 \
--platform managed \
--region us-central1 \
--allow-unauthenticated \
--port 8080 \
--memory 512Mi \
--cpu 1 \
--concurrency 80 \
--min-instances 0 \
--max-instances 100 \
--set-env-vars NODE_ENV=production,LOG_LEVEL=info
# Get service URL
gcloud run services describe my-service \
--region us-central1 \
--format 'value(status.url)'Environment Variables and Secrets
# Set environment variables
gcloud run deploy my-service \
--image my-image \
--set-env-vars KEY1=value1,KEY2=value2
# Update single env var without redeployment
gcloud run services update my-service \
--update-env-vars DATABASE_URL=postgres://...
# Mount secrets from Secret Manager
gcloud run deploy my-service \
--image my-image \
--set-secrets DB_PASSWORD=myapp-db-password:latest,API_KEY=myapp-api-key:1
# Or mount as file
gcloud run deploy my-service \
--image my-image \
--set-secrets /secrets/config=myapp-config:latestTraffic Splitting and Canary Deployments
# Deploy new revision without sending traffic
gcloud run deploy my-service \
--image my-image:v2 \
--no-traffic \
--tag v2
# Send 10% traffic to new version (canary)
gcloud run services update-traffic my-service \
--to-tags v2=10
# Gradually increase traffic
gcloud run services update-traffic my-service \
--to-tags v2=50
# Promote to 100% when confident
gcloud run services update-traffic my-service \
--to-latest
# Rollback — redirect all traffic to previous revision
gcloud run services update-traffic my-service \
--to-revisions PREV_REVISION=100VPC and Private Access
# Connect Cloud Run to VPC for private database access
gcloud run deploy my-service \
--image my-image \
--vpc-connector my-vpc-connector \
--vpc-egress private-ranges-only
# Create serverless VPC Access connector
gcloud compute networks vpc-access connectors create my-connector \
--region us-central1 \
--range 10.8.0.0/28 \
--network default
# For private-only service (no public internet)
gcloud run deploy my-service \
--image my-image \
--no-allow-unauthenticated \
--ingress internalAuthentication and IAM
# Service-to-service authentication
# Caller service: get identity token
TOKEN=$(gcloud auth print-identity-token)
curl -H "Authorization: Bearer $TOKEN" https://my-service-url.run.app
# Grant specific service account permission to invoke
gcloud run services add-iam-policy-binding my-service \
--member serviceAccount:caller@my-project.iam.gserviceaccount.com \
--role roles/run.invoker
# Use Workload Identity for GKE-to-Cloud Run calls
# Or Cloud Tasks with OIDC token for async triggersCloud Run Jobs (Batch)
# Create a batch job (not an HTTP service)
gcloud run jobs create data-import \
--image us-central1-docker.pkg.dev/my-project/my-repo/importer:latest \
--region us-central1 \
--memory 1Gi \
--cpu 2 \
--max-retries 3 \
--task-timeout 3600s \
--parallelism 5 \
--tasks 100 \
--set-env-vars BATCH_SIZE=1000
# Execute job
gcloud run jobs execute data-import
# Schedule with Cloud Scheduler
gcloud scheduler jobs create http nightly-import \
--schedule "0 2 * * *" \
--uri https://us-central1-run.googleapis.com/apis/run.googleapis.com/v1/namespaces/my-project/jobs/data-import:run \
--oauth-service-account-email scheduler@my-project.iam.gserviceaccount.comCI/CD with Cloud Build
# cloudbuild.yaml
steps:
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA', '.']
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA']
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
args:
- gcloud
- run
- deploy
- my-service
- --image=us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA
- --region=us-central1
- --platform=managed
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'Common Mistakes
- Using
--allow-unauthenticatedfor internal services — services that only receive traffic from other services should use IAM authentication - Not setting
--min-instances 1for latency-sensitive services — cold starts can take 1-3 seconds for large images - Ignoring the 60-minute request timeout limit — Cloud Run is designed for HTTP; use Cloud Run Jobs for long-running batch work
- Not configuring VPC connector for services that need private database access — Cloud Run uses public internet by default
- Setting concurrency too high for CPU-intensive workloads — lower concurrency ensures each request gets adequate CPU
Best Practices
- Use Artifact Registry (not Container Registry) for new projects — it supports multi-format repos and fine-grained IAM
- Set
--concurrencybased on your application characteristics — I/O-bound apps handle more concurrent requests per instance - Use Cloud Run traffic splitting for canary deployments instead of big-bang releases
- Enable Cloud Logging and Cloud Trace — they integrate automatically with Cloud Run at no configuration cost
- Pin container image tags to digests in production (
@sha256:...) rather than mutable tags likelatest - Use service accounts with minimum permissions for each Cloud Run service
Key Takeaways
- Cloud Run runs any containerized HTTP application — no cluster management, no infrastructure provisioning
- Scale-to-zero means you pay nothing when the service receives no traffic — ideal for dev/staging environments
- Cold starts occur when a new instance starts —
--min-instances 1eliminates cold starts at the cost of always-on compute - Traffic splitting allows canary deployments — route a percentage of traffic to a new revision before full rollout
- Cloud Run Jobs handle batch workloads with configurable task count, parallelism, and retries
- VPC connector is required for Cloud Run to reach private resources like Cloud SQL in a VPC
- IAM controls invocation permissions — internal services should require authentication via service account tokens
--concurrencycontrols how many simultaneous requests one instance handles — tune based on CPU vs I/O workload type
Advertisement
Related reading
Google Cloud Platform Guide 2026 — Cloud Run, BigQuery, Firebase, and GKE6 min readKubernetes Guide 2026 — Deploy, Scale, and Manage Containers in Production5 min readVercel Deployment Guide 2026 — Next.js, Edge Functions, and Production Optimization6 min readServerless Computing Guide 2026 — AWS Lambda, Cloudflare Workers, and Edge Functions7 min readDocker Best Practices in 2026 — Production-Ready Containers6 min readDocker Guide 2026 — Containerize Node.js, Python, and Next.js Apps4 min read