6. Alertmanager를 이용한 장애 알림 시스템 구축

모니터링의 최종 목표는 단순히 데이터를 쌓고 대시보드를 보는 것이 아니라, 문제가 발생했을 때 이를 자동으로 인지하고 담당자에게 알리는 것입니다. 아무리 멋진 대시보드도 24시간 보고 있을 수는 없기 때문입니다. 이 역할을 하는 것이 바로 프로메테우스 생태계의 '알림 처리 전문 컴포넌트'인 Alertmanager입니다.

이번 장에서는 프로메테우스에서 알림 규칙을 정의하고, Alertmanager를 통해 중복 알림을 방지하며 슬랙(Slack)으로 의미 있는 장애 알림을 보내는 전체 과정을 실습합니다.

1. 프로메테우스와 Alertmanager의 역할 분담

프로메테우스 생태계는 알림 발생과 알림 처리를 의도적으로 분리했습니다. 이는 각 컴포넌트가 자신의 역할에만 집중하도록 하는 좋은 설계입니다.

Prometheus
(Alerting Rules)
Alertmanager
(Grouping, Routing)
Slack, Email, ...

2. 1단계: 프로메테우스에 알림 규칙(Alerting Rules) 정의하기

먼저 프로메테우스가 "어떤 상황에 알림을 보낼지"를 정의해야 합니다. 이는 별도의 YAML 파일(예: alert.rules.yml)에 작성합니다.

# alert.rules.yml
groups:
  - name: host-alerts
    rules:
      - alert: InstanceDown
        expr: up == 0
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "인스턴스 다운: {{ $labels.instance }}"
          description: "{{ $labels.job }} 잡의 {{ $labels.instance }} 인스턴스가 1분 이상 다운 상태입니다."

      - alert: HighCpuUsage
        expr: (100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[2m])) * 100)) > 80
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "높은 CPU 사용률: {{ $labels.instance }}"
          description: "{{ $labels.instance }}의 CPU 사용률이 5분 동안 {{ $value | printf `%.2f` }}% 입니다."

위 규칙 파일의 각 필드는 다음과 같은 의미를 가집니다.

이 규칙 파일을 prometheus.yml에 등록하고 프로메테우스를 재시작하면, 프로메테우스는 이제 알림을 발생시킬 준비를 마칩니다.

# prometheus.yml
rule_files:
  - "alert.rules.yml"

alerting:
  alertmanagers:
    - static_configs:
      - targets:
        - 'localhost:9093' # Alertmanager 주소

3. 2단계: Alertmanager 설정하기 (`alertmanager.yml`)

이제 프로메테우스가 보낸 알림을 받아서 처리할 Alertmanager를 설정합니다.

비유: 우체국 집배원

Alertmanager는 똑똑한 우체국 집배원과 같습니다. 여러 부서(프로메테우스)에서 온 편지(알림)들을 그냥 배달하지 않습니다.

이 과정 덕분에 우리는 새벽 3시에 "서버 1 다운!", "서버 2 다운!", ... "서버 100 다운!" 이라는 100개의 알림 폭탄을 받는 대신, "prod-cluster 서버 100대 다운" 이라는 하나의 통합된 알림만 받게 됩니다.

# alertmanager.yml
global:
  # 여기에 슬랙 웹훅 URL 등을 설정할 수 있습니다.
  slack_api_url: 'https://hooks.slack.com/services/...'

route:
  # 기본 수신자
  receiver: 'slack-default'
  # 어떤 레이블로 알림을 그룹화할지 결정합니다.
  # cluster, alertname이 같다면 하나의 알림으로 묶입니다.
  group_by: ['alertname', 'cluster']
  
  # 첫 알림을 받은 후, 이 시간만큼 기다렸다가 그룹 내 다른 알림이 오는지 확인
  group_wait: 30s
  # 그룹 내 새로운 알림이 발생했을 때, 다음 알림까지 대기하는 시간
  group_interval: 5m
  # 동일한 알림이 해결되지 않았을 때, 다시 알림을 보내는 주기
  repeat_interval: 4h

  # 하위 라우팅 규칙들
  routes:
    - receiver: 'slack-critical'
      # severity 레이블이 'critical'인 알림은 이 경로를 따릅니다.
      match:
        severity: 'critical'

