Skip to content

GCP Cloud Run (from image)

The gcp-cloud-run-from-image recipe deploys an image that already exists to Google Cloud Run. There is no build and no push: Pilum runs gcloud run deploy with the image you name, then routes traffic to the new revision.

Use it when:

  • You run a third-party image, such as Grafana or an OpenTelemetry collector
  • You promote an image that was built and tested elsewhere, for example by another service’s pipeline or a GCP Artifact Registry Image service
  • Several Cloud Run services run the same image with different configuration

To build your own code and deploy it in one pipeline, use GCP Cloud Run instead.

Prerequisites

  1. Google Cloud SDK installed and authenticated
  2. A GCP project with the Cloud Run API enabled
  3. An image Cloud Run can pull: Artifact Registry, Container Registry, or a public Docker Hub image

Docker is not needed, since nothing is built.

Terminal window
# Authenticate
gcloud auth login
# Enable Cloud Run
gcloud services enable run.googleapis.com --project my-gcp-project

Service Configuration

name: mcp-controller
type: gcp-cloud-run-from-image
project: my-gcp-project
region: us-central1
image: us-central1-docker.pkg.dev/my-gcp-project/platform-images/mcp-controller:v1.0.0
cloud_run:
port: 8080
memory: 1Gi
cpu: "1"
min_instances: 0
max_instances: 5
concurrency: 80
timeout_seconds: 300
env_vars:
LOG_LEVEL: info
secrets:
DATABASE_URL: database-url:latest

A third-party image works the same way:

name: grafana
type: gcp-cloud-run-from-image
project: my-gcp-project
region: us-central1
image: docker.io/grafana/grafana:11.2.0
cloud_run:
port: 3000
memory: 1Gi
allow_unauthenticated: true

The image value is used exactly as written, tag included. --tag and version: do not change it, so pin a version in image and update it to promote a new release.

Required Fields

FieldDescription
nameCloud Run service name
projectGCP project ID
regionGCP region, e.g. us-central1
imageFully qualified image reference, including the tag or digest

Optional Fields

Cloud Run Configuration

Pilum only sends a flag for keys you set. An unset key keeps the service’s current value, or Cloud Run’s default on the first deploy. The Default column shows the recipe’s documented default.

FieldTypeDefaultDescription
cloud_run.min_instancesint0Minimum instances (0 for scale to zero)
cloud_run.max_instancesint10Maximum instances
cloud_run.cpu_throttlingbooltruetrue sends --cpu-throttling. false sends nothing, so it does not turn throttling off.
cloud_run.memorystring512MiMemory per instance, e.g. 512Mi, 1Gi
cloud_run.cpustring1CPUs per instance
cloud_run.concurrencyint80Max concurrent requests per instance
cloud_run.timeout_secondsint300Request timeout in seconds
cloud_run.portint8080Ingress container port. Sent only when set, except with sidecars, where it falls back to 8080.
cloud_run.use_http2boolfalseServe end-to-end HTTP/2 (h2c). Unset sends nothing, so removing it later does not turn HTTP/2 off.
sidecarslist-Extra containers in the same revision. See GCP Cloud Run.

The same deploy command as the gcp-cloud-run recipe is used, so these cloud_run keys also apply:

FieldTypeDefaultDescription
cloud_run.allow_unauthenticatedboolfalsetrue makes the service public. Otherwise Pilum sends --no-allow-unauthenticated.
cloud_run.ingressstring-all, internal-and-cloud-load-balancing or internal
cloud_run.service_accountstring-Service account the service runs as
cloud_run.vpc_connectorstring-Serverless VPC Access connector for outbound traffic
cloud_run.vpc_egressstringall-trafficall-traffic or private-ranges-only. Ignored without vpc_connector.
cloud_run.no_trafficboolfalseDeploy a revision that receives no traffic, and skip route traffic to latest. Fails on a service’s first deploy.
cloud_run.tagstring-Revision tag, which gives the revision its own URL
cloud_run.cloudsql_instanceslist-Cloud SQL connections, sent as --add-cloudsql-instances

Secrets

secrets must be a map. Each value is name:version or a full projects/<p>/secrets/<s>/versions/<v> path:

secrets:
DATABASE_URL: database-url:latest
API_KEY: projects/my-gcp-project/secrets/api-key/versions/3

Pilum always states the full set. With no secrets, it sends --clear-secrets, which removes secrets already on the service. A list of {name, value} entries is ignored and therefore also clears them.

Environment Variables

env_vars must be a map. With no env vars, Pilum sends --clear-env-vars.

env_vars:
LOG_LEVEL: info
FEATURE_FLAGS: "a,b,c" # values with commas are handled

Deployment Steps

  1. deploy from image — gcloud run deploy with the configured image
  2. route traffic to latest — gcloud run services update-traffic --to-latest, so the new revision serves all traffic. Skipped when cloud_run.no_traffic is set.

Both steps are tagged deploy. pilum build, pilum push and pilum publish do nothing for this recipe.

Routing to latest also undoes a rollback pin and resets any traffic split you set by hand.

Example Commands

Terminal window
# Deploy
pilum deploy mcp-controller
# Preview the gcloud commands
pilum dry-run mcp-controller
# Check what is serving
pilum status mcp-controller
pilum logs mcp-controller
# Move traffic back to the previous revision
pilum rollback mcp-controller

Generated Deploy Command

For the first configuration above, Pilum runs:

Terminal window
gcloud run deploy mcp-controller \
--region us-central1 \
--platform managed \
--no-allow-unauthenticated \
--min-instances=0 \
--max-instances=5 \
--concurrency=80 \
--timeout=300 \
--project my-gcp-project \
--image us-central1-docker.pkg.dev/my-gcp-project/platform-images/mcp-controller:v1.0.0 \
--port=8080 \
--memory 1Gi \
--cpu 1 \
--set-env-vars LOG_LEVEL=info \
--set-secrets DATABASE_URL=database-url:latest
gcloud run services update-traffic mcp-controller \
--to-latest \
--region us-central1 \
--project my-gcp-project

Rollback

pilum rollback moves 100% of traffic to the previous healthy revision, the same as for gcp-cloud-run. Nothing is redeployed. The next pilum deploy routes traffic to the latest revision again. See Rollback and Status.

Troubleshooting

Image Not Found or Access Denied

Cloud Run pulls the image with its service agent. For a private Artifact Registry repository in another project, grant the Cloud Run service agent of the deploying project roles/artifactregistry.reader on that repository.

Secrets Disappeared After Deploy

The service had secrets, but pilum.yaml lists none, or lists them in list form. Pilum sent --clear-secrets. Write secrets as a map and deploy again.

Container Fails to Start

The image must listen on the port Cloud Run sends traffic to. Set cloud_run.port to the port the image uses, for example 3000 for Grafana.

Deploy Succeeded but Old Revision Still Serves

Check whether cloud_run.no_traffic is set. With it, the route traffic to latest step is skipped by design.

Next Steps