Прямой ответ
Стратегия деплоя выбирается по двум параметрам: цена ошибки релиза (сколько стоит плохая версия в проде) и скорость отката (как быстро можно вернуться). Rolling (постепенная замена инстансов) — дефолт для большинства: дёшево по ресурсам, откат — обратный rolling, но старая и новая версии работают одновременно (обратимая совместимость обязательна). Blue-green — две полных среды, переключение трафика мгновенное: откат — секунды (переключить обратно), цена — двойные ресурсы на окно деплоя. Canary — новая версия получает 5% трафика, метрики сравниваются, доля растёт: максимум защиты от «у всех сломалось», максимум сложности (нужны метрики и автоматика). И сквозное правило, важнее выбора стратегии: миграции БД отделяются от кода (expand-contract — старая и новая версии кода работают с одной схемой), иначе ни одна стратегия не спасёт — откат кода упрётся в несовместимую схему.
Rolling: рабочий дефолт
Механика: N инстансов, по одному (или батчами) заменяются на новую версию; каждый новый проходит startup/readiness (health-механика) до продолжения; останавливаемые — graceful shutdown, трафик отведён. В Kubernetes это Deployment из коробки (maxUnavailable/maxSurge задают агрессивность), на «голом» железе — два systemd-инстанса за nginx или скрипт-оркестратор. Требования, которые rolling предъявляет коду: смешанные версии живут одновременно — формат сообщений в очередях, кеш-ключи, API-контракты совместимы в обе стороны (новая читает старое, старая переживает новое); окно смешанности — минуты, но баг «работает только когда все инстансы новые» всплывает именно здесь. Откат — выкатка предыдущей версии тем же rolling'ом (минуты); ускорение отката — хранение предыдущего артефакта готовым к запуску. Rolling — правильная точка старта: проще blue-green, защищает от «сразу всё сломалось» (первый инстанс — канарейка поневоле).
Blue-green: мгновенное переключение
Две идентичные среды: blue (текущая) и green (новая версия, развёрнута и прогрета, но без трафика). Переключение — атомарная смена указателя: DNS (медленно и с оговорками на TTL — плохой вариант), балансировщик/nginx (upstream-файл или переменная — секунды), в облаках — смена target group/слота (App Service slots, ALB). Проверка green до переключения — ключевое преимущество: смоук-тесты гоняются по «холодной» среде реальным кодом, и только зелёный стенд получает пользователей. Откат — обратное переключение (секунды, без пересборки). Ценой: двойные ресурсы (постоянно или на окно деплоя), состояние — только внешнее (сессии/загрузки в общей БД/хранилище, иначе переключение теряет состояние), и «мгновенность» относится к новым запросам — долгоживущие соединения (WebSocket) мигрируют отдельно. Blue-green оправдан там, где цена плохого релиза высока, а откат обязан быть мгновенным: платежи, критичные API, релизы «в пятницу вечером» (шутка, не делайте так).
Canary: постепенность с доказательствами
Канарейка — не «первый инстанс rolling'а», а управляемая стратегия: новая версия получает заданную долю трафика (5% → 25% → 50% → 100%) с автоматическим анализом метрик на каждом шаге (error-rate и p95 новой версии против контрольной — метрики RED здесь становятся системой принятия решений). Механика доли: заголовочная маршрутизация (внутренние тестировщики — 100% новой), взвешенный роутинг на балансировщике/service mesh, в K8s — Ingress-аннотации веса или Argo Rollouts/Flagger (автоматика: шаг, анализ, promote/rollback по метрикам). Требования: метрики с версией в лейбле (сравнимость), достаточный трафик (на 10 запросах в день статистика не работает — для низкотрафиковых сервисов canary вырождается в blue-green с ручным наблюдением), и дисциплина остановки (канарейка «на выходные» — незакрытый риск). Смежный инструмент — feature flags: код задеплоен, но функция выключена/включается для процента пользователей — деплой и релиз разделены во времени (откат флага мгновенен без деплоя); в зрелом виде canary+флаги покрывают почти все сценарии риска.
Миграции БД: невидимая половина деплоя
Любая стратегия ломается, если схема БД меняется одновременно с кодом: откатили код — схема уже новая (или наоборот). Паттерн expand-contract из гайда по Alembic: расширение схемы (nullable-колонки, новые таблицы) до деплоя кода; код работает со смешанной схемой (пишет в оба места/читает новое с фолбэком); сжатие (удаление старого) — отдельным деплоем после стабилизации. Следствие для процессов: миграции накатываются до выкатки кода и обязаны быть обратимыми на окно отката; «одна кнопка деплоит и код, и миграции» допустима только при соблюдении совместимости. Для blue-green это критичнее всего: обе среды смотрят в одну БД — схема обязана устраивать обе версии кода одновременно.
Практический сценарий: выбор для небольшого сервиса
Сервис на двух VM за nginx, 30 RPS, деплои ежедневно. Реалистичная эволюция: старт — rolling вручную (скрипт: вывести инстанс из upstream nginx → обновить → healthcheck → вернуть → второй инстанс; двадцать строк bash из надёжных скриптов с проверками) — уже покрывает 90% пользы «без даунтайма». Через квартал, когда релизы стали нервными (платёжная интеграция) — blue-green на тех же двух VM: второй инстанс поднимается новой версией, смоук-тест по локальному порту, переключение upstream-конфига и reload nginx, откат — обратный reload; ресурсы не удваиваются постоянно, потому что среды чередуются. Canary — следующий шаг при росте трафика и появлении метрик с версией: взвешенный upstream nginx (weight=) или переезд в K8s с Flagger. Итог: стратегия росла вместе с ценой ошибки — от «rolling руками» до автоматики, без premature-инженерии и без даунтаймов на каждом шаге.
FAQ
Можно ли комбинировать стратегии внутри одного продукта? Да, и это норма: базовые сервисы — rolling, платёжное ядро — canary с автоматическим анализом, критичные релизы — blue-green. Стратегия выбирается на сервис, а не на продукт: разные части системы имеют разную цену ошибки, и унификация «всё канареечным» — переплата за ненужную защиту там, где откат rolling'ом достаточен.
Какая стратегия нужна микросервисам? Та же логика на сервис: rolling дефолт, canary для рискованных изменений ядра; плюс контракты между сервисами (обратная совместимость API/событий — микросервисные паттерны) — в распределённой системе «одновременность версий» норма, а не окно деплоя.
Что важнее: стратегия или качество релиза? Качество: тесты, нагрузочные прогоны и ревью ловят большинство проблем до прода; стратегия — страховка от того, что проскочило. Canary без тестов — дорогая система обнаружения собственных багов пользователями.
Как деплоить без downtime на одном инстансе? Технически — blue-green из двух процессов на одной машине (разные порты, переключение nginx) при условии, что ресурсов хватает на оба; честно — один инстанд означает окно недоступности при перезапуске, и стратегия маскирует, но не отменяет single point of failure.
Нужен ли отдельный «флаг отката» в коде? Для опасных изменений — да (kill-switch: поведение возвращается старому пути конфигурацией без деплоя). Для обычной логики — нет: откат версией артефакта проще, а зоопарк флагов со временем сам становится риском (мёртвые ветки, непредсказуемые комбинации).
Источники: Martin Fowler (BlueGreenDeployment, CanaryRelease), документация Kubernetes Deployment — ссылки в шапке.