receivers:
  - name: 'slack-default'
    slack_configs:
      - channel: '#alerts-general'
        # 슬랙 메시지 템플릿
        text: "summary: {{ .CommonAnnotations.summary }}\ndescription: {{ .CommonAnnotations.description }}"

  - name: 'slack-critical'
    slack_configs:
      - channel: '#alerts-critical'
        text: " [CRITICAL] {{ .CommonAnnotations.summary }}\n{{ .CommonAnnotations.description }}"

4. 고급 기능: Inhibition과 Silencing

Alertmanager의 강력함은 불필요한 알림을 '억제'하는 기능에서 나옵니다.

# alertmanager.yml에 추가
inhibit_rules:
  - source_match:
      severity: 'critical' # 심각도 'critical' 알림이 발생하면
    target_match:
      severity: 'warning'   # 심각도 'warning' 알림을 억제한다
    # 단, cluster 레이블이 같을 때만 억제한다
    equal: ['cluster']

면접관의 시선 💡

Q: "프로메테우스에서 알림은 어떻게 동작하나요? Alertmanager의 역할은 무엇인가요?"

A: "프로메테우스의 알림은 프로메테우스 서버와 Alertmanager의 역할 분담으로 동작합니다. 먼저 프로메테우스 서버는 `alert.rules.yml`에 정의된 PromQL 규칙을 주기적으로 평가하여, 조건이 충족되면 Alertmanager로 알림 이벤트를 보냅니다. 즉, '언제' 알림을 보낼지 결정합니다. Alertmanager는 이 알림을 받아서 그룹화, 중복제거, 라우팅을 담당합니다. 예를 들어, 여러 개의 알림을 하나의 메시지로 묶어주거나, 심각도에 따라 다른 채널(슬랙, 이메일)로 보내는 등 '어떻게', '어디로' 알림을 보낼지 결정합니다. 이러한 역할 분리 덕분에 복잡한 알림 정책을 효율적으로 관리할 수 있습니다."


Q: "CPU 사용량이 순간적으로 튀는 경우가 많은데, 이로 인해 불필요한 알림이 계속 오는 것을 어떻게 방지할 수 있나요?"

A: "프로메테우스의 알림 규칙에 있는 `for` 절을 사용하여 해결할 수 있습니다. 예를 들어, `expr: cpu_usage > 80` 라는 조건에 `for: 5m`를 추가하면, CPU 사용량이 80%를 넘는 상태가 5분 이상 '지속'될 때만 알림을 발생시킵니다. 이렇게 하면 일시적으로 튀는 값(flapping)으로 인한 불필요한 알림을 효과적으로 방지하고, 정말로 문제가 지속되는 상황에만 집중할 수 있습니다."


Q: "네트워크 장애로 인해 수백 개의 서버 알림이 동시에 쏟아지는 '알림 폭풍(Alert Storm)'을 경험한 적이 있나요? 어떻게 해결할 수 있을까요?"

A: "네, Alertmanager의 그룹화(Grouping)와 억제(Inhibition) 기능으로 해결할 수 있습니다. 첫째, `alertmanager.yml`의 `group_by` 설정을 사용하여 `cluster`나 `region` 같은 상위 레이블로 알림을 묶어주면, 수백 개의 개별 알림이 '클러스터 A에서 100개의 인스턴스 다운'과 같은 하나의 통합된 알림으로 수신됩니다. 둘째, 더 근본적인 해결책으로 Inhibition 규칙을 사용할 수 있습니다. 예를 들어, '네트워크 스위치 다운'이라는 최상위 원인 알림이 발생했을 때, 이와 관련된 하위 알림인 '서버 다운' 알림들을 자동으로 억제하도록 규칙을 설정하면, 가장 핵심적인 원인에 대한 알림만 받을 수 있어 혼란을 크게 줄일 수 있습니다."