GCP for DevOps — Deployment Strategies
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