GCP for DevOps — Cloud Build
3 minute read
Cloud Build
Cloud Build is Google Cloud’s serverless CI/CD platform. It executes builds as a series of steps defined in cloudbuild.yaml, running each step in a Docker container.
How Cloud Build Works
┌──────────────────────────────────────────────┐
│ Cloud Build Execution │
├──────────────────────────────────────────────┤
│ │
│ cloudbuild.yaml │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ Step 1 ├──► Step 2 ├──► Step 3 │ │
│ │ (build) │ │ (test) │ │ (push) │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ /workspace (shared volume across all steps) │
│ │
│ Built-in builders: │
│ gcr.io/cloud-builders/docker │
│ gcr.io/cloud-builders/gcloud │
│ gcr.io/cloud-builders/kubectl │
│ gcr.io/cloud-builders/npm │
│ gcr.io/cloud-builders/go │
└──────────────────────────────────────────────┘
Basic cloudbuild.yaml
# cloudbuild.yaml — Build, test, and push a Docker image
steps:
# Step 1: Build the Docker image
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA', '.']
# Step 2: Run tests
- name: 'gcr.io/cloud-builders/docker'
args: ['run', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA', 'npm', 'test']
# Step 3: Push to Artifact Registry
- name: 'gcr.io/cloud-builders/docker'
args: ['push', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA']
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
options:
logging: CLOUD_LOGGING_ONLY
Submit a Build Manually
# Submit from current directory
$ gcloud builds submit --config=cloudbuild.yaml .
# Submit with substitution variables
$ gcloud builds submit --config=cloudbuild.yaml \
--substitutions=_ENV=staging,_VERSION=1.2.3 .
# Quick build — Dockerfile only (no cloudbuild.yaml needed)
$ gcloud builds submit --tag us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest .
Built-in Substitution Variables
| Variable |
Description |
$PROJECT_ID |
GCP project ID |
$BUILD_ID |
Unique build ID |
$COMMIT_SHA |
Full Git commit SHA |
$SHORT_SHA |
First 7 characters of commit SHA |
$BRANCH_NAME |
Git branch name |
$TAG_NAME |
Git tag name |
$REPO_NAME |
Repository name |
$_CUSTOM_VAR |
User-defined substitution (prefix _) |
Multi-Step Pipeline Example
steps:
# Install dependencies
- name: 'node:18'
entrypoint: 'npm'
args: ['ci']
# Lint
- name: 'node:18'
entrypoint: 'npm'
args: ['run', 'lint']
# Unit tests
- name: 'node:18'
entrypoint: 'npm'
args: ['test']
# Build Docker image
- name: 'gcr.io/cloud-builders/docker'
args:
- 'build'
- '-t'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
- '-t'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:latest'
- '.'
# Push image
- name: 'gcr.io/cloud-builders/docker'
args: ['push', '--all-tags', 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app']
# 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'
images:
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:$SHORT_SHA'
- 'us-central1-docker.pkg.dev/$PROJECT_ID/my-repo/my-app:latest'
timeout: '1200s'
options:
machineType: 'E2_HIGHCPU_8'
Parallel Steps
steps:
- name: 'node:18'
entrypoint: 'npm'
args: ['ci']
id: 'install'
- name: 'node:18'
entrypoint: 'npm'
args: ['run', 'lint']
id: 'lint'
waitFor: ['install']
- name: 'node:18'
entrypoint: 'npm'
args: ['test']
id: 'test'
waitFor: ['install']
# lint and test run in parallel after install
- name: 'gcr.io/cloud-builders/docker'
args: ['build', '-t', 'my-app', '.']
id: 'build'
waitFor: ['lint', 'test']
Saving Artifacts
steps:
- name: 'gcr.io/cloud-builders/go'
args: ['build', '-o', 'app', '.']
artifacts:
objects:
location: 'gs://my-build-artifacts/builds/$BUILD_ID/'
paths: ['app']
Build Configuration Options
| Option |
Description |
machineType |
E2_MEDIUM, E2_HIGHCPU_8, E2_HIGHCPU_32 |
diskSizeGb |
Disk size for build (default 100 GB) |
timeout |
Max build duration (default 10 min, max 24 hr) |
logging |
CLOUD_LOGGING_ONLY, GCS_ONLY, NONE |
pool |
Private pool for VPC access |
Service Account Permissions
Cloud Build uses a default service account: PROJECT_NUMBER@cloudbuild.gserviceaccount.com
# Grant Artifact Registry writer
$ gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:123456789@cloudbuild.gserviceaccount.com" \
--role="roles/artifactregistry.writer"
# Grant Cloud Run deployer
$ gcloud projects add-iam-policy-binding my-project \
--member="serviceAccount:123456789@cloudbuild.gserviceaccount.com" \
--role="roles/run.admin"
Common Mistakes
| Mistake |
Why It’s Wrong |
Fix |
No waitFor on independent steps |
Steps run sequentially by default |
Use id and waitFor for parallelism |
| Hardcoding project ID |
Breaks across projects |
Use $PROJECT_ID substitution |
| Default machine type for large builds |
Slow builds |
Use E2_HIGHCPU_8 or higher |
| Missing service account roles |
Build fails on push/deploy |
Grant required IAM roles |
| No timeout set |
Builds can run for 24 hours |
Set explicit timeout |
Quick Reference
| Command |
Description |
gcloud builds submit --config=FILE . |
Submit a build |
gcloud builds submit --tag TAG . |
Quick Docker build |
gcloud builds list |
List recent builds |
gcloud builds log BUILD_ID |
View build logs |
gcloud builds cancel BUILD_ID |
Cancel a build |
Next → Build Triggers