GCP for DevOps — CI/CD Exercises
CI/CD — Practice Exercises
Test your knowledge of Cloud Build, build triggers, Artifact Registry, Cloud Deploy, and deployment strategies.
Exercise 1 — Cloud Build Pipeline
Write a cloudbuild.yaml that builds a Docker image, runs tests, pushes to Artifact Registry, and deploys to Cloud Run. Use parallel steps for linting and testing.
Show Answer
steps:
# Install dependencies
- name: 'node:18'
entrypoint: 'npm'
args: ['ci']
id: 'install'
# Lint (parallel with test)
- name: 'node:18'
entrypoint: 'npm'
args: ['run', 'lint']
id: 'lint'
waitFor: ['install']
# Test (parallel with lint)
- name: 'node:18'
entrypoint: 'npm'
args: ['test']
id: 'test'
waitFor: ['install']
# Build Docker image (after lint + test pass)
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
- '.'
id: 'build'
waitFor: ['lint', 'test']
# Push image
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA']
id: 'push'
waitFor: ['build']
# Deploy to Cloud Run
- name: 'gcr.io/cloud-builders/gcloud'
args:
- 'run'
- 'deploy'
- 'my-app'
- '--image=us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
- '--region=us-central1'
- '--platform=managed'
waitFor: ['push']
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
options:
machineType: 'E2_HIGHCPU_8'
timeout: '900s'
Exercise 2 — Build Triggers
Create three triggers: (1) CI on all branches, (2) deploy to staging on develop push, (3) deploy to production on semantic version tags with approval.
Show Answer
# 1. CI trigger on all branches
$ gcloud builds triggers create github \
--name=ci-all-branches \
--repository=projects/my-project/locations/us-central1/connections/github/repositories/my-repo \
--branch-pattern=".*" \
--build-config=cloudbuild-ci.yaml \
--ignored-files="docs/**,*.md"
# 2. Deploy to staging on develop push
$ gcloud builds triggers create github \
--name=deploy-staging \
--repository=projects/my-project/locations/us-central1/connections/github/repositories/my-repo \
--branch-pattern="^develop$" \
--build-config=cloudbuild-staging.yaml \
--substitutions=_ENV=staging
# 3. Deploy to production on version tags (with approval)
$ gcloud builds triggers create github \
--name=deploy-production \
--repository=projects/my-project/locations/us-central1/connections/github/repositories/my-repo \
--tag-pattern="^v[0-9]+\.[0-9]+\.[0-9]+$" \
--build-config=cloudbuild-prod.yaml \
--require-approval
# Verify
$ gcloud builds triggers list --region=us-central1
Exercise 3 — Artifact Registry Setup
Create a Docker repository, push an image, and set up a cleanup policy to delete untagged images older than 14 days.
Show Answer
# Create repository
$ gcloud artifacts repositories create app-images \
--repository-format=docker \
--location=us-central1 \
--description="Application Docker images"
# Configure Docker authentication
$ gcloud auth configure-docker us-central1-docker.pkg.dev
# Build and push an image
$ docker build -t us-central1-docker.pkg.dev/my-project/app-images/web:v1.0.0 .
$ docker push us-central1-docker.pkg.dev/my-project/app-images/web:v1.0.0
# Set cleanup policy — delete untagged images older than 14 days
$ gcloud artifacts repositories set-cleanup-policies app-images \
--location=us-central1 \
--policy='{"conditionalPolicy":{"tagState":"UNTAGGED","olderThan":"1209600s"},"action":"DELETE"}'
# Verify the image
$ gcloud artifacts docker images list \
us-central1-docker.pkg.dev/my-project/app-images
Exercise 4 — Cloud Deploy Pipeline
Define a Cloud Deploy pipeline with dev → staging → production stages. The production target should require approval.
Show Answer
# clouddeploy.yaml
apiVersion: deploy.cloud.google.com/v1
kind: DeliveryPipeline
metadata:
name: web-app-pipeline
description: "Web application delivery pipeline"
serialPipeline:
stages:
- targetId: dev
profiles: [dev]
- targetId: staging
profiles: [staging]
- targetId: production
profiles: [production]
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: dev
description: "Development"
run:
location: projects/my-project/locations/us-central1
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: staging
description: "Staging"
run:
location: projects/my-project/locations/us-central1
---
apiVersion: deploy.cloud.google.com/v1
kind: Target
metadata:
name: production
description: "Production"
requireApproval: true
run:
location: projects/my-project/locations/us-central1
# Apply
$ gcloud deploy apply --file=clouddeploy.yaml --region=us-central1
# Create a release
$ gcloud deploy releases create release-v1 \
--delivery-pipeline=web-app-pipeline \
--region=us-central1 \
--images=web=us-central1-docker.pkg.dev/my-project/app-images/web:v1.0.0
# Promote through stages
$ gcloud deploy releases promote --release=release-v1 \
--delivery-pipeline=web-app-pipeline --region=us-central1
Exercise 5 — Canary Deployment on Cloud Run
Deploy a new version of a Cloud Run service with canary traffic splitting: start at 10%, verify, then promote to 100%.
Show Answer
# Deploy new revision with no traffic and a canary tag
$ gcloud run deploy my-app \
--image=us-central1-docker.pkg.dev/my-project/app-images/web:v2.0.0 \
--region=us-central1 \
--no-traffic \
--tag=canary
# Send 10% traffic to canary
$ gcloud run services update-traffic my-app \
--region=us-central1 \
--to-tags=canary=10
# Monitor (check error rates, latency)
# Wait and verify...
# Increase to 50%
$ gcloud run services update-traffic my-app \
--region=us-central1 \
--to-tags=canary=50
# Verify again, then promote to 100%
$ gcloud run services update-traffic my-app \
--region=us-central1 \
--to-latest
# View current traffic split
$ gcloud run services describe my-app \
--region=us-central1 \
--format="yaml(status.traffic)"
If issues are detected, rollback:
$ gcloud run services update-traffic my-app \
--region=us-central1 \
--to-tags=canary=0
Cleanup
$ gcloud deploy delivery-pipelines delete web-app-pipeline --region=us-central1 --force --quiet
$ gcloud artifacts repositories delete app-images --location=us-central1 --quiet
$ gcloud builds triggers delete ci-all-branches --region=us-central1 --quiet
$ gcloud builds triggers delete deploy-staging --region=us-central1 --quiet
$ gcloud builds triggers delete deploy-production --region=us-central1 --quiet
$ gcloud run services delete my-app --region=us-central1 --quiet
Next Chapter → Containers