Blue-Green Deployments: Zero-Downtime Releases with Instant Rollback
February 16, 2026 · 7 min · 1343 words · Rob Washington
Table of Contents
What if you could deploy with a safety net? Blue-green deployments give you exactly that: two identical production environments, one serving traffic while the other waits in the wings.
Deploy to the idle environment, test it, then switch traffic instantly. If something breaks, switch back. No rollback procedure—just flip.
# Blue deploymentapiVersion:apps/v1kind:Deploymentmetadata:name:app-bluespec:replicas:3selector:matchLabels:app:myappversion:bluetemplate:metadata:labels:app:myappversion:blue---# Green deployment apiVersion:apps/v1kind:Deploymentmetadata:name:app-greenspec:replicas:3selector:matchLabels:app:myappversion:greentemplate:metadata:labels:app:myappversion:green---# Service (switch by changing selector)apiVersion:v1kind:Servicemetadata:name:myappspec:selector:app:myappversion:blue # Change to 'green' to switchports:- port:80
Switch with one command:
1
kubectl patch service myapp -p '{"spec":{"selector":{"version":"green"}}}'
#!/bin/bash
set -e
CURRENT=$(kubectl get svc myapp -o jsonpath='{.spec.selector.version}')TARGET=$(["$CURRENT"="blue"]&&echo"green"||echo"blue")echo"Current: $CURRENT, Deploying to: $TARGET"# Deploy new version to idle environmentkubectl set image deployment/app-$TARGETapp=myapp:$VERSION# Wait for rolloutkubectl rollout status deployment/app-$TARGET --timeout=300s
# Run smoke testsecho"Running smoke tests against $TARGET..."./smoke-tests.sh "http://app-$TARGET.internal"if[$? -eq 0];thenecho"Smoke tests passed. Switching traffic..." kubectl patch service myapp -p "{\"spec\":{\"selector\":{\"version\":\"$TARGET\"}}}"echo"Traffic switched to $TARGET"elseecho"Smoke tests failed. Aborting."exit1fi
asyncfunctionvalidateGreenEnvironment(){constchecks=[// Health check
fetch('https://green.internal/health').then(r=>r.ok?'pass':'fail'),// API smoke test
fetch('https://green.internal/api/status').then(r=>r.json()).then(d=>d.version===expectedVersion?'pass':'fail'),// Database connectivity
fetch('https://green.internal/api/db-check').then(r=>r.ok?'pass':'fail'),// Critical endpoint
fetch('https://green.internal/api/users/test-user').then(r=>r.status===200?'pass':'fail'),];constresults=awaitPromise.all(checks);constallPassed=results.every(r=>r==='pass');console.log('Validation results:',results);returnallPassed;}
Blue-green works best with stateless applications. Databases complicate things:
Option 1: Shared Database
Both environments connect to the same database. Schema changes must be backward compatible.
Option 2: Database per Environment
More isolation, but requires data sync:
Option 3: Expand-Contract Migrations
Use the expand-contract pattern from database migrations—new code works with old schema, old code works with new schema.
Terminate idle environment after successful deployment window
1
2
3
4
5
# After successful deployment, scale down old environmentkubectl scale deployment app-blue --replicas=1# After 24 hours with no issues, you could remove it entirely# (but keep the deployment manifest for quick spin-up)