Definition
- Blue-Green – Two identical environments (blue = current, green = new); deploy and test on green, then switch all traffic at once; blue remains as an instant rollback target.
- Canary – Release the new version to a small percentage of traffic (1-5%), increase gradually while watching metrics, and abort if metrics regress.
- Rolling – Replace instances of the old version with the new version a few at a time; the Kubernetes default, controlled by
maxSurgeandmaxUnavailable. - Trade-offs – Blue-Green: instant rollback but double cost; Canary: smallest blast radius but complex routing; Rolling: cost-efficient but mixed versions and slower rollback.
- Database rule – All three require backward-compatible schema changes (expand-and-contract) because old and new code may run simultaneously.
Imagine the National Bank of India upgrading its branch systems. Blue-Green is building a second identical branch next door with the new system, testing it, then redirecting all customers to it in one switch, and if anything is wrong, switching everyone straight back. Canary is quietly sending just a handful of customers like Rajesh to the new counter first, watching closely, and only if all goes well sending more until everyone is on it. Rolling is upgrading the counters one at a time while the branch stays open, so some counters are new and some are old until the last one is done.
Understanding the Concepts
What is Blue-Green deployment?
Blue-Green keeps two complete environments. The blue environment serves production while you deploy and fully test the new version in green. When green is verified, you flip the router or load balancer so all traffic goes to green at once. Blue stays warm as an instant rollback target.
# Blue-Green on AWS with ALB target groups
# Blue (current): banking-api-blue target group
# Green (new): banking-api-green target group
# Deploy and test green
aws ecs update-service --cluster banking --service banking-api-green \
--task-definition banking-api:v5.3
# Run smoke tests against green
curl -s https://green.api.nationalbank.in/health
# Switch all traffic from blue to green
aws elbv2 modify-listener \
--listener-arn $LISTENER_ARN \
--default-actions Type=forward,TargetGroupArn=$GREEN_TG_ARN
# Rollback: flip back to blue instantly
aws elbv2 modify-listener \
--listener-arn $LISTENER_ARN \
--default-actions Type=forward,TargetGroupArn=$BLUE_TG_ARN
What is Canary deployment?
Canary releases the new version to a small slice of traffic first (say 5%), while 95% stays on stable. You watch error rate, latency, and business metrics. If healthy, increase to 25%, 50%, 100%. If it regresses, route everyone back to stable.
# Argo Rollouts: Canary with metric-driven promotion
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: banking-api
namespace: banking
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 50
- pause: { duration: 10m }
- setWeight: 100
analysis:
templates:
- templateName: banking-api-success-rate
startingStep: 1
args:
- name: service-name
value: banking-api
# AnalysisTemplate: auto-abort if success rate drops below 99%
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: banking-api-success-rate
spec:
metrics:
- name: success-rate
interval: 1m
successCondition: result[0] >= 0.99
provider:
prometheus:
address: http://prometheus:9090
query: |
sum(rate(http_requests_total{app="banking-api",status=~"2.."}[5m]))
/
sum(rate(http_requests_total{app="banking-api"}[5m]))
What is Rolling deployment?
Rolling replaces instances incrementally: start a few new ones, wait for them to become healthy, terminate a few old ones, repeat. It is the Kubernetes default, controlled by maxSurge and maxUnavailable.
# Kubernetes Rolling Update strategy
apiVersion: apps/v1
kind: Deployment
metadata:
name: banking-api
namespace: banking
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # at most 1 extra Pod during rollout
maxUnavailable: 0 # all current Pods stay available
template:
spec:
containers:
- name: banking-api
image: registry.nationalbank.in/banking-api:v5.3
# Trigger a rolling update
kubectl set image deployment/banking-api \
banking-api=registry.nationalbank.in/banking-api:v5.3 -n banking
# Watch the rollout
kubectl rollout status deployment/banking-api -n banking
# Rollback (also a rolling operation)
kubectl rollout undo deployment/banking-api -n banking
How do the three strategies compare? (comparison table)
| Aspect | Blue-Green | Canary | Rolling | |---|---|---|---| | Traffic switch | All at once | Gradual (1% -> 100%) | Incremental | | Blast radius | All users or none | Small % first | Mixed during rollout | | Rollback speed | Instant (flip back) | Fast (route to stable) | Slow (rolling back) | | Extra infrastructure | Double (two full envs) | Minimal | None | | Version mixing | No (clean cutover) | Yes (old + new) | Yes (old + new) | | Complexity | Moderate | High (routing + metrics) | Low (K8s default) | | Best for | Critical releases | Risky changes | Routine updates |
When should you use each?
Use Blue-Green when you need instant, clean cutover and instant rollback, for example for a critical payments release where you cannot tolerate a slow or messy rollback, and when you can afford the temporary double capacity.
Use Canary when the risk of a regression is high or the change is significant, when you serve enough traffic that a small percentage is still a meaningful sample, and when you want automated, metric-driven promotion.
Use Rolling for routine, low-to-moderate-risk updates of stateless services where brief version mixing is acceptable and you want simplicity with no extra cost.
# Decision at National Bank of India:
# Payments service (critical, money movement) -> Blue-Green
# New fraud-scoring model (risky, needs validation) -> Canary
# Account-query service (routine, stateless) -> Rolling
What about database schema changes?
Across all three strategies, old and new code may run at the same moment, so database schema changes must be backward and forward compatible. Use the expand-and-contract pattern.
-- WRONG: Drop a column that old code still reads
ALTER TABLE accounts DROP COLUMN account_type;
-- Old code (still running during rollout) crashes!
-- CORRECT: Expand-and-contract in 3 steps
-- Step 1 (deploy v5.2): Add new column, keep old column
ALTER TABLE accounts ADD COLUMN account_category VARCHAR(50);
-- Both v5.1 and v5.2 work (old reads old column, new reads both)
-- Step 2 (after v5.2 is fully rolled out): Migrate data
UPDATE accounts SET account_category = account_type;
-- Step 3 (deploy v5.3): Remove old column
ALTER TABLE accounts DROP COLUMN account_type;
-- Only v5.3 is running, so it is safe to drop.
What are common mistakes?
# WRONG: Using Blue-Green without handling database migrations
# Blue and green share the same database.
# You run a migration that drops a column before flipping.
# Blue (still serving traffic) crashes because the column is gone.
# CORRECT: Use expand-and-contract migrations.
# Both blue and green can work with the schema at all times.
# WRONG: Using Canary without automated metric analysis
# You send 5% to canary, but nobody watches the metrics.
# The canary has a 10x error rate, but it gets promoted to 100% manually.
# CORRECT: Use Argo Rollouts or Flagger with automated analysis.
# If success rate drops below 99%, the canary is automatically aborted.
What are common interview follow-up questions?
- "Can you combine strategies?" – Yes. Use Canary for initial validation, then Blue-Green for the final switch.
- "How do feature flags relate?" – Feature flags decouple code deployment from feature activation. You can deploy code with a flag off using Rolling, then activate the feature gradually by flipping the flag, achieving canary-like behavior without traffic splitting.
- "What about stateful services?" – Stateful services (databases, queues) are harder to deploy with any strategy. Use expand-and-contract for schema, and consider separate deployment pipelines for stateful components.
Visual Overview
Deployment Strategies Comparison
=================================
Blue-Green (instant switch)
──────────────────────────
[Blue v5.2] ◄── 100% traffic
[Green v5.3] 0% traffic (testing)
│
FLIP ▼
[Blue v5.2] 0% traffic (rollback ready)
[Green v5.3] ◄── 100% traffic
Canary (gradual increase)
─────────────────────────
[Stable v5.2] ◄── 95% traffic
[Canary v5.3] ◄── 5% traffic
│ metrics OK
▼
[Stable v5.2] ◄── 50% traffic
[Canary v5.3] ◄── 50% traffic
│ metrics OK
▼
[New v5.3] ◄── 100% traffic
Rolling (one by one)
────────────────────
[v5.2] [v5.2] [v5.2] [v5.2] <- all old
[v5.3] [v5.2] [v5.2] [v5.2] <- 1 new
[v5.3] [v5.3] [v5.2] [v5.2] <- 2 new
[v5.3] [v5.3] [v5.3] [v5.3] <- all new
Key Takeaway
Blue-Green, Canary, and Rolling are three deployment strategies that trade off risk, cost, speed, and rollback ability. Blue-Green runs two identical environments and switches all traffic at once, giving instant cutover and instant rollback at the cost of double infrastructure, so use it for critical releases where you cannot tolerate a slow rollback. Canary releases the new version to a small percentage first and increases gradually while watching metrics, giving the smallest blast radius and automated metric-driven promotion, so use it for risky or significant changes.
Rolling replaces instances a few at a time with no extra environment, which is cost-efficient and simple but mixes versions during the rollout and has slower rollback, so use it for routine low-risk updates. At the National Bank of India, the critical payments service used Blue-Green for instant rollback, the risky fraud-scoring model used Canary and was automatically aborted when metrics regressed, and the routine account-query service used a simple Rolling update. Across all three, database schema changes must use expand-and-contract because old and new code may run simultaneously, and feature flags complement these strategies by decoupling code deployment from feature activation.
Remember one sentence: choose Blue-Green for instant rollback, Canary for smallest blast radius with metric-driven confidence, and Rolling for routine simplicity, and always use expand-and-contract for database migrations.
---