«Релиз в пятницу» — фраза, после которой опытный девопс начинает нервно искать билет на Бали. Но если ваш процесс деплоя устроен правильно, релиз в любой день недели — это рутина, а не риск. Разбираем стратегии деплоя, которые делают релиз безопасным.
Зачем что-то менять
Простой деплой:
- Останавливаем старую версию.
- Поднимаем новую.
- Если новая сломана — откатываемся, теряем время и пользователей.
Между шагами 1 и 2 — даунтайм. На шаге 3 — паника. Хотим: ноль даунтайма, мгновенный откат, проверка на части трафика перед полным переключением.
Стратегии
| Стратегия | Даунтайм | Откат | Сложность | Когда |
|---|---|---|---|---|
| Recreate (обычный) | да | долгий | минимум | dev, staging |
| Rolling | минимальный | средний | низкая | стандарт K8s |
| Blue-Green | нет | мгновенный | средняя | критичные сервисы |
| Canary | нет | мгновенный | высокая | большие проекты |
| A/B (на трафике) | нет | мгновенный | очень высокая | продуктовые гипотезы |
Rolling deploy
Стандарт Kubernetes. Поды старой версии заменяются по одному.
spec:
replicas: 4
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # сколько новых сверх лимита
maxUnavailable: 0 # сколько одновременно недоступно
В каждый момент: 4 рабочих пода, постепенно меняются. Если новый под не проходит readiness probe — выкатка останавливается.
Минус: во время деплоя в проде одновременно работают и старая, и новая версии. Для несовместимых API/схем БД — проблема.
Blue-Green
Две идентичные среды. Blue — текущая в проде. Green — новая версия. Балансировщик переключает 100% трафика мгновенно.
Пользователи → LoadBalancer → Blue (v1.42) ← активный
Green (v1.43) ← новый, прогревается
После прогрева и smoke-тестов — переключаем балансер: всё на Green. Blue остаётся работать ещё час (на случай отката).
Откат — два клика, обратно на Blue.
upstream backend {
server blue:3000; # активный
# server green:3000; # закомментирован
}
Reload nginx → переключение мгновенное. Без сброса соединений (graceful reload).
Минусы:
- Ресурсов нужно в 2 раза больше (две среды).
- Долгие соединения (WebSocket) обрываются при переключении.
- Миграции БД сложнее: новая версия может ожидать новой схемы.
Canary
Постепенный rollout: 1% → 10% → 50% → 100%. Если на 1% видим проблему (рост ошибок, латенция, бизнес-метрики) — откатываемся, основной массе ничего не показано.
LoadBalancer:
- 99% → v1.42 (стабильная)
- 1% → v1.43 (canary)
Через 30 минут наблюдения за метриками — увеличиваем процент. Цикл может длиться часы или дни.
В Kubernetes — через Argo Rollouts или Flagger:
apiVersion: argoproj.io/v1alpha1
kind: Rollout
spec:
strategy:
canary:
steps:
- setWeight: 5
- pause: { duration: 5m }
- setWeight: 25
- pause: { duration: 10m }
- setWeight: 50
- pause: { duration: 30m }
- setWeight: 100
analysis:
templates:
- templateName: success-rate
args:
- name: service-name
value: my-app
Если success-rate < 99% на каком-то шаге — автоматический rollback.
Без Kubernetes
На VPS с Docker Compose тоже можно делать blue-green, через два compose-проекта и переключение nginx upstream.
# скрипт deploy.sh
docker compose -p site-green pull
docker compose -p site-green up -d
sleep 10
curl -f http://green:3000/health || exit 1
# переключаем nginx
sed -i 's/blue:3000/green:3000/' /etc/nginx/conf.d/site.conf
nginx -s reload
# даём 5 минут на observation
sleep 300
docker compose -p site-blue down
Не идеально, но работает на маленьких проектах без K8s-головной боли.
Миграции БД
Главная сложность blue-green / canary: схема БД одна, версий приложения две.
Правило expand-migrate-contract:
- Expand: добавить новую колонку как nullable, новый код может с ней работать, старый игнорирует.
- Migrate: задеплоить новый код, который пишет в обе колонки.
- Contract: после полного перехода на новую — удалить старую колонку.
Это растягивает фичу на 3 деплоя, но избавляет от downtime.
Health checks и readiness
Без них любая стратегия превращается в обычный recreate. Балансировщик должен знать, готов ли под принимать трафик:
readinessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 5
periodSeconds: 5
livenessProbe:
httpGet:
path: /health
port: 3000
initialDelaySeconds: 30
periodSeconds: 10
/health должен реально проверять — не просто return 200, а пинг к БД, Redis, очереди. Лучше отдельные /ready (можно принимать трафик) и /live (приложение живо вообще).
Метрики для решения
Что смотреть во время canary:
- HTTP 5xx rate (если выше базового — стоп).
- Latency p95/p99 (если выросла — стоп).
- Бизнес-метрика: конверсия checkout, успешность регистрации, добавления в корзину.
- Логи ошибок (Sentry — алерт на новую ошибку в release X).
Автоматизация: Flagger/Argo сами читают Prometheus и решают. Без них — оператор смотрит дашборд и вручную нажимает «promote» или «rollback».
Откат — самое важное
Стратегия имеет смысл только если откат реально работает. Что нужно:
- Образ предыдущей версии всегда доступен (не удалён из registry).
- Конфиг и переменные окружения версионированы (не редактируются вручную).
- Скрипт
./rollback.shотлажен и регулярно тестируется. - Команда знает, кто и когда инициирует откат, нет долгих обсуждений.
- Миграции БД совместимы назад минимум на 1-2 версии.
«Откатимся» без дисциплины миграций — гарантированный downtime, потому что новая версия сделала ALTER TABLE, которого старая не понимает.
Когда какую стратегию
| Размер проекта | Рекомендация |
|---|---|
| MVP, 1 сервер | Recreate с быстрой пересборкой образа |
| Малый прод, 1-2 пользователя в секунду | Rolling в Docker Compose |
| Средний прод, важно не падать | Blue-Green |
| Большой прод, много фич/неделю | Canary с автоматическим rollback |
| Финтех, медицина, госсектор | Canary + extensive smoke + manual approve |
Итого
Сложность стратегии должна соответствовать рискам. Не стройте Argo Rollouts на трёх пользователях — оверинжиниринг. Но и не запускайте recreate без даунтайма для приложения с 5к посещений в час — потеряете деньги. Blue-Green — отличный middle ground, доступен почти всем.
Частые вопросы
Можно ли делать blue-green на одном VPS?
Можно, два набора контейнеров на разных портах + nginx переключает. Памяти нужно в 2 раза больше (на время деплоя), CPU — почти столько же. На 4 ГБ RAM поднимется только маленькое приложение в двух копиях, для нормального — 8-16 ГБ. Альтернатива — арендовать второй VPS только на время деплоя.
Canary на маленьком проекте — оверкилл?
Да. Canary имеет смысл от ~10 деплоев в неделю и заметного трафика (тысячи RPS), где вы статистически быстро увидите ухудшение метрик на 1% трафика. Для проекта с 1 деплоем в неделю и 10 RPS на canary метрики не отличить от шума. Хватит blue-green с smoke-тестами.
Как делать rollback миграций БД?
Никак не делать «обратные миграции» автоматически — они почти всегда теряют данные. Правило: миграции совместимы назад. Если новая колонка nullable — старый код её игнорирует, можно откатываться. Если переименовали поле — сначала expand (новое поле, оба заполняются), потом deploy, потом contract — даже если откатились между шагами, всё работает.
Что делать с долгими WebSocket-соединениями при blue-green?
Drainage: новые соединения идут на green, старые остаются на blue до закрытия. Через 5-15 минут (или по достижении ~0 активных) гасим blue. Если простой висит часами (стрим, чат) — отправьте клиенту команду reconnect, тогда он переподключится на актуальную версию. WS-серверы (LiveKit, Socket.IO) обычно поддерживают graceful drain.
Argo Rollouts или Flagger?
Argo Rollouts — более гибкая декларативная модель, лучше интегрируется с Argo CD. Flagger — проще, тесная интеграция с Istio/Linkerd/NGINX. Если уже на Argo CD — Argo Rollouts. Если service mesh — Flagger. Для не-K8s — обе не подходят, смотрите Spinnaker или самописные скрипты.
Какой минимум health-check должен быть?
/health — приложение запущено и принимает HTTP. Этого мало. Лучше /ready — может ли реально обслуживать (есть коннект к БД, инициализированы кеши, доступны критичные внешние API). Правило: если probe вернул 200, но первый же запрос даёт 500 — это сломанный probe, переписывайте.
Сколько времени занимает blue-green деплой?
На небольшом приложении (Node.js + Postgres) — 30-60 секунд от push до переключения трафика, плюс 5-15 минут наблюдения за метриками green-окружения перед декомиссионированием blue. На больших образах (200-500 МБ) — pull занимает дольше, плюс прогрев JIT и кешей. Цельтесь в полный цикл деплоя «push → fully promoted» 10-30 минут.