16. Blue-green deployment

Blue-Green Deployment — стратегия развёртывания с нулевым даунтаймом. Два идентичных окружения (Blue и Green), трафик переключается между ними мгновенно.
Blue (текущий production) ←── 100% трафикаGreen (новая версия) ←── 0% трафика, тест
Деплой новой версии:├── Деплоим в Green (Blue всё ещё работает!)├── Тестируем Green├── Переключаем трафик: Blue → Green└── Blue становится резервом (быстрый rollback)
После успешного деплоя:Green ←── 100% трафика (новый production)Blue ←── 0% трафика (готов к следующему деплою)Преимущества
Заголовок раздела «Преимущества»✅ Нулевой даунтайм — трафик переключается мгновенно✅ Мгновенный rollback — переключить обратно на Blue✅ Тестирование в production-like окружении✅ Нет смешивания версий — либо старая, либо новаяРеализация с Nginx
Заголовок раздела «Реализация с Nginx»# Blue — версия 1.2.3upstream blue { server 127.0.0.1:3001;}
# Green — версия 1.3.0upstream green { server 127.0.0.1:3002;}
# Активный upstream — переключаем между blue/greenupstream active { server 127.0.0.1:3001; # ← меняем на 3002 при деплое Green}
server { listen 443 ssl; server_name myapp.com;
location / { proxy_pass http://active; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; }}#!/bin/bashNGINX_CONFIG="/etc/nginx/sites-available/myapp.com"
echo "Switching traffic from Blue to Green..."
# Меняем upstream в конфигеsed -i 's|server 127.0.0.1:3001;|server 127.0.0.1:3002;|g' $NGINX_CONFIG
# Проверяем конфигnginx -t || { echo "❌ Nginx config error!"; exit 1; }
# Мягкая перезагрузка (без даунтайма)systemctl reload nginx
echo "✅ Traffic switched to Green (port 3002)"Реализация с Docker
Заголовок раздела «Реализация с Docker»#!/bin/bashCURRENT=$1 # blue или greenNEW_IMAGE=$2
if [ "$CURRENT" = "blue" ]; then DEPLOY_TO="green" DEPLOY_PORT=3002 KEEP_PORT=3001else DEPLOY_TO="blue" DEPLOY_PORT=3001 KEEP_PORT=3002fi
echo "🚀 Deploying to $DEPLOY_TO (port $DEPLOY_PORT)..."
# Запустить новую версиюdocker pull $NEW_IMAGEdocker stop myapp-$DEPLOY_TO 2>/dev/null || truedocker rm myapp-$DEPLOY_TO 2>/dev/null || truedocker run -d \ --name myapp-$DEPLOY_TO \ -p $DEPLOY_PORT:3000 \ --env-file .env.production \ $NEW_IMAGE
# Подождать запускаecho "Waiting for $DEPLOY_TO to be healthy..."for i in {1..30}; do if curl -sf http://localhost:$DEPLOY_PORT/health > /dev/null; then echo "✅ $DEPLOY_TO is healthy!" break fi echo "Attempt $i/30..." sleep 2done
# Проверить что healthyif ! curl -sf http://localhost:$DEPLOY_PORT/health > /dev/null; then echo "❌ $DEPLOY_TO failed health check! Rolling back..." docker stop myapp-$DEPLOY_TO exit 1fi
# Переключить трафикecho "Switching traffic to $DEPLOY_TO..."sed -i "s|server 127.0.0.1:$KEEP_PORT|server 127.0.0.1:$DEPLOY_PORT|g" \ /etc/nginx/sites-available/myapp.comnginx -t && systemctl reload nginx
echo "✅ Blue-Green deploy complete! Active: $DEPLOY_TO"echo "Old version ($CURRENT) on port $KEEP_PORT — kept for rollback"
# Сохранить текущее состояниеecho "$DEPLOY_TO" > /tmp/active-colorGitHub Actions: Blue-Green
Заголовок раздела «GitHub Actions: Blue-Green»name: Blue-Green Deploy
on: push: branches: [main]
jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4
- name: Build and push Docker image run: | docker build -t ghcr.io/myorg/myapp:${{ github.sha }} . docker push ghcr.io/myorg/myapp:${{ github.sha }}
- name: Deploy Blue-Green uses: appleboy/ssh-action@v1 with: host: ${{ secrets.SERVER_HOST }} username: deploy key: ${{ secrets.SSH_PRIVATE_KEY }} script: | CURRENT=$(cat /tmp/active-color 2>/dev/null || echo "blue") NEW_IMAGE=ghcr.io/myorg/myapp:${{ github.sha }}
/home/deploy/scripts/blue-green-deploy.sh $CURRENT $NEW_IMAGE
- name: Verify deployment run: | sleep 10 STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.com/health) if [ "$STATUS" != "200" ]; then echo "❌ Production health check failed!" exit 1 fi echo "✅ Production is healthy"Blue-Green с Vercel (автоматически)
Заголовок раздела «Blue-Green с Vercel (автоматически)»Vercel делает blue-green из коробки:
1. Push в main2. Vercel билдит новую версию3. При успешном билде — мгновенное переключение4. Старая версия доступна через Instant Rollback
Rollback в Vercel:Dashboard → Deployments → выбрать старый → Promote to ProductionCanary Deployment (вариация)
Заголовок раздела «Canary Deployment (вариация)»Постепенное переключение трафика:
# 10% на новую версию (canary)upstream canary_split { server 127.0.0.1:3001 weight=9; # 90% на старую server 127.0.0.1:3002 weight=1; # 10% на новую}
# Через неделю:# weight=5 / weight=5 — 50/50# weight=0 / weight=10 — 100% новаяRollback
Заголовок раздела «Rollback»#!/bin/bashACTIVE=$(cat /tmp/active-color)
if [ "$ACTIVE" = "green" ]; then ROLLBACK_TO="blue" ROLLBACK_PORT=3001 CURRENT_PORT=3002else ROLLBACK_TO="green" ROLLBACK_PORT=3002 CURRENT_PORT=3001fi
echo "🔄 Rolling back to $ROLLBACK_TO..."
# Проверить что rollback target работаетif ! curl -sf http://localhost:$ROLLBACK_PORT/health > /dev/null; then echo "❌ Rollback target is not healthy!" exit 1fi
# Переключить трафик обратноsed -i "s|server 127.0.0.1:$CURRENT_PORT|server 127.0.0.1:$ROLLBACK_PORT|g" \ /etc/nginx/sites-available/myapp.comnginx -t && systemctl reload nginx
echo "$ROLLBACK_TO" > /tmp/active-colorecho "✅ Rolled back to $ROLLBACK_TO"Ключевые моменты
Заголовок раздела «Ключевые моменты»- Blue-Green — два окружения, мгновенное переключение
- Нулевой даунтайм — трафик переключается через Nginx reload
- Rollback = переключить обратно (секунды, не часы)
- Health check перед переключением — обязателен
- Vercel делает blue-green автоматически
- Canary — постепенное переключение (10% → 50% → 100%)
- Старое окружение держи живым после деплоя — на случай rollback
Интерактивный пример
Заголовок раздела «Интерактивный пример»Визуализация переключения Blue-Green: