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
- Google Cloud SDK installed and authenticated
- A GCP project with the Cloud Run API enabled
- An image Cloud Run can pull: Artifact Registry, Container Registry, or a public Docker Hub image
Docker is not needed, since nothing is built.
# Authenticategcloud auth login
# Enable Cloud Rungcloud services enable run.googleapis.com --project my-gcp-projectService Configuration
name: mcp-controllertype: gcp-cloud-run-from-imageproject: my-gcp-projectregion: us-central1image: 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: infosecrets: DATABASE_URL: database-url:latestA third-party image works the same way:
name: grafanatype: gcp-cloud-run-from-imageproject: my-gcp-projectregion: us-central1image: docker.io/grafana/grafana:11.2.0
cloud_run: port: 3000 memory: 1Gi allow_unauthenticated: trueThe 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
| Field | Description |
|---|---|
name | Cloud Run service name |
project | GCP project ID |
region | GCP region, e.g. us-central1 |
image | Fully 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.
| Field | Type | Default | Description |
|---|---|---|---|
cloud_run.min_instances | int | 0 | Minimum instances (0 for scale to zero) |
cloud_run.max_instances | int | 10 | Maximum instances |
cloud_run.cpu_throttling | bool | true | true sends --cpu-throttling. false sends nothing, so it does not turn throttling off. |
cloud_run.memory | string | 512Mi | Memory per instance, e.g. 512Mi, 1Gi |
cloud_run.cpu | string | 1 | CPUs per instance |
cloud_run.concurrency | int | 80 | Max concurrent requests per instance |
cloud_run.timeout_seconds | int | 300 | Request timeout in seconds |
cloud_run.port | int | 8080 | Ingress container port. Sent only when set, except with sidecars, where it falls back to 8080. |
cloud_run.use_http2 | bool | false | Serve end-to-end HTTP/2 (h2c). Unset sends nothing, so removing it later does not turn HTTP/2 off. |
sidecars | list | - | 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:
| Field | Type | Default | Description |
|---|---|---|---|
cloud_run.allow_unauthenticated | bool | false | true makes the service public. Otherwise Pilum sends --no-allow-unauthenticated. |
cloud_run.ingress | string | - | all, internal-and-cloud-load-balancing or internal |
cloud_run.service_account | string | - | Service account the service runs as |
cloud_run.vpc_connector | string | - | Serverless VPC Access connector for outbound traffic |
cloud_run.vpc_egress | string | all-traffic | all-traffic or private-ranges-only. Ignored without vpc_connector. |
cloud_run.no_traffic | bool | false | Deploy a revision that receives no traffic, and skip route traffic to latest. Fails on a service’s first deploy. |
cloud_run.tag | string | - | Revision tag, which gives the revision its own URL |
cloud_run.cloudsql_instances | list | - | 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/3Pilum 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 handledDeployment Steps
- deploy from image —
gcloud run deploywith the configuredimage - route traffic to latest —
gcloud run services update-traffic --to-latest, so the new revision serves all traffic. Skipped whencloud_run.no_trafficis 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
# Deploypilum deploy mcp-controller
# Preview the gcloud commandspilum dry-run mcp-controller
# Check what is servingpilum status mcp-controllerpilum logs mcp-controller
# Move traffic back to the previous revisionpilum rollback mcp-controllerGenerated Deploy Command
For the first configuration above, Pilum runs:
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-projectRollback
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
- GCP Cloud Run — Build and deploy your own code
- GCP Artifact Registry Image — Build and publish images for other services to deploy
- Rollback and Status — Roll back and inspect deployed services
- Service Configuration — Full
pilum.yamlreference