Cloud Deploy CI/CD Guide
Guide to Cloud Deploy covering delivery pipelines, targets, Skaffold rendering, canary deployments, approval gates, rollbacks, and integration with Cloud Build for end-to-end CI/CD.
Prerequisites
- Experience with container deployment (GKE or Cloud Run)
- Basic understanding of CI/CD pipeline concepts
- Familiarity with Kubernetes manifests or Cloud Run service YAML
Introduction to Cloud Deploy
Google Cloud Deploy is a fully managed continuous delivery service that automates the deployment of applications to GKE, Cloud Run, and Anthos clusters. It provides an opinionated but flexible delivery pipeline that handles progressive rollouts, canary deployments, automated verification, approval gates, and instant rollbacks. Cloud Deploy integrates with Skaffold for rendering Kubernetes manifests, making it compatible with Helm, Kustomize, and plain YAML configurations.
Unlike general-purpose CI/CD tools like Jenkins or GitHub Actions, Cloud Deploy focuses exclusively on the delivery (CD) portion of the pipeline. It assumes you have already built and tested your artifacts (typically using Cloud Build or another CI system) and manages the promotion of those artifacts through a sequence of environments like dev, staging, and production. This separation of concerns makes deployment pipelines more reliable and auditable.
This guide covers creating delivery pipelines and targets, configuring Skaffold for manifest rendering, setting up canary and blue-green deployments, implementing approval gates, automated rollbacks, and integrating Cloud Deploy with Cloud Build for end-to-end CI/CD.
Cloud Deploy Pricing
Cloud Deploy charges $0.20 per active delivery pipeline per day and $0.02 per target per day. A typical three-target pipeline (dev, staging, prod) costs approximately $0.26/day or about $8/month. Rendering and deployment operations are free. This is significantly cheaper than maintaining a dedicated deployment tool like Spinnaker or ArgoCD on your own infrastructure.
Core Concepts
Cloud Deploy Architecture
| Concept | Description | Example |
|---|---|---|
| Delivery Pipeline | Defines the sequence of targets for promotion | my-app-pipeline (dev → staging → prod) |
| Target | A deployment destination (GKE cluster, Cloud Run service) | dev-cluster, prod-run-service |
| Release | A specific version of the application to deploy | release-v1.2.3 |
| Rollout | The deployment of a release to a specific target | rollout-001 (release-v1.2.3 to prod) |
| Skaffold Config | Defines how to render and deploy manifests | skaffold.yaml with Helm or Kustomize |
| Automation | Rules for automatic promotion and rollback | Auto-promote to staging after dev succeeds |
Setting Up Your First Pipeline
A Cloud Deploy pipeline requires three components: a delivery pipeline definition, target definitions, and a Skaffold configuration. Let us create a pipeline that deploys a containerized application to Cloud Run across three environments.
# Enable the Cloud Deploy API
gcloud services enable clouddeploy.googleapis.com
# Grant the Cloud Deploy service account required roles
PROJECT_NUMBER=$(gcloud projects describe MY_PROJECT --format="value(projectNumber)")
gcloud projects add-iam-policy-binding MY_PROJECT \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/clouddeploy.jobRunner"
gcloud projects add-iam-policy-binding MY_PROJECT \
--member="serviceAccount:${PROJECT_NUMBER}-compute@developer.gserviceaccount.com" \
--role="roles/run.developer"apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
name: my-app-pipeline
description: "My application delivery pipeline"
serialPipeline:
stages:
- targetId: dev
profiles: [dev]
- targetId: staging
profiles: [staging]
- targetId: prod
profiles: [prod]
strategy:
canary:
runtimeConfig:
cloudRun:
automaticTrafficControl: true
canaryDeployment:
percentages: [25, 50, 75]
verify: true
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: dev
description: "Development environment"
run:
location: projects/MY_PROJECT/locations/us-central1
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: staging
description: "Staging environment"
run:
location: projects/MY_PROJECT/locations/us-central1
requireApproval: false
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: prod
description: "Production environment"
run:
location: projects/MY_PROJECT/locations/us-central1
requireApproval: true# Apply the pipeline and target definitions
gcloud deploy apply --file=clouddeploy.yaml --region=us-central1
# Verify the pipeline was created
gcloud deploy delivery-pipelines describe my-app-pipeline \
--region=us-central1
# List all targets
gcloud deploy targets list --region=us-central1Configuring Skaffold
Skaffold is the rendering engine that Cloud Deploy uses to transform your manifests for each target. Skaffold supports Helm charts, Kustomize overlays, and raw Kubernetes YAML. For Cloud Run deployments, Skaffold renders Cloud Run service YAML files.
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: my-app
manifests:
rawYaml:
- service.yaml
deploy:
cloudrun: {}
profiles:
- name: dev
manifests:
rawYaml:
- service.yaml
patches:
- op: replace
path: /deploy/cloudrun
value:
projectid: MY_PROJECT
region: us-central1
- name: staging
manifests:
rawYaml:
- service.yaml
patches:
- op: replace
path: /deploy/cloudrun
value:
projectid: MY_PROJECT
region: us-central1
- name: prod
manifests:
rawYaml:
- service.yaml
patches:
- op: replace
path: /deploy/cloudrun
value:
projectid: MY_PROJECT
region: us-central1apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: my-app
spec:
template:
metadata:
annotations:
autoscaling.knative.dev/minScale: "1"
autoscaling.knative.dev/maxScale: "10"
spec:
containerConcurrency: 80
containers:
- image: us-central1-docker.pkg.dev/MY_PROJECT/docker-repo/my-app
ports:
- containerPort: 8080
resources:
limits:
cpu: "1"
memory: "512Mi"
env:
- name: ENVIRONMENT
value: "production"Creating Releases and Promoting
# Create a release (deploys to the first target automatically)
gcloud deploy releases create release-v1-0-0 \
--delivery-pipeline=my-app-pipeline \
--region=us-central1 \
--images=my-app=us-central1-docker.pkg.dev/MY_PROJECT/docker-repo/my-app:v1.0.0
# Check release status
gcloud deploy releases describe release-v1-0-0 \
--delivery-pipeline=my-app-pipeline \
--region=us-central1
# List rollouts for the release
gcloud deploy rollouts list \
--delivery-pipeline=my-app-pipeline \
--release=release-v1-0-0 \
--region=us-central1
# Promote the release to the next target (dev -> staging)
gcloud deploy releases promote \
--release=release-v1-0-0 \
--delivery-pipeline=my-app-pipeline \
--region=us-central1
# Approve a rollout for a target that requires approval (prod)
gcloud deploy rollouts approve rollout-name \
--delivery-pipeline=my-app-pipeline \
--release=release-v1-0-0 \
--region=us-central1Automating Promotions
Cloud Deploy supports automation rules that automatically promote releases between targets. For example, you can configure automatic promotion from dev to staging when the dev rollout succeeds, while requiring manual approval for production. This balances automation speed with production safety.
Canary Deployments
Canary deployments gradually shift traffic to a new version, allowing you to detect issues before they affect all users. Cloud Deploy supports canary deployments for both GKE and Cloud Run targets. You define the percentage steps and optional verification steps that run automated tests at each stage.
apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
name: my-app-pipeline
serialPipeline:
stages:
- targetId: dev
profiles: [dev]
- targetId: staging
profiles: [staging]
- targetId: prod
profiles: [prod]
strategy:
canary:
runtimeConfig:
cloudRun:
automaticTrafficControl: true
canaryDeployment:
percentages: [10, 25, 50, 75]
verify: true
predeploy:
actions: ["pre-deploy-check"]
postdeploy:
actions: ["post-deploy-verify"]# During a canary rollout, advance to the next phase
gcloud deploy rollouts advance ROLLOUT_NAME \
--delivery-pipeline=my-app-pipeline \
--release=release-v1-1-0 \
--region=us-central1
# Check canary phase status
gcloud deploy rollouts describe ROLLOUT_NAME \
--delivery-pipeline=my-app-pipeline \
--release=release-v1-1-0 \
--region=us-central1 \
--format="yaml(phases)"
# Rollback a canary (reverts all traffic to previous version)
gcloud deploy targets rollback prod \
--delivery-pipeline=my-app-pipeline \
--region=us-central1Rollbacks
Cloud Deploy supports instant rollbacks by re-deploying a previous release or by creating a rollback rollout that restores the previous known-good state. For Cloud Run targets, rollbacks shift traffic back to the previous revision with zero downtime.
# Rollback the production target to the previous release
gcloud deploy targets rollback prod \
--delivery-pipeline=my-app-pipeline \
--region=us-central1
# Alternatively, re-deploy a specific previous release
gcloud deploy releases promote \
--release=release-v1-0-0 \
--delivery-pipeline=my-app-pipeline \
--region=us-central1 \
--to-target=prod
# View rollout history for a target
gcloud deploy rollouts list \
--delivery-pipeline=my-app-pipeline \
--release=- \
--region=us-central1 \
--filter="targetId=prod" \
--format="table(name,approvalState,state,deployEndTime)"Integration with Cloud Build
The most common pattern is using Cloud Build for the CI portion (build, test, scan) and Cloud Deploy for the CD portion (deploy through environments). Cloud Build triggers create releases in Cloud Deploy after successful builds.
steps:
# Build the Docker image
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/my-app:$COMMIT_SHA'
- '.'
# Run tests
- name: 'us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/my-app:$COMMIT_SHA'
entrypoint: 'npm'
args: ['test']
# Push the image
- name: 'gcr.io/cloud-builders/docker'
args:
- 'push'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/my-app:$COMMIT_SHA'
# Create a Cloud Deploy release
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'deploy'
- 'releases'
- 'create'
- 'release-$SHORT_SHA-$BUILD_ID'
- '--delivery-pipeline=my-app-pipeline'
- '--region=us-central1'
- '--images=my-app=us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/my-app:$COMMIT_SHA'
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/docker-repo/my-app:$COMMIT_SHA'Skaffold Version Compatibility
Cloud Deploy uses a specific Skaffold version for rendering. Check the Cloud Deploy release notes for the currently supported Skaffold API version. Using an unsupported Skaffold version in your configuration will cause rendering failures. Pin theapiVersion in your skaffold.yaml and update it when upgrading your Cloud Deploy pipeline.
GKE Target Configuration
For GKE targets, Cloud Deploy can deploy Kubernetes manifests rendered through Helm or Kustomize. The Skaffold configuration specifies the rendering engine and the deploy section specifies the GKE cluster.
# Target definition for GKE
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: gke-prod
description: "Production GKE cluster"
gke:
cluster: projects/MY_PROJECT/locations/us-central1/clusters/prod-cluster
---
# Skaffold config for Helm deployment
apiVersion: skaffold/v4beta11
kind: Config
metadata:
name: my-app-gke
manifests:
helm:
releases:
- name: my-app
chartPath: charts/my-app
valuesFiles:
- charts/my-app/values.yaml
setValues:
image.tag: "{{.IMAGE_TAG_my_app}}"
deploy:
kubectl: {}Monitoring and Observability
# List all releases with their status
gcloud deploy releases list \
--delivery-pipeline=my-app-pipeline \
--region=us-central1 \
--format="table(name,renderState,targetRenders)"
# View delivery pipeline metrics in Cloud Monitoring
# Navigate to: Cloud Deploy > Delivery pipelines > my-app-pipeline > Metrics
# Set up Pub/Sub notifications for deploy events
gcloud deploy delivery-pipelines add-iam-policy-binding my-app-pipeline \
--region=us-central1 \
--member="serviceAccount:deploy-notify@MY_PROJECT.iam.gserviceaccount.com" \
--role="roles/clouddeploy.viewer"Cleanup
# Delete releases
gcloud deploy releases list \
--delivery-pipeline=my-app-pipeline \
--region=us-central1 \
--format="value(name)" | while read release; do
gcloud deploy releases delete "${release}" \
--delivery-pipeline=my-app-pipeline \
--region=us-central1 --quiet
done
# Delete the delivery pipeline
gcloud deploy delivery-pipelines delete my-app-pipeline \
--region=us-central1 --force --quiet
# Delete targets
gcloud deploy targets delete dev --region=us-central1 --quiet
gcloud deploy targets delete staging --region=us-central1 --quiet
gcloud deploy targets delete prod --region=us-central1 --quietKey Takeaways
- 1Cloud Deploy separates delivery (CD) from integration (CI), providing a focused deployment experience.
- 2A typical three-target pipeline (dev, staging, prod) costs approximately $8/month.
- 3Canary deployments gradually shift traffic at configurable percentages with optional verification at each stage.
- 4Approval gates require human approval before deploying to sensitive targets like production.
- 5Rollbacks instantly revert to the previous release with zero-downtime traffic shifting.
- 6Skaffold handles manifest rendering supporting Helm, Kustomize, and raw YAML configurations.
Frequently Asked Questions
How does Cloud Deploy differ from Cloud Build?
Can Cloud Deploy handle blue-green deployments?
What is Skaffold and why does Cloud Deploy use it?
Written by CloudToolStack Team
Cloud engineers and architects with hands-on experience across AWS, Azure, and GCP. We write guides based on real-world production patterns, not just documentation rewrites.
Disclaimer: This guide is for educational purposes. Cloud services change frequently; always refer to official documentation for the latest information. AWS, Azure, and GCP are trademarks of their respective owners.