GCP Cloud Run Jobs
Deploy batch workloads, migrations and other run-to-completion tasks with Google Cloud Run Jobs. The gcp-cloud-run-job recipe builds and pushes an image the same way as GCP Cloud Run, then creates or updates the job and, optionally, runs it.
Prerequisites
- Google Cloud SDK installed and authenticated
- Docker installed and running
- A GCP project with the Cloud Run and Artifact Registry APIs enabled
- An Artifact Registry Docker repository in the job’s region
# Install gcloudbrew install google-cloud-sdk
# Authenticategcloud auth logingcloud auth configure-docker us-central1-docker.pkg.dev
# Create the Artifact Registry repository (once per region)gcloud artifacts repositories create my-repo \ --repository-format=docker \ --location=us-central1 \ --project=my-projectService Configuration
name: db-migrationstype: gcp-cloud-run-jobproject: my-projectregion: us-central1registry_name: my-repotemplate: go # Dockerfile at _templates/go in the project root
build: language: go cmd: "CGO_ENABLED=0 go build -o ./dist/migrate ./cmd/migrate"
job: timeout: "300s" memory: 1Gi cpu: "1" max_retries: 2 execute_on_deploy: true cloudsql_instances: - my-project:us-central1:main-db
secrets: DATABASE_URL: database-url:latest
depends_on: - my-apitype: gcp-cloud-run-job is required. Without it, a provider: gcp service resolves to gcp-artifact-registry-image and is never deployed.
Required Fields
| Field | Description |
|---|---|
name | Job name. Also the image name, unless image_name is set. |
type | gcp-cloud-run-job |
project | GCP project ID |
region | GCP region, e.g. us-central1 |
registry_name | Artifact Registry repository name. A bare name such as my-repo, not a full host or path. |
template | Dockerfile name under _templates/ in the project root |
The image is built and named exactly as for Cloud Run services: <region>-docker.pkg.dev/<project>/<registry_name>/<name>:<tag>. See The Dockerfile and Image Naming.
Optional Fields
Job Configuration
| Field | Type | Default | Description |
|---|---|---|---|
job.timeout | string | 600s | --task-timeout: maximum run time per task, e.g. 300s, 10m. Always sent. |
job.max_retries | int | - | --max-retries: retries per failed task |
job.parallelism | int | - | --parallelism: maximum concurrent tasks |
job.task_count | int | - | --tasks: total number of tasks |
job.cpu | string | - | --cpu per task |
job.memory | string | - | --memory per task, e.g. 512Mi, 2Gi |
job.service_account | string | - | --service-account: identity the job runs as |
job.cloudsql_instances | list | - | --set-cloudsql-instances, entries as project:region:instance |
job.execute_on_deploy | bool | false | Run the job (and wait for it) after it is deployed |
Apart from job.timeout, a key that is not set sends no flag, so the job keeps its current value or Cloud Run’s default. The other defaults listed in the recipe file are what pilum init writes; they are not applied at deploy time.
job.cloudsql_instances uses --set-cloudsql-instances, so the list replaces the job’s current connections.
Secrets and Environment Variables
secrets and env_vars are maps, exactly as for Cloud Run services:
env_vars: LOG_LEVEL: info BATCH_SIZE: "500" # quote numbers; unquoted values are dropped
secrets: DATABASE_URL: database-url:latest API_KEY: projects/my-project/secrets/api-key/versions/3- A secret value can be
name:versionorprojects/<project>/secrets/<name>/versions/<version>. The full path is converted toname:version. - Pilum always states the full set. Each deploy sends either
--set-env-varsor--clear-env-vars, and either--set-secretsor--clear-secrets. - A list-form
secrets:block is ignored, which clears the job’s secrets on the next deploy.
Cloud Run Jobs vs Cloud Run Services
| Feature | Cloud Run Service | Cloud Run Job |
|---|---|---|
| Runs | Continuously (HTTP server) | To completion (batch) |
| Triggered by | HTTP requests | Manual, scheduler, or on deploy |
| Scaling | 0-N based on traffic | Fixed task count |
| Use case | APIs, web apps | Migrations, ETL, data processing |
Deployment Steps
The gcp-cloud-run-job recipe runs:
- build binary [build] — Runs
build.cmdin the service directory. Skipped whenbuild.cmdis empty. - build docker image [build] —
docker buildfrom the project root with-f ./_templates/<template>. - publish to registry [push] —
docker pushof the versioned tag. - deploy job [deploy] —
gcloud run jobs deploy(creates or updates the job). - execute job [execute] —
gcloud run jobs execute --wait. Only whenjob.execute_on_deploy: true; otherwise the step does nothing.
Dependency Ordering
Steps tagged build, deploy and execute respect depends_on. When a job depends on a service, Pilum deploys the service in an earlier wave:
name: db-migrationstype: gcp-cloud-run-jobdepends_on: - database-proxy # deployed before the migration jobPilum groups services into waves by dependency depth and runs each wave in turn. If a service in one wave fails, its dependents in later waves are skipped. --no-deps turns waves off.
Execute on Deploy
When job.execute_on_deploy is true, the execute step runs the job and blocks until it finishes:
gcloud run jobs execute db-migrations --region us-central1 --wait --project my-projectA failed execution fails the step, and so the deploy. The step’s timeout is 600 seconds; a job that runs longer than that is reported as failed by Pilum even if it later succeeds in Cloud Run.
When execute_on_deploy is false (the default), the execute step is a no-op. There is no CLI flag that forces an execution; --only-tags=execute still does nothing unless execute_on_deploy is true. To run the job by hand:
gcloud run jobs execute db-migrations --region us-central1 --waitExample Commands
# Build, push, deploy and (if execute_on_deploy) run the jobpilum deploy db-migrations --tag=v1.0.0
# Deploy without executing, even with execute_on_deploy: truepilum deploy db-migrations --exclude-tags=execute --tag=v1.0.0
# Update the job definition only (the image for this tag must already exist)pilum deploy db-migrations --only-tags=deploy --tag=v1.0.0
# Preview commandspilum dry-run db-migrations --tag=v1.0.0Generated Deploy Command
For the configuration above, pilum dry-run --tag=v1.0.0 shows (wrapped for reading):
gcloud run jobs deploy db-migrations \ --image us-central1-docker.pkg.dev/my-project/my-repo/db-migrations:v1.0.0 \ --region us-central1 \ --task-timeout 300s \ --max-retries=2 \ --cpu 1 \ --memory 1Gi \ --set-cloudsql-instances my-project:us-central1:main-db \ --clear-env-vars \ --set-secrets DATABASE_URL=database-url:latest \ --project my-project
gcloud run jobs execute db-migrations --region us-central1 --wait --project my-projectRollback, Status and Logs
# Point the job back at the image of the previous executionpilum rollback db-migrations
# Or at a specific image tagpilum rollback db-migrations --to v0.9.0
# Show the job's statepilum status db-migrations
# List recent executionspilum logs db-migrations- Jobs have no revisions or traffic.
pilum rollbackreads the job’s executions from Cloud Run, finds the most recent one that ran a different image, and runsgcloud run jobs update db-migrations --image <that image>. Only the image changes; the job keeps its current configuration. - If no earlier execution ran a different image, pass
--to <tag>. - Rollback does not execute the job.
pilum logsfor a job runsgcloud run jobs executions list. For log lines, use Cloud Logging (see below).
See Rollback and Status.
Troubleshooting
Job fails to execute
Step 5: execute job db-migrations ✗ - execution failedCheck the execution and its logs:
pilum logs db-migrationsgcloud logging read "resource.type=cloud_run_job AND resource.labels.job_name=db-migrations" --limit 50Timeout exceeded
If tasks hit the task timeout, raise job.timeout:
job: timeout: "1800s" # 30 minutesThe execute step itself times out after 600 seconds. For longer jobs, set execute_on_deploy: false and trigger the job outside the deploy.
Execute step skipped
The execute step only runs when execute_on_deploy is set:
job: execute_on_deploy: trueOr execute the job directly with gcloud run jobs execute db-migrations --region us-central1 --wait.
Next Steps
- GCP Cloud Run — Deploy HTTP services
- Rollback and Status — Roll back, check status, read logs
- Service Configuration — Full
pilum.yamlreference - CLI Commands — All commands and flags