CI/CD with Cloud Build
Cloud Build is GCP’s fully managed CI/CD platform. It builds, tests, and deploys code from source repositories — integrating with GitHub, GitLab, Bitbucket, and Cloud Source Repositories. Combined with Artifact Registry, Cloud Deploy, and IAM, it forms a complete delivery pipeline without managing Jenkins or other CI servers.
How Cloud Build Works
Trigger (push, PR, manual, schedule)
→ Build (steps in containers)
→ Artifacts (images, packages)
→ Deploy (GKE, Cloud Run, App Engine, Cloud Functions)
Each step runs in a container; steps execute sequentially or in parallel. Builds run on Google’s infrastructure — no agents to maintain.
Enable and Configure
gcloud services enable cloudbuild.googleapis.com artifactregistry.googleapis.com
# Create Artifact Registry repository
gcloud artifacts repositories create app \
--repository-format=docker \
--location=us-central1 \
--description="Application container images"
# Grant Cloud Build access to deploy
PROJECT_NUMBER=$(gcloud projects describe learning-gcp-dev --format='value(projectNumber)')
gcloud projects add-iam-policy-binding learning-gcp-dev \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/run.admin"
gcloud projects add-iam-policy-binding learning-gcp-dev \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
gcloud iam service-accounts add-iam-policy-binding \
${PROJECT_NUMBER}[email protected] \
--member="serviceAccount:${PROJECT_NUMBER}@cloudbuild.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
cloudbuild.yaml
steps:
# Run tests
- name: 'node:20'
entrypoint: npm
args: ['ci']
id: 'install'
- name: 'node:20'
entrypoint: npm
args: ['test']
id: 'test'
waitFor: ['install']
# Build container image
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/app/web:$COMMIT_SHA', '.']
id: 'build'
waitFor: ['test']
# Push to Artifact Registry
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/app/web:$COMMIT_SHA']
id: 'push'
waitFor: ['build']
# Deploy to Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
entrypoint: gcloud
args: ['run', 'deploy', 'web-app',
'--image=us-central1-docker.pkg.dev/$PROJECT_ID/app/web:$COMMIT_SHA',
'--region=us-central1',
'--platform=managed',
'--quiet']
id: 'deploy'
waitFor: ['push']
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/app/web:$COMMIT_SHA'
options:
logging: CLOUD_LOGGING_ONLY
machineType: 'E2_HIGHCPU_8'
timeout: '1200s'
Triggers
# GitHub trigger on push to main
gcloud builds triggers create github \
--name="deploy-on-push" \
--repo-name=my-web-app \
--repo-owner=my-org \
--branch-pattern="^main$" \
--build-config=cloudbuild.yaml \
--region=us-central1
# Pull request trigger (run tests only, no deploy)
gcloud builds triggers create github \
--name="test-on-pr" \
--repo-name=my-web-app \
--repo-owner=my-org \
--pull-request-pattern="^main$" \
--build-config=cloudbuild-test.yaml \
--comment-control=COMMENTS_ENABLED
# Manual trigger
gcloud builds triggers run deploy-on-push --branch=main
GKE Deployment
Add a deploy step for Kubernetes:
- name: 'gcr.io/cloud-builders/gke-deploy'
args:
- run
- --filename=k8s/
- --image=us-central1-docker.pkg.dev/$PROJECT_ID/app/web:$COMMIT_SHA
- --location=us-central1
- --cluster=prod-cluster
id: 'deploy-gke'
waitFor: ['push']
Or use kubectl with cluster credentials:
- name: 'gcr.io/cloud-builders/kubectl'
args: ['apply', '-f', 'k8s/']
env:
- 'CLOUDSDK_COMPUTE_REGION=us-central1'
- 'CLOUDSDK_CONTAINER_CLUSTER=prod-cluster'
Secrets in Builds
# Store secret in Secret Manager
echo -n "my-api-key" | gcloud secrets create api-key --data-file=-
# Grant Cloud Build access
gcloud secrets add-iam-policy-binding api-key \
--member="serviceAccount:[email protected]" \
--role="roles/secretmanager.secretAccessor"
In cloudbuild.yaml:
availableSecrets:
secretManager:
- versionName: projects/$PROJECT_ID/secrets/api-key/versions/latest
env: 'API_KEY'
steps:
- name: 'node:20'
entrypoint: npm
args: ['test']
secretEnv: ['API_KEY']
Progressive Delivery with Cloud Deploy
gcloud deploy delivery-pipelines create web-pipeline \
--region=us-central1 \
--description="Web app progressive delivery"
gcloud deploy targets create staging \
--delivery-pipeline=web-pipeline \
--region=us-central1 \
--gke-cluster=projects/learning-gcp-dev/locations/us-central1/clusters/staging-cluster
gcloud deploy targets create production \
--delivery-pipeline=web-pipeline \
--region=us-central1 \
--gke-cluster=projects/learning-gcp-dev/locations/us-central1/clusters/prod-cluster \
--require-approval
Cloud Deploy manages canary and blue-green rollouts with approval gates.
Cloud Build vs. Alternatives
| Feature | Cloud Build | GitHub Actions | Jenkins |
|---|---|---|---|
| Infrastructure | Fully managed | GitHub-hosted or self-hosted | Self-managed |
| GCP integration | Native | Via WIF + gcloud | Via plugins |
| Pricing | Per build-minute | Free tier + per-minute | Server cost |
| Secrets | Secret Manager | GitHub Secrets | Credentials plugin |
| Best for | GCP-native teams | GitHub-centric teams | Complex custom pipelines |
Real-World Scenario: Multi-Environment Pipeline
PR opened → cloudbuild-test.yaml (lint, unit tests, SAST)
↓ merge to main
cloudbuild.yaml → build image → push to Artifact Registry
↓
Deploy to staging (automatic)
↓
Integration tests on staging
↓
Deploy to production (manual approval via Cloud Deploy)
↓
Canary: 10% → 50% → 100% traffic shift
Common Mistakes
| Mistake | Impact | Fix |
|---|---|---|
| No test step before deploy | Broken code in production | Always test in pipeline |
:latest image tags |
Cannot rollback | Tag with $COMMIT_SHA |
| Secrets in cloudbuild.yaml | Leaked in version control | Secret Manager |
| No build timeout | Runaway build costs | Set timeout in yaml |
| Deploying from developer laptops | No audit trail | All deploys through CI/CD |
Best Practices
| Practice | Benefit |
|---|---|
| Secret Manager | Secure build credentials |
| Build caches | Faster subsequent builds |
| Separate triggers | Staging vs production promotion |
| Artifact Registry | Image vulnerability scanning |
| Cloud Deploy | Managed progressive rollouts |
| Immutable tags | Rollback to any commit |
| Build logs in Cloud Logging | Searchable, exportable audit trail |
| Workload Identity Federation | GitHub Actions without SA keys |
Troubleshooting
Build fails at push step:
gcloud builds log BUILD_ID
# Verify Artifact Registry permissions for Cloud Build SA
gcloud artifacts repositories describe app --location=us-central1
Deploy step permission denied:
# Check Cloud Build SA has roles/run.admin and iam.serviceAccountUser
gcloud projects get-iam-policy learning-gcp-dev \
--flatten="bindings[].members" \
--filter="bindings.members:cloudbuild"
Trigger not firing:
gcloud builds triggers list
gcloud builds triggers describe deploy-on-push --region=us-central1
# Verify GitHub App connection in Cloud Build settings
Slow builds:
Use Kaniko for cached Docker builds, or increase machineType to E2_HIGHCPU_32.
Cloud Build integrates natively with Artifact Registry, GKE, Cloud Run, and IAM.
Next: Cloud Run — serverless containers for production workloads.