Kubernetes에서 Flagger 카나리 배포 모니터링하기: Grafana 대시보드 + AlertManager Slack 알림 가이드
새벽 2시, 카나리 배포가 자동 롤백됐다. 팀원 누구도 몰랐다. 오전 9시에 출근해서야 Flagger 이벤트 로그를 뒤지며 롤백 원인을 추적했다 — 그 7시간 동안 트래픽 일부는 잘못된 응답을 반환하고 있었다. Flagger는 카나리 분석 루프를 자동화해 주지만, 그 결과를 팀에 즉시 전달하는 파이프라인이 없으면 반쪽짜리 도구에 불과하다.
이 글은 Flagger → Prometheus → Grafana/AlertManager → Slack으로 이어지는 관측 스택을 직접 연결해, 카나리 분석 실패를 30초 안에 온콜 담당자가 인지하고 대응할 수 있는 구조를 만드는 법을 다룬다. 이미 Flagger를 운영 중인 팀이 타깃이지만, 스택 전체를 처음 구성하는 팀도 따라올 수 있도록 전제 조건부터 명시한다.
전제 조건: Kubernetes 클러스터, Helm 3, Prometheus, Grafana, AlertManager, Flagger, Istio(또는 NGINX/Traefik 인그레스)가 설치되어 있어야 한다. Prometheus + Grafana + AlertManager를 한 번에 설치하려면 kube-prometheus-stack Helm 차트를, Istio는 공식 설치 가이드를 참고한다.
핵심 개념
전체 데이터 흐름 — 먼저 큰 그림부터
Flagger ──(메트릭 기록)──▶ Prometheus
│
┌────────────────┴─────────────────┐
▼ ▼
Grafana AlertManager
(실시간 대시보드) (알림 그루핑·라우팅)
│
▼
Slack (#deployments-alert)
(30초 이내 팀 전체 인지)세부 설정에 들어가기 전에 이 흐름을 머릿속에 고정해야 한다. Grafana는 시각화, AlertManager는 알림 정책이라는 역할이 명확히 분리된다.
Flagger의 카나리 분석 루프
Flagger는 Deployment를 Primary(안정 버전)와 Canary(신규 버전) 두 서비스로 분리한다. 설정된 주기마다 Prometheus 메트릭을 평가해 트래픽 가중치를 단계적으로 올리거나 롤백을 결정한다. Istio의 VirtualService가 이 가중치를 실제 트래픽 분할로 변환한다 — Flagger가 VirtualService의 weight 필드를 주기마다 업데이트하면 Istio 사이드카가 이를 반영해 실제 패킷 라우팅을 바꾸는 구조다.
Primary (90%) ──▶ 실 사용자 트래픽
Canary (10%) ──▶ 점진적으로 증가 (stepWeight: 10)
└▶ 분석 실패 시 0%로 즉시 롤백Flagger가 Prometheus에 노출하는 핵심 메트릭은 두 가지다.
| 메트릭 | 의미 |
|---|---|
flagger_canary_status |
카나리 상태 코드. 0=초기화, 1=진행, 2=성공(승격), 3=실패(롤백) |
flagger_canary_weight |
현재 카나리로 흐르는 트래픽 비율 (%) |
중요:
flagger_canary_status값은 Flagger 버전에 따라 다를 수 있다. 위 값은 공식 소스코드 기준이며, 배포 전kubectl exec로 실제 메트릭 값을 직접 확인하고 Alert Rule을 작성하는 것을 권장한다.
Prometheus가 이 메트릭을 수집하려면 Flagger Pod에 대한 ServiceMonitor CRD가 필요하다. Flagger Helm 차트 설치 시 --set serviceMonitor.enabled=true로 자동 생성하거나, 아래처럼 수동으로 적용한다.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: flagger
namespace: flagger-system
labels:
release: kube-prometheus-stack # Prometheus Operator의 selector에 맞게 조정
spec:
selector:
matchLabels:
app.kubernetes.io/name: flagger
namespaceSelector:
matchNames:
- flagger-system
endpoints:
- port: http
path: /metrics
interval: 15s이
ServiceMonitor가 없으면 Prometheus 타겟 목록에 Flagger가 나타나지 않아flagger_canary_status메트릭 자체를 볼 수 없다. Grafana 대시보드에 데이터가 없다면 가장 먼저 확인해야 할 지점이다.
카나리(Canary) 배포: 신규 버전을 소수의 사용자에게 먼저 노출하고, 오류율·응답시간 같은 메트릭이 기준치 이내일 때만 점진적으로 트래픽을 확대하는 배포 전략. "광산의 카나리아"(위험 감지 조기 경보)에서 유래.
AlertManager: Prometheus 생태계의 알림 라우팅 허브. 같은 알림이 반복 발생할 때 묶어서 보내는 그루핑, 특정 시간대에 알림을 끄는 억제(Silence), 조건에 따라 다른 채널로 보내는 라우팅을 담당한다.
실전 적용
예시 1: Grafana 대시보드로 카나리 현황 시각화
Step 1 — Flagger용 Grafana 설치
helm upgrade -i flagger-grafana flagger/grafana \
--create-namespace \
--namespace=flagger-system \
--set url=http://prometheus:9090Step 2 — 공식 대시보드 임포트 (ID: 15158)
Grafana UI → Dashboards → Import → ID 15158 입력 → Prometheus 데이터소스 선택.
데이터가 없으면: Prometheus 데이터소스 URL이 올바른지(
http://prometheus-operated:9090등 네임스페이스 내 서비스 이름 확인),ServiceMonitor가 적용됐는지 순서대로 확인한다.
Step 3 — 핵심 PromQL 쿼리
# 카나리 현재 상태 (3 = 실패/롤백)
flagger_canary_status{name="my-app", namespace="default"}
# 현재 트래픽 가중치 (%)
flagger_canary_weight{name="my-app", namespace="default"}
# 요청 성공률 (5xx 제외)
sum(rate(http_requests_total{status!~"5.."}[5m]))
/ sum(rate(http_requests_total[5m])) * 100
# 카나리 분석 경과 시간 (초)
flagger_canary_duration_seconds{name="my-app"}예시 2: Prometheus Alert Rule — 롤백 감지
아래 YAML을 PrometheusRule CRD로 적용하거나, Helm values의 additionalPrometheusRulesMap에 추가한다.
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: flagger-alerts
namespace: flagger-system
labels:
release: kube-prometheus-stack # Prometheus Operator selector에 맞게 조정
spec:
groups:
- name: flagger.rules
rules:
- alert: CanaryRollback
expr: flagger_canary_status == 3
for: 0m
labels:
severity: critical
annotations:
summary: "카나리 롤백 발생: {{ $labels.name }}"
description: >
네임스페이스 {{ $labels.namespace }}의
{{ $labels.name }} 카나리 분석 실패로 롤백됨
- alert: CanaryProgressing
expr: flagger_canary_status == 1
for: 1m
labels:
severity: info
annotations:
summary: "카나리 배포 진행 중: {{ $labels.name }}"
- alert: CanaryWeightHigh
expr: flagger_canary_weight > 50
for: 0m
labels:
severity: warning
annotations:
summary: "카나리 트래픽 50% 초과: {{ $labels.name }} ({{ $value }}%)"kubectl apply -f flagger-alerts.yaml으로 적용한다. kube-prometheus-stack을 사용하는 경우 PrometheusRule을 Prometheus Operator가 자동으로 감지한다.
예시 3: AlertManager → Slack 라우팅 (권장 방식)
Slack Incoming Webhook URL 발급: Slack 워크스페이스 → Apps → Incoming WebHooks → Add → 채널 선택 → Webhook URL 복사.
AlertManager 설정을 Kubernetes에 적용하는 방법은 두 가지다.
방법 A — kube-prometheus-stack Helm values로 적용 (권장)
# values.yaml
alertmanager:
config:
global:
resolve_timeout: 5m
route:
group_by: ['alertname', 'namespace']
group_wait: 10s
group_interval: 10m
repeat_interval: 1h
receiver: 'slack-default'
routes:
- match:
alertname: CanaryRollback
severity: critical
receiver: 'slack-canary-rollback'
continue: false
receivers:
- name: 'slack-canary-rollback'
slack_configs:
- api_url: 'https://hooks.slack.com/services/T.../B.../XXXX'
channel: '#deployments-alert'
send_resolved: true
title: ':rotating_light: 카나리 롤백 발생'
text: |
*앱:* {{ .GroupLabels.name }}
*네임스페이스:* {{ .GroupLabels.namespace }}
*상태:* {{ .CommonAnnotations.description }}
color: 'danger'
- name: 'slack-default'
slack_configs:
- api_url: 'https://hooks.slack.com/services/T.../B.../XXXX'
channel: '#deployments'
send_resolved: true
title: '{{ .GroupLabels.alertname }}'
text: '{{ .CommonAnnotations.summary }}'helm upgrade kube-prometheus-stack prometheus-community/kube-prometheus-stack \
--namespace monitoring \
-f values.yaml방법 B — ConfigMap 직접 적용
kubectl create secret generic alertmanager-kube-prometheus-stack-alertmanager \
--from-file=alertmanager.yaml=./alertmanager.yaml \
--namespace monitoring \
--dry-run=client -o yaml | kubectl apply -f -
api_url은 receiver별로 각각 지정하는 것이 보안상 올바른 방식이다.global.slack_api_url은 모든 receiver에 동일한 Webhook URL을 노출하므로 채널별로 다른 Webhook을 쓸 때 관리가 어려워진다.
예시 4: AlertManager 없이 Flagger 직접 Slack 연동 (간단 대안)
이 예시는 예시 3의 대안이다. AlertManager를 운영하지 않는 소규모 팀이나 단순 알림만 필요한 경우에 사용한다. 예시 3과 예시 4를 동시에 설정하면 롤백 한 번에 Slack 메시지가 두 개 오니 둘 중 하나만 선택해야 한다.
Step 1 — AlertProvider CRD 생성
Slack Webhook URL을 Secret으로 저장한 뒤 AlertProvider를 생성한다.
kubectl create secret generic slack-webhook-secret \
--from-literal=address='https://hooks.slack.com/services/T.../B.../XXXX' \
--namespace flagger-systemapiVersion: notification.toolkit.fluxcd.io/v1beta2
kind: Provider
metadata:
name: slack-provider
namespace: flagger-system
spec:
type: slack
channel: deployments
secretRef:
name: slack-webhook-secretStep 2 — Canary CRD에 알림 연결
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: my-app
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: my-app
analysis:
interval: 1m
threshold: 5
maxWeight: 50
stepWeight: 10
metrics:
- name: request-success-rate
thresholdRange:
min: 99
interval: 1m
- name: request-duration
thresholdRange:
max: 500
interval: 30s
alerts:
- name: "rollback-alert"
severity: error
providerRef:
name: slack-provider
namespace: flagger-systemseverity: error로 설정하면 실패 이벤트에만 알림이 발생한다. info로 바꾸면 배포 시작·완료·롤백 모든 이벤트를 받는다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 자동 롤백 | 메트릭 임계값 초과 시 무인 롤백으로 장애 시간 최소화 |
| 점진적 위험 노출 | stepWeight로 소수 사용자에게 먼저 검증 후 확대 |
| 다중 메트릭 공급자 | Prometheus 외 Datadog·CloudWatch를 MetricTemplate CRD로 연동 |
| GitOps 친화적 | Flux/Argo CD와 네이티브 통합 |
| 다채널 알림 | Slack·Teams·Discord·Rocket.Chat 지원 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| Prometheus 의존성 | 분석 루프가 Prometheus 없이 동작 불가 | kube-prometheus-stack Helm 차트로 일괄 설치 |
| 최소 트래픽 요건 | 트래픽이 너무 적으면 신뢰할 수 없는 메트릭 | flagger-loadtester로 분석 기간 내 인공 트래픽 확보 |
| 단기 데이터 보존 | Flagger 전용 Prometheus 기본 보존 기간 2시간 | Thanos·Cortex로 장기 보존 확장 |
| 중복 알림 위험 | 예시 3 + 예시 4 동시 설정 시 알림 2중 발송 | 둘 중 하나만 사용하거나 inhibit_rules로 억제 |
| 서비스 메시 필요 | 트래픽 분할은 Istio·Linkerd 또는 인그레스 필요 | NGINX·Traefik으로 메시 없이도 구성 가능 |
| RBAC 권한 | 클러스터에 따라 ServiceAccount 권한 오류 발생 | Flagger Helm 차트의 rbac.create: true 확인 |
실무에서 가장 흔한 실수
flagger_canary_status값을 확인 없이 Alert Rule 작성 — Flagger 버전에 따라 상태 코드가 다르다. 배포 후kubectl port-forward로 Flagger 메트릭 엔드포인트에 직접 접속해 실제 값을 확인한 뒤 Alert Rule에 적용해야 한다. 잘못된 값으로 작성하면 롤백이 발생해도 알림이 오지 않는다.- 예시 3 + 예시 4 이중 설정 — 롤백 한 번에 Slack 메시지가 두 개 온다.
inhibit_rules로 억제하거나 둘 중 하나만 사용해야 한다. - 트래픽 없는 카나리 분석 통과 — 새벽 배포 시 트래픽이 없으면 성공률 100%로 보여 분석이 통과된다.
flagger-loadtester로 분석 기간 내 인공 트래픽을 확보하거나,webhooks설정으로 부하 테스트를 분석 루프에 연결해야 한다.
마치며
새벽 4시 배포 실패를 온콜 담당자가 30초 안에 Slack으로 받고, Grafana 대시보드에서 트래픽 가중치와 성공률 그래프를 보며 원인을 추적할 수 있을 때 — Flagger 카나리 분석은 비로소 완성된다.
지금 바로 시작할 수 있는 3단계:
helm upgrade -i flagger-grafana flagger/grafana --create-namespace --namespace=flagger-system --set url=http://prometheus:9090으로 Grafana를 설치하고 대시보드 ID15158을 임포트한다. 데이터가 없으면 Prometheus URL과ServiceMonitor적용 여부를 먼저 확인한다.flagger_canary_status == 3조건의CanaryRollbackPrometheusRule을 클러스터에 적용하고,for: 0m으로 설정해 롤백 즉시 알림이 발생하도록 한다. 적용 전 실제 메트릭 값을 직접 확인한다.- AlertManager values에
slack-canary-rollbackreceiver를 추가하고#deployments-alert채널로 라우팅을 연결한 뒤,helm upgrade로 반영한다.
다음 글: Flagger
MetricTemplateCRD로 Datadog·New Relic 등 외부 APM 메트릭을 카나리 분석 기준으로 연동하는 법