Если вы когда-либо с тревогой наблюдали за развёртыванием в продакшн, зная, что одно неверное движение может отправить всех ваших пользователей в пропасть ошибок, вы, вероятно, фантазировали о наличии страховой сетки. Что ж, считайте, что это ваша страховочная сетка, обёрнутая в два цвета и горняцкую метафору.

Развёртывание нового кода в продакшн во многом похоже на проведение хирургической операции: всем предпочтительнее, чтобы пациент оставался в сознании и функционировал во время операции. Плохая новость? Большинство традиционных подходов к развёртыванию больше похожи на использование кувалды. Хорошая новость? Вам не нужен Kubernetes для достижения хирургической точности. Синхронное blue-green развёртывание и поэтапное внедрение изменений (canary releases) — проверенные стратегии, которые прекрасно работают и в средах без Kubernetes.

Давайте разберём эти подходы и построим их с нуля.

Что делает развёртывания такими рискованными?

Прежде чем решать проблему, давайте разберёмся, что мы решаем. Традиционные развёртывания обычно следуют такому шаблону: остановить старую версию, развернуть новую версию, запустить новую версию, задержать дыхание. Если что-то сломается, вы уже в продакшне с неработающим кодом. Ваши пользователи узнают об этом одновременно с вами. Неловко.

Риск при развёртывании умножается с ростом сложности приложения. Миграции баз данных, изменения конфигурации и ошибки в коде — всё это подстерегает в тени нового релиза. Одно развёртывание может привести к множественным сбоям, заставляя вас судорожно искать, что пошло не так и почему.

Синхронное blue-green развёртывание: безопасный переключатель

Синхронное blue-green развёртывание концептуально просто: поддерживайте две идентичные производственные среды и мгновенно переключайте трафик между ними.

Представьте, что у вас есть ресторан с двумя кухнями. Голубая кухня в настоящее время готовит блюда для всех клиентов. Когда вы хотите представить новый рецепт, вы готовите всё на зелёной кухне, пока клиенты продолжают питаться с голубой кухни. Только после того, как зелёная кухня пройдёт все проверки качества, вы переключаете все входящие заказы на неё. Если что-то не так с новым рецептом, вы переключаетесь обратно на голубую в течение нескольких секунд.

Как работает синхронное blue-green развёртывание

Механика проста:

  • Голубая среда: запуск текущего производственного кода, обработка всего живого трафика.
  • Зелёная среда: полная реплика, где вы развёртываете и тестируете новую версию.
  • Балансировщик нагрузки: направляет весь входящий трафик либо на голубую, либо на зелёную среду.
  • Переключение трафика: после проверки вы переключаете балансировщик нагрузки, чтобы отправить весь трафик на зелёную среду.
  • Откат: если возникают проблемы, вы мгновенно переключаетесь обратно на голубую среду.

Магия происходит потому, что обе среды готовы к работе. Вы не постепенно переводите пользователей; вы переключаете переключатель. Это означает отсутствие простоев и возможность мгновенного отката.

Настройка синхронного blue-green развёртывания с традиционной инфраструктурой

Вот практическая реализация с использованием nginx в качестве балансировщика нагрузки и простых серверов:

Ваша инфраструктура:

  • Сервер blue-app-1: 10.0.1.10 (текущая версия)
  • Сервер green-app-1: 10.0.2.10 (новая версия)
  • Балансировщик нагрузки: nginx на 10.0.0.5

Конфигурация nginx (nginx.conf):

upstream blue_backend {
    server 10.0.1.10:8080;
}
upstream green_backend {
    server 10.0.2.10:8080;
}
# Текущий активный бэкенд
upstream active_backend {
    server 10.0.1.10:8080;
}
server {
    listen 80;
    server_name your-app.com;
    location / {
        proxy_pass http://active_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Сценарий развёртывания (deploy.sh):

#!/bin/bash
ENVIRONMENT=$1
VERSION=$2
TARGET_SERVER=$3
if [ "$ENVIRONMENT" != "blue" ] && [ "$ENVIRONMENT" != "green" ]; then
    echo "Ошибка: среда должна быть 'blue' или 'green'"
    exit 1
fi
echo "Развёртывание версии $VERSION в среде $ENVIRONMENT ($TARGET_SERVER)"
# Развёртывание в целевую среду
ssh deploy@$TARGET_SERVER << EOF
    cd /app
    git fetch origin
    git checkout $VERSION
    npm install --production
    npm run build
    systemctl restart app
EOF
echo "Развёртывание завершено. Тестирование проверок работоспособности..."
# Проверка работоспособности
HEALTH_ENDPOINT="http://$TARGET_SERVER:8080/health"
MAX_RETRIES=30
RETRY_COUNT=0
while [ $RETRY_COUNT -lt $MAX_RETRIES ]; do
    HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" $HEALTH_ENDPOINT)
    if [ "$HTTP_CODE" == "200" ]; then
        echo "Проверка работоспособности прошла успешно!"
        exit 0
    fi
    echo "Проверка работоспособности не удалась (HTTP $HTTP_CODE). Повтор..."
    sleep 2
    RETRY_COUNT=$((RETRY_COUNT + 1))
done
echo "Проверки работоспособности не удались. Прерывание развёртывания."
exit 1

Сценарий переключения трафика (switch-traffic.sh):

#!/bin/bash
TARGET_ENV=$1
NGINX_CONF="/etc/nginx/sites-enabled/default"
if [ "$TARGET_ENV" != "blue" ] && [ "$TARGET_ENV" != "green" ]; then
    echo "Ошибка: целевая среда должна быть 'blue' или 'green'"
    exit 1
fi
echo "Переключение трафика на среду $TARGET_ENV..."
if [ "$TARGET_ENV" == "blue" ]; then
    UPSTREAM_SERVER="10.0.1.10:8080"
elif [ "$TARGET_ENV" == "green" ]; then
    UPSTREAM_SERVER="10.0.2.10:8080"
fi
# Обновление конфигурации nginx
sudo sed -i "s/server .*:8080;/server $UPSTREAM_SERVER;/" $NGINX_CONF
# Проверка синтаксиса конфигурации nginx
sudo nginx -t
if [ $? -eq 0 ]; then
    # Перезапуск nginx без разрыва соединений
    sudo nginx -s reload
    echo "Трафик успешно переключён на $TARGET_ENV"
    exit 0
else
    echo "Конфигурация nginx недействительна. Прерывание переключения."
    exit 1
fi

Схема потока развёртывания синхронного blue-green

graph LR User["Пользователи"] LB["Балансировщик нагрузки
nginx"] Blue["Голубая среда
v1.0.0
В данный момент активна"] Green["Зелёная среда
v1.1.0
Готова к тестированию"] User -->|Весь трафик| LB LB -->|Направляет на| Blue LB -->|Будет направлять на| Green style Blue fill:#4a90ff,stroke:#333,color:#fff style Green fill:#7cff4a,stroke:#333,color:#000 style LB fill:#ff9f4a,stroke:#333,color:#fff

Рабочий процесс в реальных условиях

Вот как выглядит полный цикл развёртывания:

  1. Подготовка зелёной среды (в нерабочее время)

    ./deploy.sh green v1.1.0 10.0.2.10
    
  2. Запуск дымовых тестов против зелёной среды

    curl http://10.0.2.10:8080/api/users
    curl http://10.0.2.10:8080/api/posts
    
  3. После уверенности, переключение трафика

    ./switch-traffic.sh green
    
  4. Мониторинг новой среды

    tail -f /var/log/app/production.log
    
  5. Если что-то пойдёт не так, мгновенный откат

    ./switch-traffic.sh blue