Skip to main content

Zero-Downtime Deploy: Blue-Green and Rolling Strategies

Migration · 04.02.2025 · 4 min read
Illustration for “Zero-Downtime Deploy: Blue-Green and Rolling Strategies”

A deploy order that never returns 502

Zero downtime does not mean "no risk" — it means "no interruption visible to the user." That is achieved by bringing up and checking the new version next to the old one, then switching over with a single atomic operation that is easy to undo.

  1. Deploy the new version of the application on a separate port or in a separate container, without touching the running one.
  2. Wait until the new version passes its health check and fully initializes (warms its cache, connects to the database).
  3. Check the new version directly, bypassing the main domain — through the direct port or a service header.
  4. Switch the load balancer or proxy to the new version with a single command.
  5. Keep the old version running for a while longer, in case an instant rollback is needed.

Being honest: truly zero downtime never happens even with this order — a fraction of a second remains for switching connections at the moment of reload. In practice that means 0-2 seconds of visible delay for some requests, not a complete absence of any effect.

Blue-Green deployment

Keep two identical environments: Blue (the current live one) and Green (the new version). After testing Green, switch the traffic over.

# Nginx upstream — switching between blue and green
upstream app {
    server 127.0.0.1:8080;  # blue
    # server 127.0.0.1:8081;  # green (uncomment when switching)
}

server {
    location / {
        proxy_pass http://app;
    }
}

Blue-Green with Docker Compose

# Start the green environment
docker-compose -f docker-compose.green.yml up -d

# Check green
curl http://localhost:8081/health

# Switch Nginx to green
sed -i 's/8080/8081/' /etc/nginx/conf.d/app.conf
nginx -s reload

# Stop blue
docker-compose -f docker-compose.blue.yml down
💡 Blue-Green allows an instant rollback: if green fails, switch Nginx back to blue with a single command.

Rolling deployment

Gradual instance replacement: update them one by one without stopping the service.

# Example with Docker Swarm
docker service update   --image myapp:v2   --update-parallelism 1   --update-delay 30s   myapp_service

Comparing deployment strategies

StrategyRollbackResourcesComplexity
Blue-GreenInstant2xMedium
RollingGradual1x + overheadLow
CanaryGradual1xHigh

Checking the new version before switching traffic

Do not rely on a visual look — check the health-check endpoint and a real application flow directly on the new port, before switching the proxy over:

curl -s http://127.0.0.1:8081/health | grep -q '"status":"ok"' && echo "Green is ready"

A healthy endpoint should check not just "the process is running" but real dependencies: the database connection, cache availability, and job queue readiness.

Common errors during the switch

SymptomCause and fix
502 Bad Gateway right after reloadThe new upstream is not yet accepting connections — add a health check before switching Nginx
Some requests still hit the old version after the switchKeep-alive connections to Nginx workers were not dropped — use nginx -s reload, not restart
Database schema errors after deploying the new versionThe database migration is incompatible with the old code version still running in parallel

Rollback after a failed deploy

  1. Do not stop the old version (blue) until the new one has run under real traffic for at least 15-30 minutes.
  2. If problems arise, point the upstream back at the old port — the command is identical to the switch, just in reverse.
  3. Investigate the failure on the green environment separately, without disturbing live traffic.

When this does not fit

Blue-Green requires twice the resources during deployment — for small projects on a tight budget that can be hard to justify. If the application keeps state in process memory (sessions, WebSocket connections) with no external store, that data is lost during the switch — you need a separate scheme with sticky sessions or an external state store.

⚠️ With a blue-green deploy, make sure both environments run against the same database and that the database schema is compatible with both versions of the application.

Checking the result after switching

  • Monitor the 5xx error rate in the logs for a few minutes after the switch — a spike points to a problem.
  • Check that existing open user sessions were not dropped.
  • Make sure background jobs (queues, cron) do not run twice on the old and new version at the same time.

Configuring servers with Ansible ahead of regular deploys is worth automating — see the article Ansible: automating server setup, and a safe full migration rollback is described in migration rollback plan.

Was this article helpful?
← Back to Knowledge Base Ask Support