откатывать канарейку при превышении burn rate по SLO
Автоматический анализ канареечных релизов и откат по SLO в Kubernetes
14 минут
Запустить канареечный релиз просто; продвинуть или откатить по фактам — нет. Свяжите Flagger или Argo Rollouts с математикой burn rate по SLO, чтобы откат срабатывал при ускоренном расходе бюджета ошибок — а не после ночного просмотра панели.
Почему канареечные релизы ломаются без решений по SLO
Прогрессивная выкатка даёт механизм: часть трафика на новую версию, наблюдение, продвижение или откат. Логики принятия решений обычно нет. Ручной контроль — пятнадцать минут на панели и кнопка «продвинуть» — не масштабируется и добавляет задержку человека. Статические пороги вроде «ошибок больше пяти процентов пять минут» не связаны с целями SLO и часто слишком мягкие: к пяти процентам вы уже могли сжечь заметную долю месячного бюджета ошибок. Канарейка выглядит здоровой сама по себе, а суммарное SLO по всем репликам проседает — потому что никто не сравнивает версии с расходом бюджета. Откат ведут себя по-разному: одни сервисы откатываются сами, другие ждут оператора. Команды либо слепо доверяют канарейке, либо навешивают столько ручных ворот, что процесс не быстрее blue-green.
Burn rate по SLO как ворота продвижения
SLO — источник истины для promote и rollback, а не проценты «на глаз». Опишите SLI в Git через Sloth или аналог, измеряйте burn rate бюджета ошибок в окне канарейки и пусть Flagger или Argo Rollouts наращивают вес только пока burn в пределах политики. При превышении многократного порога, выведенного из цели SLO, контроллер возвращает трафик на stable автоматически. CI пушит теги образов; контроллер канарейки проверяет здоровье. GitOps применяет желаемое состояние, но анализ не даёт плохой версии получить весь трафик. Цепочка: сборка и push, канарейка на десяти процентах, Prometheus оценивает burn rate каждые тридцать секунд, вес растёт при успехе или откат при серии провалов.
Определение SLO в коде через Sloth
Храните PrometheusServiceLevel рядом с манифестами сервиса: цели, запросы и имена алертов под версионным контролем. SLO доступности 99,9% даёт бюджет ошибок 0,1%. Burn rate — текущая доля ошибок, делённая на допустимую; 14,4× за час исчерпывает месячный бюджет примерно за час, 72× за пять минут ловит быстрые регрессии. Sloth генерирует recording rules и многократные burn-rate алерты, которые можно переиспользовать в шаблонах анализа канарейки.
apiVersion: sloth.slok.dev/v1
kind: PrometheusServiceLevel
metadata:
name: my-service-slo
namespace: production
spec:
service: "my-service"
labels:
team: "platform"
slos:
- name: "availability"
objective: 99.9
description: "99.9% of requests succeed"
sli:
events:
errorQuery: |
sum(rate(http_requests_total{
namespace="production",
service="my-service",
code=~"5.."
}[5m]))
totalQuery: |
sum(rate(http_requests_total{
namespace="production",
service="my-service"
}[5m]))
alerting:
name: "MyServiceHighErrorBudgetBurn"
labels:
severity: "critical"
annotations:
summary: "High error budget burn rate"
pageAlert:
labels:
severity: "page"Анализ канарейки в Flagger с метрикой burn rate
Flagger наращивает вес канарейки по расписанию и опрашивает Prometheus через MetricTemplate. PromQL должен возвращать числовой burn rate, а порог задавайте в thresholdRange у метрики Canary — не сравнение «больше 14,4» внутри запроса. Размечайте метрики так, чтобы трафик канарейки и stable различались: метка version, subset mesh или метка пода от ingress. Без разделения burn rate смешивает версии и скрывает регрессию на доле канарейки.
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: my-service
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-service
service:
port: 8080
progressDeadlineSeconds: 600
analysis:
interval: 30s
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 30s
- name: slo-burn-rate
templateRef:
name: slo-budget-burn
thresholdRange:
max: 14.4
interval: 30s
revertOnFailure: trueapiVersion: flagger.app/v1beta1
kind: MetricTemplate
metadata:
name: slo-budget-burn
namespace: production
spec:
provider:
type: prometheus
address: http://prometheus.monitoring:9090
query: |
(
sum(rate(http_requests_total{
namespace="production",
service="{{ target }}",
version="canary",
code=~"5.."
}[5m]))
/
sum(rate(http_requests_total{
namespace="production",
service="{{ target }}",
version="canary"
}[5m]))
)
/
(1 - 0.999)Альтернатива: AnalysisTemplate в Argo Rollouts
Argo Rollouts запускает AnalysisRun по метрикам AnalysisTemplate между шагами канарейки. Тот же PromQL для burn rate, successCondition сравнивает result с порогом окна — 14,4 для политики на час, выше для коротких окон. Сочетайте с маршрутизацией Istio, NGINX или ALB, чтобы stable и canary Service получали взвешенный трафик. Статусы Rollout и AnalysisRun фиксируют каждый pass или fail для разбора после инцидента.
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: my-service
namespace: production
spec:
replicas: 3
strategy:
canary:
canaryService: my-service-canary
stableService: my-service-stable
trafficRouting:
istio:
virtualService:
name: my-service-vsvc
routes:
- primary
analysis:
templates:
- templateName: slo-check
startingStep: 2
args:
- name: service-name
value: my-service
---
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: slo-check
spec:
args:
- name: service-name
metrics:
- name: slo-budget-burn-rate
interval: 30s
count: 5
successCondition: result[0] < 14.4
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring:9090
query: |
(
sum(rate(http_requests_total{
namespace="production",
service="{{args.service-name}}",
code=~"5.."
}[5m]))
/
sum(rate(http_requests_total{
namespace="production",
service="{{args.service-name}}"
}[5m]))
)
/
(1 - 0.999)Полный цикл: выкатка, откат и алертинг
Запускайте релиз обновлением образа Deployment; Flagger или Rollouts начинают анализ с десяти процентов трафика. Каждый интервал — ошибки и burn rate; три провала подряд откатывают на stable. Алертируйте в Prometheus на повышенный burn в окне канарейки, чтобы дежурный видел причину автоотката — тихие откаты маскируют повторяющиеся проблемы сборки. Логируйте снимки метрик и время решения при каждом promote или abort.
kubectl set image deployment/my-service \
my-service=my-registry/my-service:v2.1.0 \
-n production
# Flagger или Rollouts: 90% stable / 10% canary, метрики каждые 30s(
sum(rate(http_requests_total{
namespace="production",
service="my-service",
code=~"5.."
}[5m]))
/
sum(rate(http_requests_total{
namespace="production",
service="my-service"
}[5m]))
)
/
(1 - 0.999)groups:
- name: canary-analysis
rules:
- alert: CanaryHighBudgetBurn
expr: |
(
sum(rate(http_requests_total{
namespace="production",
service="my-service",
version="canary",
code=~"5.."
}[5m]))
/
sum(rate(http_requests_total{
namespace="production",
service="my-service",
version="canary"
}[5m]))
) / (1 - 0.999) > 14.4
for: 2m
labels:
severity: warning
canary: "true"
annotations:
summary: "Burn rate канарейки превышает политику SLO на 1 ч; возможен откат"Практика: пороги, разделение ролей, учения и связь с инцидентами
Выводите каждый порог из цели SLO и окна оценки — зафиксируйте арифметику в README репозитория. Разделяйте триггеры деплоя в CI и проверку в Flagger или Rollouts: один инструмент выкатывает артефакты, другой держит ворота трафика. Начинайте строго — ложный откат безопаснее продвижения с регрессией. Используйте burn rate в нескольких окнах: пять минут при 72× и час при 14,4× отсекают всплески, но ловят устойчивую деградацию. Раз в квартал проверяйте откат намеренно плохой сборкой или хаос-экспериментом; неотработанный путь ломается в бою. При автооткате создавайте тикет или зовите дежурного — повторяющиеся тихие abort часто означают кривые тесты или метки. Держите серии canary и stable раздельными в Prometheus, согласуйте ворота с правилами продвижения в GitOps и относитесь к панелям SLO как к политике релиза, а не к экрану, который никто не смотрит в час выкатки.
Деление трафика и feature flags — база; эта статья добавляет пороги SLO поверх прогрессивной выкатки с canary и feature flags в Kubernetes.
Пороги burn rate имеют смысл только после определения SLI и бюджета ошибок — см. гайд по SLO, SLI и error budget для платформенных команд.
