GCP Cloud Build and CI/CD

Cloud Build is GCP's fully managed CI/CD (Continuous Integration and Continuous Deployment) service. It automatically builds, tests, and deploys application code whenever a change is pushed to a source repository. Cloud Build eliminates manual deployment steps and ensures every code change is tested before reaching production.

Imagine a car factory assembly line. A worker places raw materials at one end (code commit). The line automatically welds, paints, checks quality, and produces a finished car (deployed application) at the other end — without anyone manually running each step. Cloud Build is that assembly line for software.

CI/CD Concepts

TermDefinitionExample
Continuous Integration (CI)Automatically build and test code on every commitRun unit tests when a developer pushes code
Continuous Delivery (CD)Automatically prepare code for deployment after CI passesBuild a container image after tests pass
Continuous DeploymentAutomatically deploy to production after CD passesPush container to Cloud Run automatically

Cloud Build Architecture

Developer pushes code to GitHub / Cloud Source Repositories
                │
                ▼
Cloud Build Trigger fires
                │
                ▼
Cloud Build (runs steps defined in cloudbuild.yaml)
    │
    ├── Step 1: Install dependencies (npm install / pip install)
    ├── Step 2: Run unit tests
    ├── Step 3: Build container image (docker build)
    ├── Step 4: Push image to Artifact Registry
    └── Step 5: Deploy to Cloud Run / GKE / App Engine
                │
                ▼
Application is live in production ✓

The cloudbuild.yaml File

Every Cloud Build pipeline is defined by a cloudbuild.yaml file in the root of the repository. Each step in the file runs a Docker container to execute a command.

Example – Python App: Test, Build, Deploy to Cloud Run

# cloudbuild.yaml
steps:
  # Step 1 — Run unit tests
  - name: 'python:3.11'
    entrypoint: 'bash'
    args:
      - '-c'
      - |
        pip install -r requirements.txt
        python -m pytest tests/ -v

  # Step 2 — Build the Docker container image
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'build'
      - '-t'
      - 'us-central1-docker.pkg.dev/my-project/my-repo/my-app:$COMMIT_SHA'
      - '.'

  # Step 3 — Push image to Artifact Registry
  - name: 'gcr.io/cloud-builders/docker'
    args:
      - 'push'
      - 'us-central1-docker.pkg.dev/my-project/my-repo/my-app:$COMMIT_SHA'

  # Step 4 — Deploy to Cloud Run
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    args:
      - 'gcloud'
      - 'run'
      - 'deploy'
      - 'my-app'
      - '--image=us-central1-docker.pkg.dev/my-project/my-repo/my-app:$COMMIT_SHA'
      - '--region=us-central1'
      - '--allow-unauthenticated'

# Store the built image in Artifact Registry
images:
  - 'us-central1-docker.pkg.dev/my-project/my-repo/my-app:$COMMIT_SHA'

Built-in substitution variables available in every build:

VariableValue
$PROJECT_IDThe GCP project ID
$COMMIT_SHAThe Git commit hash (first 7 characters)
$BRANCH_NAMEThe Git branch name
$SHORT_SHAShort version of the commit hash
$REPO_NAMEThe source repository name

Cloud Build Triggers

A trigger automatically starts a build when specific events happen in a source repository.

# Create a trigger that runs on every push to the main branch
gcloud builds triggers create github \
  --repo-name=my-app \
  --repo-owner=my-github-username \
  --branch-pattern="^main$" \
  --build-config=cloudbuild.yaml

Common trigger configurations:

  • Push to branch: Build runs when code is pushed to a specific branch (e.g., main, production)
  • Push to any branch: Build runs on every push to any branch
  • Pull request: Build runs when a pull request is opened or updated (for testing before merge)
  • Tag push: Build runs when a Git tag is pushed (e.g., v1.0.0 for releases)

Artifact Registry

Artifact Registry is GCP's managed repository for storing build artifacts — container images, Maven packages, npm packages, and Python wheels. It replaces the older Container Registry.

# Create a Docker repository in Artifact Registry
gcloud artifacts repositories create my-repo \
  --repository-format=docker \
  --location=us-central1

# Configure Docker to authenticate with Artifact Registry
gcloud auth configure-docker us-central1-docker.pkg.dev

# Push an image
docker push us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest

# Pull an image
docker pull us-central1-docker.pkg.dev/my-project/my-repo/my-app:latest

Multi-Environment Pipeline

A professional CI/CD setup typically deploys to multiple environments based on the Git branch:

Git Branches and Environments:
┌─────────────────────────────────────────────────────────┐
│                                                         │
│  feature/* branch                                       │
│  → Build + Test only (no deployment)                    │
│                                                         │
│  develop branch                                         │
│  → Build + Test + Deploy to DEV environment             │
│                                                         │
│  staging branch                                         │
│  → Build + Test + Deploy to STAGING environment         │
│                                                         │
│  main/production branch                                 │
│  → Build + Test + Deploy to PRODUCTION environment      │
│                                                         │
└─────────────────────────────────────────────────────────┘

Branch-Based Deployment in cloudbuild.yaml

steps:
  - name: 'python:3.11'
    entrypoint: bash
    args: ['-c', 'pip install -r requirements.txt && pytest tests/']

  - name: 'gcr.io/cloud-builders/docker'
    args: ['build', '-t', 'gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA', '.']

  # Deploy to staging (only on the staging branch)
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: bash
    args:
      - '-c'
      - |
        if [[ "$BRANCH_NAME" == "staging" ]]; then
          gcloud run deploy my-app-staging \
            --image=gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA \
            --region=us-central1
        fi

  # Deploy to production (only on the main branch)
  - name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
    entrypoint: bash
    args:
      - '-c'
      - |
        if [[ "$BRANCH_NAME" == "main" ]]; then
          gcloud run deploy my-app-prod \
            --image=gcr.io/$PROJECT_ID/my-app:$COMMIT_SHA \
            --region=us-central1
        fi

Running a Build Manually

# Trigger a build manually from the current directory
gcloud builds submit --config=cloudbuild.yaml .

# Trigger a build with custom substitutions
gcloud builds submit --config=cloudbuild.yaml \
  --substitutions=_ENV=staging,_VERSION=1.2.0 .

Key Takeaways

  • Cloud Build automates building, testing, and deploying applications on every code commit.
  • The cloudbuild.yaml file defines the pipeline steps — each step runs in a Docker container.
  • Triggers connect a Git repository event (push, pull request) to a build pipeline.
  • Artifact Registry stores container images and other build outputs securely.
  • Multi-environment pipelines use Git branches to control which environment receives a deployment.
  • Built-in variables like $COMMIT_SHA enable traceable, versioned deployments.

Leave a Comment