open atlas
↑ К треку
CI/CD-пайплайны CICD · 04 · 03

Прогрессивная доставка: канарейка, blue-green и флаги

Задеплоить код — не то же, что зарелизить. Раздели их: выкатывай тёмным, открывай постепенно — канарейка 1-5% с авто-откатом по метрикам, blue-green для мгновенного флипа назад, фича-флаг как kill switch без редеплоя. Ограничь радиус поражения, а не ставь на staging.

CICD Senior ◷ 18 min
Уровень
ОсновыJuniorMiddleSenior

Тег нарезан, пайплайн зелёный, артефакт опубликован. Команда сделала всё, чему учили прошлые два урока — чистый SemVer, отревьюенный тег, подписанный релиз — а затем выкатила новую версию на 100% прода одним махом, потому что так деплой-скрипт делал всегда. За пятнадцать секунд error rate ушёл вертикально. Баг сериализации, который срабатывает только при реальных конкурентных записях — невидимый в однопоточном smoke-тесте staging — теперь падал для каждого пользователя. У них не было ни гейта, ни среза, чтобы откатить, только один рычаг, и он уже был опущен до упора. Откат был лихорадочным редеплоем предыдущей версии под крик инцидент-канала: минуты полного простоя, 100% пользователей задеты. Баг не был настоящим провалом. Провалом было выкатить его на всех сразу.

Деплой — это не релиз

Вот рамка, на которой держится весь урок. Деплой — это размещение нового кода на серверах: бинарь работает, контейнер поднят. Релиз — это направление пользовательского трафика к этому коду: решение, кто на самом деле на него попадёт. Прошлые уроки довели тебя до опубликованного артефакта; они не сказали, что хоть один пользователь уже должен его увидеть. Сеньорский ход — считать это двумя отдельными переключателями. Выкатывай код тёмным — задеплоенным, но без трафика — и затем крути ручку трафика вверх постепенно, следя за сигналами, готовый повернуть её обратно в тот момент, когда они деградируют. Всё ниже — это разные механизмы одной идеи: отдели «код здесь» от «пользователи на нём» и навесь ограничитель радиуса поражения на второй переключатель.

Четыре стратегии выката

# big-bang (recreate): останови всё, запусти новую версию — простой + 100% радиуса поражения
strategy:
  type: Recreate          # старые поды умирают, новые стартуют: зазор, где никто не обслуживает

# rolling: заменяй инстансы партиями — без простоя, но две версии работают одновременно
strategy:
  type: RollingUpdate
  rollingUpdate:
    maxSurge: 25%
    maxUnavailable: 0      # почти дефолт k8s: инкрементально, но БЕЗ явного гейта трафика
  • Big-bang (recreate / всё-сразу): останови старую версию, запусти новую. Есть зазор простоя, и в момент, когда она поднялась, радиус поражения — 100%: все пользователи разом на коде, непроверенном в проде. Это провал из Hook. Приемлемо только для крошечных или внутренних приложений, где сбой не страшен.
  • Rolling: заменяй инстансы партия за партией (дефолт Kubernetes). Без простоя — поэтому кажется безопасным — но две версии работают одновременно, так что они обязаны быть обратно/прямо совместимы, а плохая версия всё равно доходит до пользователей инкрементально без явного гейта, следящего, здорова ли она. Rolling управляет доступностью, а не риском.
  • Blue-green: подними два полных окружения. Задеплой в GREEN (простаивающее), прогони smoke-тест в изоляции, затем атомарно переключи балансировщик / роутер с BLUE на GREEN. Переключение мгновенно, и откат тоже мгновенный — переключи роутер обратно на BLUE. Цена — примерно 2x инфраструктуры на время переключения, и трудная часть — общее состояние: обе версии обычно ходят в одну базу, так что изменение схемы должно быть совместимо и с BLUE, и с GREEN через весь флип.
  • Canary (канарейка): направь маленький процент реального трафика (1-5%) на новую версию, следи за её error rate, латентностью и бизнес-метриками против старой, затем поднимай 5 → 25 → 50 → 100%, если остаётся здоровой, или прерывай, если нет. Канарейка ловит проблемы на реальном продовом трафике при крошечном радиусе поражения — ровно тот класс багов, что staging пропустил.
