- Published on
Prometheus·Alertmanager 알림 파이프라인 구축: 규칙 작성부터 PagerDuty·Slack 라우팅까지
- Authors
- Name
- 들어가며
- Prometheus 알림 규칙 작성
- 알림 규칙 테스트
- Alertmanager 설정 심화
- PagerDuty와 Slack 통합
- Grafana Alerting과의 비교
- Alert Fatigue 방지 전략
- 실패 사례와 복구 절차
- 운영 시 주의사항
- 참고자료

들어가며
모니터링 시스템을 구축하고 대시보드를 만들었다고 해서 관찰 가능성이 완성되는 것이 아니다. 대시보드는 사람이 능동적으로 확인해야 하지만, 알림은 시스템이 이상 상태를 감지했을 때 적절한 사람에게 적시에 통보한다. 진정한 관찰 가능성은 메트릭 수집에서 시작하여 알림 파이프라인으로 완성된다.
Google SRE 출신 Rob Ewaschuk는 "My Philosophy on Alerting"에서 두 가지 핵심 원칙을 제시한다. 첫째, 원인(Cause)이 아닌 증상(Symptom)에 알림을 걸어라. 디스크 사용률 80% 같은 원인 기반 알림보다 "사용자 요청의 에러율이 1%를 초과한다" 같은 증상 기반 알림이 실제 사용자 영향을 더 정확히 반영한다. 둘째, 모든 알림은 즉각적인 행동을 유발해야 한다. 알림을 받고도 "나중에 보면 되겠지"라면 그 알림은 존재할 이유가 없다.
이 글에서는 Prometheus 알림 규칙(Alerting Rules) 작성, Alertmanager 라우팅 트리 설계, PagerDuty와 Slack 통합, Alert Fatigue 방지 전략까지 프로덕션 알림 파이프라인 구축의 전 과정을 다룬다.
Prometheus 알림 규칙 작성
alerting rules 구조
Prometheus 알림 규칙은 다섯 가지 핵심 필드로 구성된다.
- alert: 알림의 고유 이름
- expr: PromQL 표현식. 결과가 빈 벡터가 아니면 알림이 발생한다
- for: pending 상태를 유지하는 대기 시간. 일시적 스파이크를 필터링한다
- labels: 알림에 추가되는 레이블. severity, team 등 라우팅에 사용된다
- annotations: 알림 설명, Runbook URL 등 사람을 위한 메타데이터
pending vs firing 상태 전환
알림은 세 가지 상태를 순환한다. inactive는 조건이 충족되지 않는 기본 상태다. expr 조건이 처음 충족되면 pending 상태로 진입하고, for에 지정한 시간 동안 지속적으로 조건이 충족되면 firing 상태로 전환되어 Alertmanager로 전송된다. for 기간 중간에 조건이 해소되면 다시 inactive로 돌아간다.
keep_firing_for 활용
Prometheus 2.42부터 도입된 keep_firing_for 필드는 간헐적 메트릭(intermittent metric)에 유용하다. 예를 들어 배치 작업의 메트릭이 작업 완료 후 사라지면 알림도 즉시 해소되는데, keep_firing_for를 설정하면 메트릭이 사라진 이후에도 지정한 시간 동안 firing 상태를 유지하여 온콜 엔지니어가 확인할 시간을 확보한다.
기본 인프라 알림 규칙
CPU, Memory, Disk에 대한 기본 알림 규칙이다. 증상 기반 알림이 우선이지만, 인프라 자원 고갈은 여전히 모니터링해야 하는 핵심 원인 지표다.
groups:
- name: infrastructure-alerts
interval: 30s
rules:
# CPU 사용률이 5분간 80% 이상 지속
- alert: HighCpuUsage
expr: |
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 5m
labels:
severity: warning
team: infra
annotations:
summary: 'CPU 사용률 높음'
description: '인스턴스 {{ $labels.instance }}의 CPU 사용률이 {{ $value | printf "%.1f" }}%입니다.'
runbook_url: 'https://wiki.internal/runbook/high-cpu'
# 메모리 사용률 90% 초과
- alert: HighMemoryUsage
expr: |
(1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) * 100 > 90
for: 5m
labels:
severity: warning
team: infra
annotations:
summary: '메모리 사용률 높음'
description: '인스턴스 {{ $labels.instance }}의 메모리 사용률이 {{ $value | printf "%.1f" }}%입니다.'
# 디스크 24시간 내 고갈 예측
- alert: DiskWillFillIn24Hours
expr: |
predict_linear(node_filesystem_avail_bytes{fstype!~"tmpfs|overlay"}[6h], 24*3600) < 0
for: 10m
labels:
severity: critical
team: infra
annotations:
summary: '디스크 24시간 내 고갈 예측'
description: '인스턴스 {{ $labels.instance }}의 마운트포인트 {{ $labels.mountpoint }}가 24시간 내 고갈될 것으로 예측됩니다.'
runbook_url: 'https://wiki.internal/runbook/disk-full'
SLO 기반 burn rate 알림 규칙
Google SRE Workbook에서 제안하는 Multi-Window Multi-Burn-Rate 알림 방식이다. 에러 버짓 소진 속도(burn rate)를 기준으로 빠른 소진과 느린 소진을 각각 감지하여 대응 긴급도를 차별화한다.
groups:
- name: slo-burn-rate-alerts
rules:
# 에러율 Recording Rule (사전 계산)
- record: slo:http_error_rate:ratio_rate5m
expr: |
sum(rate(http_requests_total{status=~"5.."}[5m])) by (service)
/
sum(rate(http_requests_total[5m])) by (service)
- record: slo:http_error_rate:ratio_rate30m
expr: |
sum(rate(http_requests_total{status=~"5.."}[30m])) by (service)
/
sum(rate(http_requests_total[30m])) by (service)
- record: slo:http_error_rate:ratio_rate1h
expr: |
sum(rate(http_requests_total{status=~"5.."}[1h])) by (service)
/
sum(rate(http_requests_total[1h])) by (service)
- record: slo:http_error_rate:ratio_rate6h
expr: |
sum(rate(http_requests_total{status=~"5.."}[6h])) by (service)
/
sum(rate(http_requests_total[6h])) by (service)
# SLO 99.9% (에러 버짓 0.1%)
# 빠른 소진: 5m/30m 윈도우, burn rate 14.4x → 1시간 내 버짓 소진 속도
- alert: SloHighBurnRate
expr: |
slo:http_error_rate:ratio_rate5m{service="api-gateway"} > (14.4 * 0.001)
and
slo:http_error_rate:ratio_rate30m{service="api-gateway"} > (14.4 * 0.001)
for: 2m
labels:
severity: critical
slo: 'availability'
window: 'fast'
annotations:
summary: 'SLO 빠른 소진 감지 - 즉시 대응 필요'
description: 'api-gateway의 에러 버짓이 1시간 내 소진될 속도로 감소 중입니다.'
# 느린 소진: 1h/6h 윈도우, burn rate 6x → 4시간 내 버짓 소진 속도
- alert: SloMediumBurnRate
expr: |
slo:http_error_rate:ratio_rate1h{service="api-gateway"} > (6 * 0.001)
and
slo:http_error_rate:ratio_rate6h{service="api-gateway"} > (6 * 0.001)
for: 5m
labels:
severity: warning
slo: 'availability'
window: 'slow'
annotations:
summary: 'SLO 느린 소진 감지 - 조사 필요'
description: 'api-gateway의 에러 버짓이 4시간 내 소진될 속도로 감소 중입니다.'
위 규칙에서 핵심은 두 개의 윈도우를 AND 조건으로 결합하는 것이다. 짧은 윈도우(5m)만 보면 일시적 스파이크에 반응하고, 긴 윈도우(30m)만 보면 감지가 느려진다. 두 윈도우가 동시에 조건을 충족할 때만 발화하여 정확도를 높인다.
알림 규칙 테스트
promtool을 활용한 단위 테스트
알림 규칙을 프로덕션에 배포하기 전에 반드시 테스트해야 한다. promtool은 가상의 시계열 데이터를 입력하고 특정 시점에서 알림이 기대한 대로 발화하는지 검증한다.
# alert_test.yaml
rule_files:
- infrastructure_alerts.yaml
evaluation_interval: 1m
tests:
# 테스트 1: CPU 80% 이상 5분 지속 시 firing
- interval: 1m
input_series:
- series: 'node_cpu_seconds_total{mode="idle",instance="node1:9100",cpu="0"}'
values: '0+0.15x20' # 매분 0.15초 idle = 85% 사용률
- series: 'node_cpu_seconds_total{mode="idle",instance="node1:9100",cpu="1"}'
values: '0+0.15x20'
alert_rule_test:
# 4분 시점: pending 상태여야 함 (for: 5m 미충족)
- eval_time: 4m
alertname: HighCpuUsage
exp_alerts: []
# 6분 시점: firing 상태여야 함
- eval_time: 6m
alertname: HighCpuUsage
exp_alerts:
- exp_labels:
severity: warning
team: infra
instance: 'node1:9100'
exp_annotations:
summary: 'CPU 사용률 높음'
# 테스트 2: 메모리 90% 미만이면 알림 없음
- interval: 1m
input_series:
- series: 'node_memory_MemAvailable_bytes{instance="node1:9100"}'
values: '2147483648x10' # 2GB available
- series: 'node_memory_MemTotal_bytes{instance="node1:9100"}'
values: '8589934592x10' # 8GB total = 75% 사용
alert_rule_test:
- eval_time: 10m
alertname: HighMemoryUsage
exp_alerts: []
CI/CD에서 알림 규칙 검증 자동화
알림 규칙 파일을 Git으로 관리하고 CI 파이프라인에서 자동 검증한다. 문법 오류, PromQL 표현식 오류, 테스트 실패를 배포 전에 잡을 수 있다.
# 문법 검증
promtool check rules infrastructure_alerts.yaml
promtool check rules slo_alerts.yaml
# 단위 테스트 실행
promtool test rules alert_test.yaml
# Alertmanager 설정 검증
amtool check-config alertmanager.yaml
# CI 파이프라인 예시 (GitHub Actions)
# jobs:
# validate-alerts:
# steps:
# - name: Check alert rules syntax
# run: promtool check rules rules/*.yaml
# - name: Run alert rule tests
# run: promtool test rules tests/*.yaml
# - name: Check Alertmanager config
# run: amtool check-config alertmanager.yaml
Alertmanager 설정 심화
라우팅 트리(routing tree) 설계
Alertmanager의 라우팅은 트리 구조로 동작한다. 최상위 route는 모든 알림의 기본 수신자를 정의하고, 하위 route들이 레이블 매칭을 통해 알림을 적절한 채널로 분기한다. continue: true를 설정하면 매칭된 후에도 동일 레벨의 다음 라우팅 규칙을 계속 평가하여 하나의 알림을 여러 수신자에게 전달할 수 있다.
group_by는 동일한 레이블 값을 가진 알림들을 하나의 그룹으로 묶는다. 예를 들어 group_by: [alertname, cluster]로 설정하면 같은 알림 이름과 같은 클러스터에서 발생한 알림들이 하나의 알림 메시지로 묶여서 전달된다. 이를 통해 100개의 Pod에서 동시에 발생한 OOMKilled 알림이 100개의 개별 메시지가 아닌 하나의 그룹 메시지로 전달된다.
# alertmanager.yaml
global:
resolve_timeout: 5m
smtp_smarthost: 'smtp.internal:587'
smtp_from: 'alertmanager@company.com'
route:
receiver: default-slack
group_by: [alertname, cluster, namespace]
group_wait: 30s # 첫 알림 수신 후 그룹핑을 위해 대기
group_interval: 5m # 기존 그룹에 새 알림 추가 시 재전송 간격
repeat_interval: 4h # 동일 알림 반복 전송 간격
routes:
# Critical 알림 → PagerDuty (즉시 페이징)
- match:
severity: critical
receiver: pagerduty-critical
group_wait: 10s
repeat_interval: 1h
continue: true # Slack에도 동시 전송
# Critical 알림 → Slack critical 채널 (동시 전송)
- match:
severity: critical
receiver: slack-critical
# SLO 관련 알림 → SRE 팀 전용 채널
- match_re:
alertname: '^Slo.*'
receiver: slack-sre-slo
group_by: [alertname, service]
# 인프라 팀 알림
- match:
team: infra
receiver: slack-infra
group_by: [alertname, instance]
# 백엔드 팀 알림
- match:
team: backend
receiver: slack-backend
group_by: [alertname, service, namespace]
# Watchdog 알림 (Alertmanager 정상 동작 확인용)
- match:
alertname: Watchdog
receiver: 'null'
repeat_interval: 24h
Inhibition Rules로 하위 알림 억제
Inhibition Rules는 특정 알림이 발화 중일 때 관련된 하위 알림을 억제한다. 예를 들어 노드 자체가 다운되면 해당 노드의 모든 Pod 알림은 불필요하다. 인프라 레벨 장애가 발생했을 때 그로 인해 연쇄적으로 발생하는 수십 개의 하위 알림을 억제하여 알림 폭주를 방지한다.
# alertmanager.yaml (inhibition section)
inhibit_rules:
# 노드 다운 시 해당 노드의 모든 하위 알림 억제
- source_matchers:
- alertname = NodeDown
target_matchers:
- severity =~ "warning|info"
equal: [instance]
# 클러스터 레벨 장애 시 개별 서비스 알림 억제
- source_matchers:
- alertname = ClusterUnreachable
target_matchers:
- severity =~ "warning|critical"
equal: [cluster]
# Critical이 firing 중이면 동일 알림의 Warning 억제
- source_matchers:
- severity = critical
target_matchers:
- severity = warning
equal: [alertname, cluster, namespace]
# 대규모 장애 시 SLO 알림 억제 (인프라 레벨 문제이므로)
- source_matchers:
- alertname =~ "NodeDown|ClusterUnreachable"
target_matchers:
- alertname =~ "^Slo.*"
equal: [cluster]
Silences로 유지보수 시 알림 중지
계획된 유지보수 시 관련 알림을 일시적으로 중지할 수 있다. amtool CLI 또는 Alertmanager UI에서 Silence를 생성한다. Silence는 레이블 매처로 적용 범위를 지정하고, 만료 시간이 지나면 자동으로 해제된다.
# amtool로 Silence 생성 (2시간 동안 특정 클러스터 알림 중지)
amtool silence add \
--alertmanager.url=http://alertmanager:9093 \
--author="sre-team" \
--comment="Planned maintenance: k8s cluster upgrade" \
--duration=2h \
cluster="production-us-east-1"
# 활성 Silence 목록 확인
amtool silence query --alertmanager.url=http://alertmanager:9093
# Silence 해제
amtool silence expire --alertmanager.url=http://alertmanager:9093 <silence-id>
PagerDuty와 Slack 통합
다중 수신자 설정
심각도에 따라 알림을 다른 채널로 라우팅하는 것이 핵심이다. Critical 알림은 PagerDuty를 통해 온콜 엔지니어에게 즉시 페이징하고, Warning 알림은 Slack 채널에 전달하여 근무 시간 내에 조사하도록 한다.
# alertmanager.yaml (receivers section)
receivers:
# 기본 수신자: Slack general 채널
- name: default-slack
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/XXXXX'
channel: '#alerts-general'
send_resolved: true
title: '{{ if eq .Status "firing" }}FIRING{{ else }}RESOLVED{{ end }} - {{ .CommonLabels.alertname }}'
text: >-
*Severity:* {{ .CommonLabels.severity | toUpper }}
*Cluster:* {{ .CommonLabels.cluster }}
*Namespace:* {{ .CommonLabels.namespace }}
{{ range .Alerts }}
- *{{ .Labels.instance }}*: {{ .Annotations.description }}
{{ end }}
# PagerDuty Critical 수신자
- name: pagerduty-critical
pagerduty_configs:
- service_key_file: '/etc/alertmanager/secrets/pagerduty-service-key'
severity: '{{ .CommonLabels.severity }}'
description: '{{ .CommonAnnotations.summary }}'
details:
firing: '{{ .Alerts.Firing | len }}'
resolved: '{{ .Alerts.Resolved | len }}'
cluster: '{{ .CommonLabels.cluster }}'
namespace: '{{ .CommonLabels.namespace }}'
runbook_url: '{{ .CommonAnnotations.runbook_url }}'
# Slack Critical 채널 (PagerDuty와 동시 전송)
- name: slack-critical
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/YYYYY'
channel: '#alerts-critical'
send_resolved: true
color: '{{ if eq .Status "firing" }}danger{{ else }}good{{ end }}'
title: 'CRITICAL: {{ .CommonLabels.alertname }}'
text: >-
*Status:* {{ .Status | toUpper }}
{{ range .Alerts }}
- {{ .Annotations.description }}
Runbook: {{ .Annotations.runbook_url }}
{{ end }}
# SRE SLO 전용 채널
- name: slack-sre-slo
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/ZZZZZ'
channel: '#sre-slo-alerts'
send_resolved: true
title: 'SLO Alert: {{ .CommonLabels.alertname }}'
text: >-
*Service:* {{ .CommonLabels.service }}
*Window:* {{ .CommonLabels.window }}
{{ range .Alerts }}
- {{ .Annotations.description }}
{{ end }}
# 인프라 팀 채널
- name: slack-infra
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/INFRA'
channel: '#team-infra-alerts'
send_resolved: true
# 백엔드 팀 채널
- name: slack-backend
slack_configs:
- api_url: 'https://hooks.slack.com/services/T00/B00/BACKEND'
channel: '#team-backend-alerts'
send_resolved: true
# Null 수신자 (Watchdog 등 불필요한 알림 흡수)
- name: 'null'
PagerDuty Events API v2를 사용할 경우 routing_key와 service_key_file을 적절히 선택해야 한다. service_key_file은 파일 기반으로 비밀 키를 주입하므로 Kubernetes Secret과 연동하기 용이하다. Slack Incoming Webhook은 채널별로 별도의 Webhook URL을 생성하여 수신자별로 다른 채널에 전달한다.
Grafana Alerting과의 비교
Grafana 9 이후 Unified Alerting이 도입되면서 Grafana 자체에서도 알림 규칙을 관리할 수 있게 되었다. 두 시스템의 특성을 비교하여 환경에 맞는 선택을 해야 한다.
| 항목 | Prometheus Alertmanager | Grafana Unified Alerting |
|---|---|---|
| 데이터 소스 | Prometheus 전용 | 다중 데이터 소스 (Loki, Tempo, SQL 등) |
| 규칙 관리 | YAML 파일 (GitOps 친화) | UI 또는 Provisioning API |
| 라우팅 | 트리 기반 정밀 라우팅 | 정책 기반 라우팅 (Notification Policies) |
| 평가 엔진 | Prometheus 서버 내장 | Grafana 서버 또는 외부 Ruler |
| HA 지원 | Gossip 프로토콜 내장 | Grafana HA 의존 |
| 테스트 도구 | promtool (CLI 기반) | UI 프리뷰, API 기반 |
| 성숙도 | 매우 높음 (10년+) | 성장 중 (Grafana 9+ 이후) |
| 확장성 | Thanos/Cortex Ruler 연동 | Mimir Ruler 연동 |
| 생태계 | 풍부한 커뮤니티 규칙 | Grafana 에코시스템 통합 |
하이브리드 접근 전략
실무에서는 둘 중 하나만 선택하기보다 하이브리드 접근이 효과적이다.
- Prometheus Alertmanager: 인프라 메트릭, SLO 기반 알림, 높은 신뢰성이 요구되는 핵심 알림
- Grafana Unified Alerting: 로그 기반 알림 (Loki), 트레이스 기반 알림 (Tempo), 비즈니스 메트릭 알림 (SQL 데이터 소스)
- 공통 Alertmanager: Grafana의 알림도 외부 Alertmanager로 라우팅하여 통합 관리 가능
Grafana에서 외부 Alertmanager를 연결하면, Grafana의 다양한 데이터 소스 지원과 Alertmanager의 강력한 라우팅/그룹핑을 동시에 활용할 수 있다.
Alert Fatigue 방지 전략
알림 피로의 원인과 증상
Alert Fatigue(알림 피로)는 과도한 알림으로 인해 온콜 엔지니어의 주의력이 분산되고, 결국 중요한 알림까지 무시하게 되는 현상이다. PagerDuty의 2024 State of Digital Operations 보고서에 따르면, 온콜 엔지니어가 하루 평균 10건 이상의 알림을 받으면 대응 품질이 급격히 저하된다.
알림 피로의 주요 원인은 다음과 같다.
- 과도한 원인 기반 알림: CPU 60%, 70%, 80% 각각에 알림을 건 경우
- 임계값 미조정: 기본값 그대로 사용하여 정상 변동에도 반응
- group_by 미설정: 동일 장애로 수십 개의 개별 알림 발생
- 자동 복구되는 일시적 현상: 재시작으로 해결되는 OOM에 매번 알림
- 비즈니스 시간 무관 알림: 새벽 3시에 Warning 알림으로 페이징
신호 대 잡음비(SNR) 개선
모든 알림은 다음 질문을 통과해야 한다.
- 이 알림을 받으면 즉시 행동해야 하는가?
- 이 알림은 사용자에게 영향을 주는 증상을 나타내는가?
- 이 알림이 없다면 어떤 위험이 있는가?
- 이 알림에 대한 명확한 Runbook이 존재하는가?
하나라도 "아니오"라면 그 알림은 제거하거나 대시보드 패널로 전환해야 한다.
알림 우선순위 체계: P1-P4
| 우선순위 | 정의 | 알림 채널 | 대응 시간 | 예시 |
|---|---|---|---|---|
| P1 (Critical) | 서비스 전면 장애 또는 데이터 손실 위험 | PagerDuty 즉시 페이징 | 5분 이내 | 전체 API 다운, 데이터베이스 장애 |
| P2 (High) | 부분 장애 또는 성능 심각 저하 | PagerDuty + Slack | 30분 이내 | 특정 엔드포인트 에러율 급증 |
| P3 (Warning) | 잠재적 문제, 조사 필요 | Slack 채널 | 영업일 기준 4시간 | 디스크 사용률 증가 추세 |
| P4 (Info) | 참고 정보 | Slack 또는 대시보드만 | 다음 스프린트 | 인증서 30일 내 만료 |
주간 알림 리뷰 프로세스
매주 팀 차원에서 지난 한 주간의 알림을 리뷰한다.
- 정량 분석: 총 알림 수, severity별 분포, 팀별 분포, MTTR 측정
- 오탐 분류: 각 알림이 실제 행동을 유발했는지 확인
- 임계값 조정: 오탐이 반복되는 알림의 임계값 또는 for 기간 조정
- 규칙 정리: 3주 연속 무시된 알림은 제거 후보
- 문서화: 조정 사항과 근거를 기록
Cloudflare의 알림 관찰성 사례
Cloudflare는 "Alerts Observability"라는 개념을 도입하여 알림 자체를 관찰 대상으로 삼았다. 알림의 발화 빈도, 응답 시간, 자동 해소 비율, 에스컬레이션 비율을 대시보드로 시각화하고, 이를 기반으로 알림 품질을 지속적으로 개선한다. 알림 시스템에 대한 메타 모니터링이 Alert Fatigue를 체계적으로 관리하는 핵심이다.
실패 사례와 복구 절차
사례 1: group_by 잘못 설정으로 알림 폭주
상황: group_by를 [alertname]으로만 설정한 상태에서 100개 노드의 DiskWillFillIn24Hours 알림이 동시에 발화했다. 모든 노드의 알림이 하나의 그룹으로 묶여 단일 알림만 전송되었고, 개별 노드 정보가 누락되어 대응이 불가능했다.
원인: group_by에 instance 레이블을 포함하지 않아 모든 노드의 알림이 하나로 합쳐졌다.
해결: group_by: [alertname, instance]로 변경하여 노드별로 별도의 알림 그룹이 생성되도록 수정했다. 단, group_by에 레이블을 너무 많이 포함하면 그룹이 지나치게 세분화되어 반대의 문제(알림 폭주)가 발생할 수 있으므로 적절한 균형이 필요하다.
사례 2: PagerDuty 라우팅 누락으로 장애 미감지
상황: 새로운 마이크로서비스를 배포했으나 해당 서비스의 알림에 team: payments 레이블이 누락되었다. 라우팅 규칙에 매칭되지 않아 기본 수신자(Slack general 채널)로만 전달되었고, 결제 서비스 장애가 30분간 미감지되었다.
원인: 서비스 배포 시 알림 규칙의 레이블 검증 프로세스가 없었다.
해결: CI 파이프라인에 레이블 검증 단계를 추가하여 모든 알림 규칙에 team, severity 레이블이 반드시 포함되도록 강제했다. amtool을 활용한 라우팅 시뮬레이션을 배포 전 체크에 포함했다.
# amtool로 라우팅 경로 시뮬레이션
amtool config routes test \
--config.file=alertmanager.yaml \
--tree \
severity=critical team=payments alertname=HighErrorRate
# 예상 출력: pagerduty-critical → slack-critical
# team=payments 라벨이 없는 경우: default-slack (경고 발생)
복구 절차 체크리스트
알림 파이프라인 장애 시 단계별 확인 항목이다.
- Alertmanager 클러스터 상태 확인:
amtool cluster show - 현재 활성 알림 확인: Alertmanager UI 또는
amtool alert query - Silence 상태 확인: 의도하지 않은 Silence가 활성화되어 있지 않은지
- Prometheus 알림 규칙 평가 상태: Prometheus UI의 Alerts 탭에서 에러 확인
- 네트워크 연결: Prometheus에서 Alertmanager로의 통신 확인
- 수신자 연결: PagerDuty API, Slack Webhook 응답 확인
- 설정 파일 무결성:
amtool check-config alertmanager.yaml
운영 시 주의사항
알림 규칙 네이밍 컨벤션
일관된 네이밍은 라우팅 규칙 작성과 대시보드 필터링에 필수적이다. 다음 컨벤션을 권장한다.
| 패턴 | 설명 | 예시 |
|---|---|---|
| 대상 + 증상 | 무엇이 어떤 상태인지 | HighCpuUsage, DiskWillFillIn24Hours |
| SLO 접두사 | SLO 관련 알림 구분 | SloHighBurnRate, SloLatencyBudgetExhausted |
| 서비스 접두사 | 서비스별 고유 알림 | ApiGatewayHighLatency, PaymentServiceDown |
PascalCase를 사용하고, 알림 이름만으로 무엇이 문제인지 파악할 수 있어야 한다. "Alert1", "Check5"같은 의미 없는 이름은 금지한다.
라벨 표준화와 거버넌스
모든 알림 규칙에 포함해야 하는 필수 레이블을 정의한다.
| 레이블 | 필수 여부 | 설명 | 허용 값 |
|---|---|---|---|
| severity | 필수 | 알림 심각도 | critical, warning, info |
| team | 필수 | 담당 팀 | infra, backend, frontend, data, sre |
| service | 권장 | 관련 서비스 | 서비스 디스커버리 이름과 일치 |
| slo | 선택 | SLO 관련 여부 | availability, latency |
레이블 값은 반드시 열거형으로 관리하고, 자유 텍스트를 허용하면 라우팅 규칙이 복잡해지고 관리가 불가능해진다. OPA(Open Policy Agent)나 CI 파이프라인에서 레이블 스키마를 검증하는 방법이 효과적이다.
정기적 알림 감사(audit)
분기별로 전체 알림 규칙에 대한 감사를 수행한다.
- 활성 알림 수 추이: 알림 수가 지속적으로 증가하고 있다면 규칙 정리 필요
- 오탐률 측정: firing 후 5분 내 자동 resolve된 알림의 비율
- 응답률 측정: 알림 발화 후 실제 조치가 이루어진 비율
- 소유자 확인: 모든 알림 규칙에 담당 팀이 지정되어 있는지
- Runbook 연결: 모든 Critical/Warning 알림에 runbook_url이 있는지
감사 결과를 기반으로 규칙을 정리하고, 불필요한 알림을 제거하며, 임계값을 조정한다. 알림 규칙은 코드와 마찬가지로 지속적인 유지보수가 필요한 살아있는 자산이다.