Если вы когда-либо с тревогой наблюдали за развёртыванием в продакшн, зная, что одно неверное движение может отправить всех ваших пользователей в пропасть ошибок, вы, вероятно, фантазировали о наличии страховой сетки. Что ж, считайте, что это ваша страховочная сетка, обёрнутая в два цвета и горняцкую метафору.
Развёртывание нового кода в продакшн во многом похоже на проведение хирургической операции: всем предпочтительнее, чтобы пациент оставался в сознании и функционировал во время операции. Плохая новость? Большинство традиционных подходов к развёртыванию больше похожи на использование кувалды. Хорошая новость? Вам не нужен 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
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
Рабочий процесс в реальных условиях
Вот как выглядит полный цикл развёртывания:
Подготовка зелёной среды (в нерабочее время)
./deploy.sh green v1.1.0 10.0.2.10Запуск дымовых тестов против зелёной среды
curl http://10.0.2.10:8080/api/users curl http://10.0.2.10:8080/api/postsПосле уверенности, переключение трафика
./switch-traffic.sh greenМониторинг новой среды
tail -f /var/log/app/production.logЕсли что-то пойдёт не так, мгновенный откат
./switch-traffic.sh blue