Почему это работает

Зачем разделять деплой и релиз флагами и канарейками, вместо того чтобы просто тестировать жёстче в staging? Потому что staging структурно не может воспроизвести реальный микс трафика, конкуренцию, форму данных и масштаб прода — а именно там живут дорогие баги. Гонки, contention по горячему ключу, сериализатор, который ломается только при одновременных записях, единственный кривой payload, существующий в реальной таблице пользователей — ни один из них не проявится против восьми засеянных строк и одного тестового потока. Прогрессивная доставка принимает это и считает прод финальным тестом, но с привинченным ограничителем: открой изменение тонкому срезу, измерь его против baseline, и если оно плохое — ты сдержал ущерб этим срезом, а не поставил всю свою пользовательскую базу на то, что staging был репрезентативен. Тестировать жёстче — хорошо; просто это заканчивается раньше, чем баги, которые тебя кладут.

Фича-флаги: переключатель релиза, которому не нужен редеплой

Канарейка двигает трафик на уровне инфраструктуры. Фича-флаг переносит решение о релизе на уровень приложения: оберни новое поведение в условие, задеплой с флагом OFF, и код едет тёмным, пока пользователи продолжают получать старый путь. Затем ты переключаешь флаг — для 1% пользователей, потом 10%, потом всех — независимо от любого деплоя. Новый код уже был на каждом сервере; ты просто меняешь значение конфига.

// новый код задеплоен везде, но тёмный, пока флаг его не откроет
if (flags.isEnabled("new-checkout-pipeline", { userId })) {
  return runNewCheckout(order);   // открыт на 1% -> 10% -> 100% через конфиг, без редеплоя
}
return runLegacyCheckout(order);  // все остальные, без изменений

Два свойства делают это любимым инструментом сеньора. Первое — это мгновенный kill switch: если new-checkout-pipeline ведёт себя плохо, ты переключаешь флаг обратно в OFF, и каждый пользователь на старом пути за секунды — без прогона пайплайна, без пересборки образа, без редеплоя. Второе — таргетинг по пользователю / проценту, что и питает A/B-тесты и dark launch (гоняй новый путь, отбрасывай его результат, просто измеряй его нагрузку). Если у тебя есть флаг, который «временно включили» полгода назад — ты уже в колонке затрат. Цена реальна: долг флагов. Каждый флаг — это ветка в коде и строка в конфиге; устаревшие флаги, которые так и не убрали, превращаются в комбинаторный бардак, который никто не смеет удалить. Флаги — это рычаг релиза, а не постоянный дом: открой их, узнай что нужно, потом удали.

Автоматический откат: решает гейт, а не человек

Всё выше просто безопаснее, если человек смотрит. Сеньорская версия — автоматическая. Контроллер прогрессивной доставки — Argo Rollouts, Flagger или логика в твоём деплой-пайплайне — поднимает канарейку по расписанию и на каждом шаге прогоняет аналитический запрос к твоим метрикам: error rate, p99 латентность, скорость прожига SLO. Если запрос пробивает порог, контроллер авто-прерывает и откатывает — сдвигает трафик обратно на стабильную версию — без человека в петле. Вот ключевое число, которое надо усвоить: решение об откате завязано на метрики, а не на ощущения и не на то, что кто-то случайно пялится в дашборд в 16:00.

# Канарейка Argo Rollouts с шагом анализа по метрике (набросок)
strategy:
  canary:
    steps:
      - setWeight: 5            # 5% трафика на новую версию
      - analysis:               # запрос к Prometheus; авто-прерывание при провале
          templates: [{ templateName: error-rate }]
      - setWeight: 25
      - analysis: { templates: [{ templateName: error-rate }] }
      - setWeight: 50
      - setWeight: 100          # полное продвижение только если каждый гейт прошёл

Прогони инцидент из Hook через это. Плохая версия едет на 5% трафика. Баг сериализации срабатывает под реальной конкуренцией, и аналитический запрос видит, как error rate на канарейке скачет за порог за секунды. Контроллер прерывает на 5% и сдвигает трафик обратно на стабильную — автоматически. Радиус поражения: 5% пользователей на несколько секунд вместо 100% пользователей на минуты. Баг всё равно случился; прогрессивная доставка просто сделала его не-событием.

СтратегияПростойРадиус поражения плохой версииОткатЦена / подвох
Big-bangДа (зазор)100% мгновенноРедеплой старой (медленно)Нет гейта; ок лишь для крошечных/внутренних
RollingНетРастёт инкрементально, без гейтаОткати партииДве версии живы; должны быть совместимы
Blue-greenНет100% на флипе (но сначала smoke-тест)Мгновенно: флипни роутер назад2x инфры; общая БД — трудная часть
CanaryНет1-5%, сдержан гейтомАвто-прерывание при пробое метрикиНужны хорошие метрики + автоматизация
Выбери лучший вариант

Тебе нужно выкатить рискованное изменение на высоконагруженный сервис с минимально возможным радиусом поражения и мгновенным откатом. Как ты его выкатишь?

Викторина

В прогрессивной доставке в чём разница между деплоем и релизом и что разделяет фича-флаг?

Викторина

Баг сериализации проявляется только при реальных конкурентных записях; его big-bang деплой на 100% положил весь сайт. Какой выкат сдержал бы его и по какому сигналу?

Вспомните перед уходом
  1. 01
    Объясни рамку «деплой против релиза» и сравни четыре стратегии выката (big-bang, rolling, blue-green, canary) по простою, радиусу поражения и откату.
  2. 02
    Что разделяет фича-флаг и какова его цена, и как автоматический откат по метрикам превращает инцидент из Hook в не-событие?
Итог

Задеплоить код — не то же самое, что зарелизить: деплой кладёт бинарь на серверы, релиз направляет к нему пользовательский трафик, и сеньорский ход — считать их двумя переключателями: выкатывай тёмным, потом открывай постепенно, следя за сигналами, готовый быстро откатить. Четыре стратегии выката торгуют простоем против радиуса поражения: big-bang останавливает старую и запускает новую с зазором простоя и 100% радиуса (ок лишь для крошечных/внутренних приложений); rolling заменяет инстансы партия за партией без простоя, но с двумя совместимыми версиями и без явного гейта, управляя доступностью, а не риском; blue-green поднимает два полных окружения и атомарно флипает роутер с BLUE на GREEN для мгновенного переключения и мгновенного флипа назад, ценой ~2x инфры и трудной проблемы общей базы; canary направляет 1-5% реального трафика на новую версию, следит за error rate / p99 / бизнес-метриками против baseline и поднимает 5/25/50/100%, если здорова, или прерывает, если нет, ловя баги, которые staging не может воспроизвести, при крошечном радиусе поражения. Фича-флаги отделяют релиз от деплоя на уровне приложения — деплой с флагом OFF, потом переключай по пользователю или проценту без редеплоя — давая мгновенный kill switch и таргетинг A/B/dark-launch, ценой долга флагов, который надо чистить. Сеньорская версия автоматическая: контроллер поднимает канарейку и прогоняет аналитический запрос по error rate / p99 / прожигу SLO, авто-прерывая и откатывая на стабильную при пробое метрики без человека в петле — решение завязано на метрики, а не на ощущения. Канарейка на 5% с этим гейтом поймала бы баг сериализации из Hook при 5% радиуса поражения на секунды, вместо того чтобы big-bang на 100% положил весь сайт на минуты. Теперь, когда увидишь деплой-скрипт, выкатывающий сразу на 100%, — будешь знать, какого рычага не хватает и чего стоило бы его иметь.

Практика

Начни сверху. Задачи идут от простого к сложному: вспомнить факт, применить к случаю, затем senior-уровень. Открой, попробуй, потом открой ответ.

вспомнитьприменитьуглубить0 из 5 завершено

Что-то непонятно?

Задай вопрос по этому уроку. Вопросы анонимны и попадают напрямую автору — урок станет лучше.

хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.