Blue-green deployment setup
Learn to set up blue-green deployments: switch traffic between two identical environments for low-risk releases. This tutorial covers the core concept, step-by-step walkthrough, and troubleshooting tips — perfect for CI/CD foundations.
Focus: set up a blue-green deployment strategy
You’ve automated your builds and tests, but every release still feels like a high-wire act: one bad deploy, and your users are staring at a 502 while you scramble to roll back. The fix isn’t more caution — it’s a blue-green deployment strategy, a pattern that lets you switch traffic between two identical environments so releases become a routine, reversible flip. Here’s how to set one up and why it’s a cornerstone of modern CI/CD.
The problem this lesson solves
Traditional rolling deployments update instances one by one, so at any moment your cluster hosts a mix of old and new code. That’s fine for internal tools, but it creates a nightmare for user-facing services: version skew, database migrations that run against half-updated code, and a painful rollback that means redeploying the old version.
A blue-green deployment eliminates that mixing by keeping two production environments: blue (the current, stable version) and green (the new release). You deploy to green, test it in production-like conditions, then flip the router or load balancer to send all traffic to green. If something breaks, you flip back — no code redeploy, no downtime, no half-states.
The pain is real: without blue-green, rollbacks take minutes (or hours) and require a full redeploy. With blue-green, rollback is a single router change that takes seconds. That speed is what makes set up a blue-green deployment strategy a skill worth mastering.
Why it matters now: As your CI/CD pipeline matures, release frequency goes up. Blue-green deployments let you ship daily (or hourly) without turning every deploy into an incident.
Core concept / mental model
Think of a light switch in a dark room with two identical light bulbs. One bulb (blue) is lit — that’s your current live traffic. The other (green) is off — it’s the new code you’ve prepared. You wire up the new bulb, test it in the dark, then flip the switch. If the room catches fire, you flip back. That’s blue-green: two identical environments, one active at a time, a switch between them.
Defining terms
- Blue environment: The currently live version, receiving 100% of production traffic.
- Green environment: A fully provisioned, exact copy of blue, but with the new code deployed. It’s idle until you switch.
- Router or load balancer: The traffic switch — nginx, AWS ALB, Kubernetes Service, etc. It points at blue or green.
- Cutover: The moment you flip traffic from blue to green.
- Rollback: Flipping back to blue after a bad cutover.
Key principles
- Idempotence: Green must be created from the same infrastructure-as-code (Terraform, CloudFormation) as blue, so they’re identical.
- Database challenges: The database is shared, so schema changes must be backward-compatible (expand-migrate-contract).
- Cutover is not deployment: Deployment is to green; cutover is a traffic switch. Always separate them mentally.
When NOT to use it
- Stateful workloads: Databases, queues, or any service with client sessions stored locally — cutting over loses state.
- Cost-sensitive projects: Doubling infrastructure costs is hard to justify for a small hobby app.
How it works step by step
A blue-green deployment follows a repeatable sequence:
- Provision the green environment — Spin up an identical stack from your CI/CD pipeline or infrastructure code.
- Deploy the new version to green — Run your build, run tests, deploy the artifact to green.
- Validate green in isolation — Run smoke tests, health checks, and maybe a canary test against green’s internal URL.
- Switch traffic — Update the router to point at green; this is the atomic cutover. All new requests go to green.
- Monitor — Watch metrics, errors, and logs for a burn-in period (15–60 minutes).
- Keep blue for rollback — Leave blue alive. If anything breaks, flip the router back.
- Retire blue (optional) — After a day or two, tear down blue or reuse it for the next green.
Why the switch is atomic
In step 4, the router update is a single configuration change — either it points at blue or green. There’s no window where traffic splits, no version mixing. That atomicity is the core safety property.
Hands-on walkthrough
Let’s see blue-green in action. I’ll show two scenarios: one using a simple nginx router, and one with Kubernetes.
Scenario 1: Nginx-based blue-green
You have two directories: blue/ and green/, each containing an index.html. Below is a minimal nginx config that serves one of them, with a variable to switch.
http {
upstream backend {
server blue-app:8080; # or green-app:8080
}
server {
listen 80;
location / {
proxy_pass http://backend;
}
}
}
To cut over, you’d edit that server line and reload nginx — but that’s manual. A better way is to use Docker Compose and a simple switch.sh:
#!/bin/bash
# switch.sh — flips traffic between blue and green
if [[ "$(cat current)" == "blue" ]]; then
echo "green" > current
docker compose up -d green-app
# Update nginx config to point at green-app
sed -i 's/server blue-app/server green-app/' nginx.conf
docker compose exec nginx nginx -s reload
echo "Switched to green"
else
echo "blue" > current
docker compose up -d blue-app
sed -i 's/server green-app/server blue-app/' nginx.conf
docker compose exec nginx nginx -s reload
echo "Switched to blue"
fi
This script flips a marker file and reloads nginx. It’s the essence of the strategy — swap, reload, done.
Scenario 2: Kubernetes blue-green
Kubernetes gives you two Deployments (blue and green) and a Service that selects one via labels. Here’s the green deployment:
# green-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: app-green
labels:
app: myapp
version: green
spec:
replicas: 3
selector:
matchLabels:
app: myapp
version: green
template:
metadata:
labels:
app: myapp
version: green
spec:
containers:
- name: app
image: myapp:v2.0
ports:
- containerPort: 8080
And the Service that acts as the router:
# service.yaml
apiVersion: v1
kind: Service
metadata:
name: app-service
spec:
selector:
app: myapp
version: blue # change to green to switch
ports:
- port: 80
targetPort: 8080
To cut over, just edit the selector:
kubectl apply -f green-deployment.yaml
# Validate green (run smoke tests against its ClusterIP)
kubectl get pods -l version=green
# Switch traffic
kubectl patch service app-service -p '{"spec":{"selector":{"version":"green"}}}'
That single kubectl patch is your atomic switch. Rollback is the same command with blue.
Pro tip: Always run smoke tests against green before the switch. In Kubernetes, you can expose green via a temporary internal service or port-forward.
Expected output
When you run the Kubernetes switch, you’ll see:
service/app-service patched
And if you kubectl get pods within seconds, you’ll see green pods receiving traffic. If you monitor logs, you’ll see new requests hitting only green.
Compare options / when to choose what
Blue-green isn’t the only release strategy. Here’s how it stacks up:
| Strategy | Downtime | Rollback speed | Cost | Database risk | Best for |
|---|---|---|---|---|---|
| Blue-green | Zero | Instant (flip) | Double infra | Shared DB issues | APIs, web apps, services with low state |
| Canary | Zero | Moderate (scale down) | Slightly higher (partial) | Shared DB still risky | Gradual rollout, feature flags |
| Rolling | Zero | Slow (redeploy old) | Low (single set) | Can be risky (mixed versions) | Internal services, stateless apps |
| Recreate | Downtime | Fast (redeploy) | Low | Simple | Batch jobs, dev environments |
When to choose blue-green
- You need instant rollback: A single command reverts to the previous version.
- You can afford two environments: Even for a small service, doubling resources might be acceptable at low traffic.
- You can manage database compatibility: Your migrations are backward-compatible.
Variations
- Canary with blue-green: Route 5% of traffic to green first (using weighted load balancing), then flip completely after validation.
- Blue-green with database blue/green: Replicate your DB and switch connections — complex but possible for zero-downtime schema changes.
- Blue-green for serverless: Use API Gateway stage variables to switch between Lambda aliases or versions.
Troubleshooting & edge cases
Common mistakes and fixes
- Database not compatible: Your new code works against an old schema, but cutover breaks writes. Fix: use expand-migrate-contract — add new columns first, release, then clean up. Always test migrations against a copy.
- Green environment drifts: Green isn’t truly identical because someone hand-tweaked it. Fix: provision both environments with the same Terraform module; never manually configure.
- Session state lost: Users get logged out after cutover because sessions are stored in memory on blue. Fix: store sessions in Redis or a database shared across environments.
- DNS caching delays: If you flip via DNS instead of a load balancer, clients may hit the old IP for hours. Fix: always use a load balancer or service to switch; avoid DNS-level cutover.
- The switch wasn’t atomic: You edited a config file over several seconds, and traffic hit a mixed state. Fix: use a single atomic update (e.g., Kubernetes patch, or a config management tool) and reload, not incremental edits.
Edge cases
- Blue-green with a message queue: If green consumes from the same queue as blue, you’ll have duplicate processing. You need to pause blue consumers before cutover.
- Multiple services: If your app spans several microservices, you need to coordinate cutovers across all of them or you’ll get version skew. Use a service mesh or feature flags to handle it.
- Long-running requests: In-flight requests may still be handled by blue after cutover. Design your load balancer to drain connections before fully switching.
What you learned & what's next
Now you can set up a blue-green deployment strategy: you understand the mental model of two identical environments, you’ve seen the step-by-step sequence, you’ve implemented it with both nginx and Kubernetes, and you know when to prefer it over canary or rolling. You know that rollback is just a flip, and you’ve learned to dodge the common database and session pitfalls.
You’ve met both learning objectives: you can explain the core idea, and you can complete a hands-on exercise. In the next lesson in this CI/CD foundations track, you’ll learn how to automate the whole blue-green process in your CI/CD pipeline — wiring the deployment and switch into your GitHub Actions or Jenkins workflow so cuts are one-click. That’s where the real speed lives.
Practice recap
Try this: on a test cluster or Docker Compose setup, deploy a simple web app to ‘blue’, then create ‘green’ with a different version. Run a smoke test against green, then switch the service selector (or nginx upstream) to green. Verify traffic hits green, then flip back to blue — measure the time it takes. This hands-on exercise will cement the atomic switch concept.
Common mistakes
- Not making the switch atomic — scientists update a config file in multiple steps, causing mixed traffic. Always use a single atomic update like
kubectl patchor a config reload. - Ignoring database compatibility — your new schema breaks the old code during rollback. Follow expand-migrate-contract: add new columns first, release, then clean up.
- Forgetting session state — users get logged out after cutover because sessions live in memory on the old environment. Store sessions in Redis or a shared DB.
- Using DNS-based cutover — DNS caching delays mean some users hit the old IP for hours. Use a load balancer or service as the switch, not DNS.
- Letting green and blue drift — manual tweaks make environments non-identical, breaking rollbacks. Provision both from the same Terraform module or pipeline.
Variations
- Canary with blue-green: route a small percentage of traffic to green first (weighted load balancer), validate, then flip 100%. Useful when you want extra safety before full cutover.
- Blue-green with database replication: maintain a database replica for green and switch connections atomically — complex but gives zero-downtime schema changes.
- Serverless blue-green: use API Gateway stage variables to switch between Lambda aliases/versions — a lightweight cloud-native take on the pattern.
Real-world use cases
- You manage a public REST API with millions of requests; a bad deploy would take down the service. Blue-green gives instant rollback with zero downtime.
- Your SaaS platform does weekly releases to production; you need to validate the new version in a production-like environment before switching all users, and you must keep the old version available for rollback.
- You run a Kubernetes microservices app; you use blue-green deployments for each service to avoid version skew during upgrades, with a service mesh controlling traffic.
Key takeaways
- Blue-green deployments use two identical environments — blue (live) and green (new) — with an atomic traffic switch between them.
- The cutover is a single router or load-balancer change, not a redeployment; rollback is the same flip in reverse.
- Always validate green in isolation (smoke tests, health checks) before switching traffic.
- Database changes must be backward-compatible; use expand-migrate-contract to avoid rollback issues.
- Keep blue alive for rollback until you’re confident in green; then retire it to save costs.
- Blue-green is ideal when you need instant rollback, but it doubles infrastructure cost — consider canary for gradual rollout.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.