Перейти к содержимому
Hogin Hogin
Назад

Progressive delivery: canary с автоматическим откатом на Flagger

9 мин чтения

Canary-выкатки долго были «экспериментальной практикой», на которую решались единицы: настроить traffic shifting, снять метрики, вручную сравнить и решить — продвигать релиз или откатывать — отдельная работа, которую редко успевали доделать. Flagger снимает эту работу с людей: один CR Canary поверх обычного Deployment, и дальше пайплайн сам ведёт релиз по шагам, сверяясь с метриками, и сам решает — продвигать или откатывать.

Содержание

Открыть содержание

Проблема: rollout, который никто не проверяет

Стандартный Kubernetes Deployment со стратегией RollingUpdate умеет одно — постепенно заменять старые поды новыми. Он ничего не знает про error-rate, задержки или бизнес-метрики. Прогресс идёт по расписанию: 25%, 50%, 75%, 100% — и на каждом шаге никто не спрашивает «а всё ли ещё хорошо».

Если в новой версии баг, который проявляется только под нагрузкой, к тому моменту, когда это заметят по алертам или жалобам пользователей, трафик уже весь на новой версии. Откатывать нечего — старых подов не осталось, приходится поднимать предыдущую версию заново, а это минуты простоя вместо секунд.

Обычный rollout без анализа метрик: ошибка видна только после 100%

Что делает Flagger

Flagger — контроллер из экосистемы Flux (CNCF), который берёт на себя ровно то, чего не хватает голому Deployment: постепенный сдвиг трафика и решение о его продолжении на основе метрик. Управляется всё одним custom resource Canary.

Работает это так: вы деплоите новую версию как обычно (обновили image в Deployment), Flagger это замечает и вместо прямой замены создаёт теневой Deployment — canary. Дальше он клонирует поды, постепенно сдвигает на них процент трафика и на каждом шаге прогоняет анализ метрик через MetricTemplate. Если метрики в норме — шаг продвигается дальше. Если нет — Flagger сам делает abort и возвращает 100% трафика на стабильную версию, без участия человека.

Canary у Flagger: шаг → анализ → промоут или откат

Ключевое отличие от ручного canary: решение «продвигать/откатывать» принимает не дежурный по алерту, а контроллер по заранее описанному в git порогу — быстрее и без «героических рук» на пейджере.

Три стратегии — что выбрать

Flagger поддерживает не только canary. Выбор стратегии зависит от того, чем вы готовы рискнуть и что можете измерить:

Для отката по 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 умеет сдвигать трафик через:

Это снижает порог входа: команда без 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 + RollingUpdateFlagger 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 → статус переходит в FailedWeight возвращается к 0. Дополнительно можно свериться с событиями:

kubectl -n prod describe canary web

В событиях будет явная запись Rolling back с причиной — какая метрика и на сколько превысила порог. Если такого события не видно, а Weight продолжает расти при явно сломанном canary, — проверьте, что MetricTemplate действительно смотрит на трафик canary (label kubernetes_pod_name с суффиксом -canary, автоматически подставляемым {{ target }}), а не на весь namespace целиком.

Частые грабли

Итог

Автоматический откат по метрикам убирает из процесса релиза самое дорогое — время реакции человека и его готовность быть на связи именно в момент выкатки. Flagger даёт это поверх обычного Deployment, без обязательного service mesh и без отдельной системы конфигурации — тот же Canary-манифест едет из git вместе со всем остальным. Цена входа — один CR и MetricTemplate с разумным порогом; отдача — откат за секунды вместо алерта, разбора и ручного kubectl rollout undo посреди ночи.


Поделиться:

Следующая статья
Kyverno vs OPA Gatekeeper: когда брать что