GCP for DevOps — Deployment Strategies

3 minute read

Deployment Strategies

Choosing the right deployment strategy minimizes downtime and risk. GCP supports rolling, canary, and blue-green deployments natively through Cloud Deploy, GKE, and Cloud Run.

Strategy Comparison

┌────────────────────────────────────────────────────────┐
│           Deployment Strategies Overview                │
├──────────┬────────────┬────────────┬──────────────────┤
│          │  Rolling   │  Canary    │  Blue-Green      │
├──────────┼────────────┼────────────┼──────────────────┤
│Downtime  │ Zero       │ Zero       │ Zero             │
│Risk      │ Medium     │ Low        │ Lowest           │
│Rollback  │ Slow       │ Fast       │ Instant          │
│Cost      │ 1× infra   │ 1× + small │ 2× infra        │
│Complexity│ Low        │ Medium     │ Medium           │
└──────────┴────────────┴────────────┴──────────────────┘

Rolling Deployment

Replace instances gradually — the default for GKE Deployments.

# GKE Rolling Update
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-app
spec:
  replicas: 4
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxUnavailable: 1
      maxSurge: 1
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
        - name: my-app
          image: us-central1-docker.pkg.dev/my-project/my-repo/my-app:v2.0.0
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
            initialDelaySeconds: 5
            periodSeconds: 10
# Trigger a rolling update
$ kubectl set image deployment/my-app \
    my-app=us-central1-docker.pkg.dev/my-project/my-repo/my-app:v2.0.0

# Watch the rollout
$ kubectl rollout status deployment/my-app

# Rollback if needed
$ kubectl rollout undo deployment/my-app

Canary Deployment

Route a small percentage of traffic to the new version, then gradually increase.

Cloud Run — Traffic Splitting

# Deploy new revision (no traffic yet)
$ gcloud run deploy my-app \
    --image=us-central1-docker.pkg.dev/my-project/my-repo/my-app: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 metrics, then increase to 50%
$ gcloud run services update-traffic my-app \
    --region=us-central1 \
    --to-tags=canary=50

# Promote canary to 100%
$ gcloud run services update-traffic my-app \
    --region=us-central1 \
    --to-latest

# Rollback — send all traffic to previous revision
$ gcloud run services update-traffic my-app \
    --region=us-central1 \
    --to-revisions=my-app-00001-abc=100

Cloud Deploy — Canary Pipeline

# In clouddeploy.yaml
serialPipeline:
  stages:
    - targetId: production
      profiles: [production]
      strategy:
        canary:
          runtimeConfig:
            cloudRun:
              automaticTrafficControl: true
          canaryDeployment:
            percentages: [10, 25, 50, 75]
            verify: true

GKE — Canary with Istio/Gateway API

# HTTPRoute for canary traffic splitting
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
  name: my-app-route
spec:
  parentRefs:
    - name: my-gateway
  rules:
    - backendRefs:
        - name: my-app-stable
          port: 80
          weight: 90
        - name: my-app-canary
          port: 80
          weight: 10

Blue-Green Deployment

Run two identical environments; switch traffic instantly.

# Blue is current (production)
# Green is new version

# Deploy green (new version)
$ gcloud run deploy my-app-green \
    --image=us-central1-docker.pkg.dev/my-project/my-repo/my-app:v2.0.0 \
    --region=us-central1 \
    --no-traffic

# Test green at its unique URL
$ curl https://green---my-app-abc123.a.run.app/healthz

# Switch all traffic to green
$ gcloud run services update-traffic my-app \
    --region=us-central1 \
    --to-latest

# If issues — instant rollback to blue
$ gcloud run services update-traffic my-app \
    --region=us-central1 \
    --to-revisions=my-app-00001-blue=100

GKE Blue-Green with Service Switching

# Deploy green deployment
$ kubectl apply -f deployment-green.yaml

# Test green internally
$ kubectl port-forward svc/my-app-green 8081:80

# Switch the production service selector to green
$ kubectl patch service my-app-prod \
    -p '{"spec":{"selector":{"version":"green"}}}'

# Rollback — switch selector back to blue
$ kubectl patch service my-app-prod \
    -p '{"spec":{"selector":{"version":"blue"}}}'

Strategy Selection Guide

Factor Rolling Canary Blue-Green
Stateless web app ✅ Good ✅ Best ✅ Good
API with breaking changes ❌ Risky ✅ Best ✅ Good
Database migrations ✅ (with backward compat) ✅ ❌ Complex
Instant rollback needed ❌ Slow ⚡ Fast ⚡ Instant
Cost-sensitive ✅ Best ✅ Good ❌ 2× cost
Compliance/audit ✅ Good ✅ Good ✅ Best

Common Mistakes

Mistake Why It’s Wrong Fix
No health checks in rolling update Unhealthy pods get traffic Add readiness/liveness probes
Canary without metrics monitoring Don’t know if canary is healthy Monitor error rate before promoting
Blue-green without smoke tests Switch to broken green Test green endpoint before switching
No rollback plan Stuck with bad deployment Document and test rollback procedure
Forgetting database compatibility New code, old schema Use backward-compatible migrations

Quick Reference

Strategy GKE Cloud Run Cloud Deploy
Rolling strategy.rollingUpdate Default Default
Canary Istio / Gateway API --to-tags=canary=N canaryDeployment.percentages
Blue-Green Service selector switch --to-revisions Custom target

Next → CI/CD Exercises

Updated: