Canary-выкатки долго были «экспериментальной практикой», на которую решались единицы: настроить traffic shifting, снять метрики, вручную сравнить и решить — продвигать релиз или откатывать — отдельная работа, которую редко успевали доделать. Flagger снимает эту работу с людей: один CR Canary поверх обычного Deployment, и дальше пайплайн сам ведёт релиз по шагам, сверяясь с метриками, и сам решает — продвигать или откатывать.
Содержание
Открыть содержание
- Проблема: rollout, который никто не проверяет
- Что делает Flagger
- Три стратегии — что выбрать
- Metric analysis: как считается «плохо»
- Traffic shifting без обязательного service mesh
- Webhooks: нагрузочный тест на каждом шаге
- Связка с Flux и GitOps
- Сравнение в одной таблице
- Что нужно, чтобы включить canary с автооткатом
- Как проверить, что откат действительно работает
- Частые грабли
- Итог
Проблема: rollout, который никто не проверяет
Стандартный Kubernetes Deployment со стратегией RollingUpdate умеет одно — постепенно заменять старые поды новыми. Он ничего не знает про error-rate, задержки или бизнес-метрики. Прогресс идёт по расписанию: 25%, 50%, 75%, 100% — и на каждом шаге никто не спрашивает «а всё ли ещё хорошо».
Если в новой версии баг, который проявляется только под нагрузкой, к тому моменту, когда это заметят по алертам или жалобам пользователей, трафик уже весь на новой версии. Откатывать нечего — старых подов не осталось, приходится поднимать предыдущую версию заново, а это минуты простоя вместо секунд.
Что делает Flagger
Flagger — контроллер из экосистемы Flux (CNCF), который берёт на себя ровно то, чего не хватает голому Deployment: постепенный сдвиг трафика и решение о его продолжении на основе метрик. Управляется всё одним custom resource Canary.
Работает это так: вы деплоите новую версию как обычно (обновили image в Deployment), Flagger это замечает и вместо прямой замены создаёт теневой Deployment — canary. Дальше он клонирует поды, постепенно сдвигает на них процент трафика и на каждом шаге прогоняет анализ метрик через MetricTemplate. Если метрики в норме — шаг продвигается дальше. Если нет — Flagger сам делает abort и возвращает 100% трафика на стабильную версию, без участия человека.
Ключевое отличие от ручного canary: решение «продвигать/откатывать» принимает не дежурный по алерту, а контроллер по заранее описанному в git порогу — быстрее и без «героических рук» на пейджере.
Три стратегии — что выбрать
Flagger поддерживает не только canary. Выбор стратегии зависит от того, чем вы готовы рискнуть и что можете измерить:
- Canary — постепенный сдвиг трафика (10% → 30% → 50% → 100%) с анализом на каждом шаге. Стандартный выбор для сервисов с достаточным объёмом трафика, чтобы метрики на 10% были статистически значимы.
- Blue-green — новая версия разворачивается полностью, тестируется на теневом трафике или через отдельный endpoint, и переключение происходит разом. Подходит, когда постепенный трафик-сплит невозможен (например, нет service mesh или ingress с поддержкой weighted routing) или когда даже 10% ошибочного трафика недопустимо.
- A/B (по заголовкам/cookie) — трафик направляется не по проценту, а по правилу: конкретный заголовок, cookie или регион идёт на новую версию. Это не про надёжность, а про эксперимент — нужно, когда важно кому именно показывать новую версию, а не сколько.
Для отката по SLO (тема этой статьи) чаще всего берут canary — он даёт максимум сигнала при минимальном блэст-радиусе на каждом шаге.
Metric analysis: как считается «плохо»
Анализ описывается ресурсом MetricTemplate — по сути, запрос к Prometheus (или Datadog, CloudWatch, New Relic — Flagger абстрагирован от источника) с порогом. Типичный набор для веб-сервиса — error rate (доля 5xx) и p95 latency. Оба считаются только по трафику canary, отдельно от стабильной версии, — иначе шум от старой версии смажет сигнал.
На каждом шаге Flagger ждёт interval (например, 1 минуту), собирает метрику, сравнивает с порогом. Если порог нарушен threshold раз подряд — canary помечается неудачным, и Flagger переходит в abort. Если пройдено maxWeight шагов без нарушений — canary промоутится: Deployment обновляется на новую версию по-настоящему, теневой canary удаляется.
Метрики не обязаны быть чисто инфраструктурными. MetricTemplate — это произвольный PromQL-запрос, поэтому туда же можно положить бизнес-сигнал: долю успешных оплат, конверсию в оформление заказа, задержку конкретного тяжёлого эндпоинта. Технически безупречный canary с деградировавшей конверсией — это тоже повод для отката, и Flagger не делает разницы между «сломался HTTP» и «сломалась воронка», если оба выражены как метрика с порогом.
Traffic shifting без обязательного service mesh
Частое заблуждение — что progressive delivery требует Istio или Linkerd. Flagger умеет сдвигать трафик через:
- Gateway API — современный стандарт, поддерживает weighted routing из коробки, без mesh;
- ingress-nginx — через canary-аннотации, тоже без mesh;
- service mesh (Istio, Linkerd, App Mesh, Open Service Mesh) — для более тонкого контроля (retries, circuit breaking) поверх того же canary-механизма.
Это снижает порог входа: команда без mesh в кластере всё равно получает автоматический откат по метрикам, просто трафик сдвигается на уровне Gateway API или ingress-контроллера, а не sidecar-прокси.
Webhooks: нагрузочный тест на каждом шаге
У Canary есть хуки, которые выполняются на разных стадиях анализа — pre-rollout, rollout, post-rollout. Самый частый пример — webhook load-test, который на каждом шаге canary дёргает нагрузочный прогон (например, hey или k6 в отдельном Job), чтобы на canary вообще была статистика для анализа, а не тишина от 10% органического трафика. Без нагрузки на низком проценте трафика метрики могут быть слишком редкими, чтобы что-то показать.
Связка с Flux и GitOps
Отдельно настраивать ничего не нужно — Canary-манифест такой же YAML в git-репозитории, как и Deployment, MetricTemplate или HelmRelease. Flux применяет его вместе со всем остальным при синхронизации. Откат по метрикам работает поверх обычного GitOps-цикла: пайплайн CI меняет тег образа в git → Flux применяет изменение → Flagger подхватывает новую версию Deployment и запускает canary-анализ. Git остаётся источником истины, а Flagger добавляет runtime-проверку прежде, чем изменение реально долетит до 100% трафика.
Сравнение в одной таблице
Deployment + RollingUpdate | Flagger Canary | |
|---|---|---|
| Сдвиг трафика | по расписанию подов | по шагам (10/30/50…%) |
| Анализ метрик | нет, только алерты постфактум | автоматический, на каждом шаге |
| Решение об откате | человек, вручную | контроллер, по порогу |
| Время до отката | минуты-десятки минут (кто-то заметил) | секунды-минуты (следующий tick анализа) |
| Нужен service mesh | нет | нет (Gateway API/ingress-nginx тоже работают) |
| Источник конфигурации | тот же git, что и остальное | тот же git (CR Canary) |
Что нужно, чтобы включить canary с автооткатом
Минимально нужны: установленный Flagger, Deployment + Service для приложения, MetricTemplate с порогом и сам Canary. Вот рабочий пример с шагами 10/30/50% и анализом по error rate и p95.
Сначала шаблон метрики error-rate из Prometheus:
apiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: error-rate
namespace: prod
spec:
provider:
type: prometheus
address: http://prometheus.monitoring:9090
query: |
100 - sum(
rate(http_requests_total{namespace="prod",kubernetes_pod_name=~"{{ target }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)?",status!~"5.."}[1m])
)
/
sum(
rate(http_requests_total{namespace="prod",kubernetes_pod_name=~"{{ target }}-[0-9a-zA-Z]+(-[0-9a-zA-Z]+)?"}[1m])
) * 100
Дальше сам Canary, который берёт под управление существующий Deployment и Service:
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: web
namespace: prod
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: web
service:
port: 80
targetPort: 8080
analysis:
interval: 1m
threshold: 3 # сколько неудачных проверок подряд до abort
maxWeight: 50 # верхняя граница canary-веса перед промоутом
stepWeight: 10 # шаг сдвига трафика — 10, 30(*), 50%
metrics:
- name: error-rate
templateRef:
name: error-rate
thresholdRange:
max: 1 # не больше 1% ошибок
interval: 1m
- name: request-duration
interval: 1m
thresholdRange:
max: 500 # p95 не больше 500ms
webhooks:
- name: load-test
type: rollout
url: http://flagger-loadtester.prod/
timeout: 15s
metadata:
cmd: "hey -z 1m -q 10 -c 2 http://web-canary.prod:80/"
threshold: 3 значит, что три подряд неудачных проверки (по любой из метрик) переводят canary в Failed, и Flagger откатывает трафик на стабильную версию — без вмешательства человека. stepWeight: 10 при maxWeight: 50 даёт шаги 10 → 20 → 30 → 40 → 50%, после чего при отсутствии нарушений идёт финальный промоут на 100%.
Как проверить, что откат действительно работает
Проверять на проде задним числом не вариант — нужен управляемый негативный тест. Разверните версию, которая специально ломает часть запросов (например, под с шансом отдавать 500 на 20% запросов), и смотрите статус Canary:
kubectl -n prod get canary web -w
Ожидаемая последовательность: Progressing → рост Weight до первого шага → на следующей проверке error-rate превышает max: 1 → статус переходит в Failed → Weight возвращается к 0. Дополнительно можно свериться с событиями:
kubectl -n prod describe canary web
В событиях будет явная запись Rolling back с причиной — какая метрика и на сколько превысила порог. Если такого события не видно, а Weight продолжает расти при явно сломанном canary, — проверьте, что MetricTemplate действительно смотрит на трафик canary (label kubernetes_pod_name с суффиксом -canary, автоматически подставляемым {{ target }}), а не на весь namespace целиком.
Частые грабли
- Порог метрики слишком мягкий. Если
maxдля error-rate выставлен на 5–10%, canary «переживёт» реальную деградацию — порог стоит подбирать по историческому базовому уровню ошибок, а не «на глазок». - Нет нагрузки на canary. При
stepWeight: 10и низком общем трафике на 10% canary может прилетать буквально пара запросов в минуту — метрика будет либо пустой, либо шумной. Без webhookload-testанализ становится бессмысленным. MetricTemplateсчитает по всему namespace. Если в PromQL-запросе не отфильтрован именно canary-под (через подстановку{{ target }}), метрика смешивает трафик стабильной и новой версии, и деградация теряется в общем шуме.maxWeightменьше суммы шагов до 100%. ЕслиstepWeight: 10, аmaxWeight: 50, финальный промоут случится на 50%, а не постепенно дойдёт до 100% — это ожидаемое поведение, но его часто путают с зависшим rollout.
Итог
Автоматический откат по метрикам убирает из процесса релиза самое дорогое — время реакции человека и его готовность быть на связи именно в момент выкатки. Flagger даёт это поверх обычного Deployment, без обязательного service mesh и без отдельной системы конфигурации — тот же Canary-манифест едет из git вместе со всем остальным. Цена входа — один CR и MetricTemplate с разумным порогом; отдача — откат за секунды вместо алерта, разбора и ручного kubectl rollout undo посреди ночи.