🤖

본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.

⚠️

본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.

이미지 로딩 중...

알림 & On-Call 자동화 완벽 가이드 - 슬라이드 1/7
A

AI Generated

2025. 12. 10. · 15 Views

알림 & On-Call 자동화 완벽 가이드

Alertmanager와 PagerDuty를 활용한 실무 알림 자동화 시스템을 구축합니다. CPU 임계치 모니터링부터 Slack 알림, 당번 관리까지 실제 운영 환경에서 필요한 모든 내용을 다룹니다.


목차

  1. Alertmanager 설치와 설정
  2. 알림 규칙 작성 (CPU>80% 5분)
  3. Slack Webhook 연동
  4. PagerDuty 무료 플랜 설정
  5. rotation csv로 당번 관리
  6. oncall.yml 완성과 runbook 링크
  7. 문제가 지속되면 인스턴스 추가 고려

1. Alertmanager 설치와 설정

새벽 3시, 김운영 씨의 전화가 울렸습니다. "서버가 다운됐어요!" 하지만 정작 문제는 2시간 전에 시작됐습니다.

아무도 모르는 사이에 말이죠.

Alertmanager는 Prometheus에서 발생한 알림을 받아 적절한 담당자에게 전달하는 시스템입니다. 마치 회사의 접수 창구처럼, 문제가 발생하면 누구에게 어떻게 알려줄지 결정합니다.

제대로 설정하면 장애를 조기에 발견하고 빠르게 대응할 수 있습니다.

다음 코드를 살펴봅시다.

# docker-compose.yml
version: '3.8'
services:
  alertmanager:
    image: prom/alertmanager:latest
    ports:
      - "9093:9093"
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml
      # 설정 파일을 컨테이너에 마운트
    command:
      - '--config.file=/etc/alertmanager/alertmanager.yml'
      - '--storage.path=/alertmanager'
      # 알림 데이터 저장 경로 지정
    restart: unless-stopped

김운영 씨는 3년 차 DevOps 엔지니어입니다. 어느 날 아침, 출근하니 밤사이 서버 디스크가 가득 차서 서비스가 중단됐다는 보고를 받았습니다.

더 큰 문제는 장애가 발생한 지 3시간이나 지나서야 알게 됐다는 점입니다. 팀장님이 물으셨습니다.

"왜 즉시 알림을 받지 못했나요?" 김운영 씨는 답할 말이 없었습니다. 모니터링은 하고 있었지만, 알림 시스템이 제대로 구축되지 않았던 겁니다.

알림 시스템이란 무엇일까요? 쉽게 비유하자면, 알림 시스템은 마치 아파트 경비실과 같습니다. 이상한 일이 생기면 경비 아저씨가 즉시 관리자에게 연락을 취하죠.

밤낮 없이 지켜보다가 문제가 생기면 적절한 사람에게 알려주는 것입니다. Alertmanager는 바로 이런 역할을 하는 도구입니다.

Prometheus가 메트릭을 수집하고 문제를 감지하면, Alertmanager가 그 알림을 받아서 누구에게 어떻게 전달할지 결정합니다. 왜 필요한가? Alertmanager가 없던 시절에는 어땠을까요?

개발자들은 직접 모니터링 대시보드를 수시로 확인해야 했습니다. 주말에도, 새벽에도 혹시 모를 장애를 대비해 긴장 상태를 유지해야 했죠.

더 큰 문제는 여러 시스템에서 동시에 알림이 오면 어떤 것이 긴급한지 판단하기 어려웠다는 점입니다. 한 스타트업에서는 5명의 개발자가 모두 같은 알림을 받아서 새벽에 동시에 전화가 울리는 바람에 혼란을 겪기도 했습니다.

"누가 처리하지?" 서로 눈치만 보다가 대응이 늦어진 것입니다. Alertmanager의 등장 바로 이런 문제를 해결하기 위해 Alertmanager가 등장했습니다.

Alertmanager를 사용하면 중복 알림을 제거할 수 있습니다. 같은 문제로 10개의 알림이 와도 하나로 묶어서 전달하죠.

또한 알림 라우팅도 가능합니다. 데이터베이스 문제는 DB팀에게, 프론트엔드 오류는 프론트 팀에게 자동으로 전달됩니다.

무엇보다 당번 관리가 가능하다는 큰 이점이 있습니다. 오늘 당번인 사람에게만 알림이 가도록 설정할 수 있습니다.

설치 방법 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 Docker Compose를 사용해 Alertmanager를 실행합니다.

image: prom/alertmanager:latest에서 최신 이미지를 가져오는 것을 알 수 있습니다. 이 부분이 핵심입니다.

다음으로 ports 섹션에서는 9093 포트를 열어줍니다. 이 포트로 웹 UI에 접속할 수 있습니다.

volumes 섹션이 중요한데, 로컬의 설정 파일을 컨테이너 안으로 마운트하는 부분입니다. command 섹션에서는 설정 파일 경로를 지정합니다.

이렇게 하면 우리가 작성한 설정이 적용됩니다. 실행하기 실제로 실행해볼까요?

터미널에서 docker-compose up -d 명령을 실행하면 Alertmanager가 백그라운드에서 시작됩니다. 브라우저에서 http://localhost:9093에 접속하면 웹 UI를 볼 수 있습니다.

처음에는 알림이 없어서 빈 화면이 보이지만, 이제부터 설정을 추가해나갈 것입니다. 기본 설정 파일 구조 Alertmanager는 alertmanager.yml 파일로 동작을 제어합니다.

이 파일에서 누구에게, 어떻게, 언제 알림을 보낼지 정의합니다. 다음 섹션에서 상세히 다룰 예정이지만, 기본적으로 route(라우팅), receivers(수신자), inhibit_rules(억제 규칙) 세 가지 섹션으로 구성됩니다.

주의사항 초보자들이 흔히 하는 실수 중 하나는 설정 파일 경로를 잘못 지정하는 것입니다. volumes 섹션에서 로컬 파일 경로를 정확히 입력해야 합니다.

상대 경로로 ./alertmanager.yml을 사용하면 docker-compose.yml과 같은 디렉토리에 있어야 합니다. 또한 포트 충돌도 주의해야 합니다.

이미 9093 포트를 다른 프로그램이 사용 중이라면 "9094:9093" 같은 형태로 변경할 수 있습니다. 정리 다시 김운영 씨의 이야기로 돌아가 봅시다.

Alertmanager를 설치한 김운영 씨는 이제 기본 인프라를 갖췄습니다. "이제 설정만 잘하면 되겠네!" Alertmanager를 제대로 설치하면 24시간 알림 시스템의 첫걸음을 뗄 수 있습니다.

여러분도 오늘 배운 내용을 실제 서버에 적용해 보세요.

실전 팁

💡 - Docker Compose를 사용하면 설치가 간단하고 재현 가능합니다

  • 웹 UI(9093 포트)로 알림 상태를 실시간으로 확인할 수 있습니다
  • 설정 변경 후에는 docker-compose restart alertmanager로 재시작해야 적용됩니다

2. 알림 규칙 작성 (CPU>80% 5분)

Alertmanager는 설치했지만 알림이 오지 않습니다. 김운영 씨는 고민에 빠졌습니다.

"뭘 빠뜨린 걸까?" 선배 박인프라 씨가 말했습니다. "Prometheus에 알림 규칙을 작성해야죠."

알림 규칙은 어떤 상황에서 알림을 발생시킬지 정의하는 조건입니다. 마치 자동차 계기판의 경고등처럼, 특정 임계치를 넘으면 알림을 보냅니다.

Prometheus에서 메트릭을 평가하고, 조건이 만족되면 Alertmanager에게 알림을 전달합니다.

다음 코드를 살펴봅시다.

# prometheus-rules.yml
groups:
  - name: system_alerts
    interval: 30s
    # 30초마다 규칙을 평가합니다
    rules:
      - alert: HighCPUUsage
        # 알림 이름: CPU 사용률 높음
        expr: 100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        # CPU 유휴 시간을 제외한 사용률이 80% 초과
        for: 5m
        # 5분간 지속될 때만 알림 발생
        labels:
          severity: warning
        annotations:
          summary: "높은 CPU 사용률 감지"
          description: "{{ $labels.instance }}의 CPU 사용률이 {{ $value }}%입니다"

김운영 씨는 Alertmanager를 설치하고 기대에 부풀었습니다. 테스트 삼아 서버에 부하를 주어 CPU를 99%까지 올렸습니다.

하지만 아무 일도 일어나지 않았습니다. Slack도 조용하고, 전화도 오지 않았습니다.

"뭐가 문제지?" 한참을 고민하던 김운영 씨는 선배 박인프라 씨를 찾아갔습니다. "Alertmanager는 설치했는데 알림이 안 와요." 박인프라 씨가 웃으며 말했습니다.

"Alertmanager는 알림을 받아서 전달만 하는 겁니다. 정작 중요한 건 Prometheus에서 알림을 발생시키는 거예요." 알림 규칙이란 무엇일까요? 쉽게 비유하자면, 알림 규칙은 마치 은행 계좌의 잔액 알림 설정과 같습니다.

"잔액이 10만 원 이하가 되면 문자를 보내주세요"라고 설정하는 것처럼, "CPU가 80% 이상이면 알림을 보내주세요"라고 정의하는 것입니다. Prometheus는 수많은 메트릭을 수집합니다.

CPU, 메모리, 디스크, 네트워크 등 수백 가지 지표들이 계속 쌓입니다. 하지만 이 중 어떤 것이 문제인지는 우리가 알려줘야 합니다.

바로 알림 규칙을 통해서 말이죠. 왜 임계치가 필요한가? 모든 메트릭 변화에 알림을 보낼 수는 없습니다.

CPU가 51%에서 52%로 올라갔다고 알림을 보내면 하루에도 수백 건의 알림이 쏟아질 것입니다. 이를 알림 피로도라고 부릅니다.

실제로 한 스타트업에서는 알림 설정을 너무 민감하게 해서 하루에 500건의 Slack 메시지를 받았습니다. 결국 개발자들이 알림을 무시하기 시작했고, 정작 중요한 장애를 놓치는 사고가 발생했습니다.

적절한 임계치 설정 바로 이런 문제를 해결하기 위해 임계치와 지속 시간을 설정합니다. CPU가 80%를 넘었다고 바로 알림을 보내지 않습니다.

5분간 지속될 때만 알림을 발생시킵니다. 왜냐하면 일시적인 스파이크는 정상적인 동작일 수 있기 때문입니다.

예를 들어 배치 작업이 실행되면 1-2분간 CPU가 100%에 도달할 수 있습니다. 이건 예상된 동작이므로 알림이 필요 없습니다.

하지만 5분 이상 지속된다면 뭔가 잘못된 것입니다. 코드 분석 위의 코드를 한 줄씩 살펴보겠습니다.

먼저 groups에서 알림 규칙들을 그룹으로 묶습니다. system_alerts라는 이름으로 시스템 관련 알림들을 모았습니다.

interval: 30s는 30초마다 이 규칙들을 평가한다는 의미입니다. alert: HighCPUUsage는 알림의 이름입니다.

이 이름이 Alertmanager와 Slack에 표시됩니다. expr 부분이 핵심인데, PromQL 쿼리로 CPU 사용률을 계산합니다.

100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80을 풀어보면, CPU idle 시간의 반대가 사용 시간입니다. 이 값이 80을 초과하면 조건이 참이 됩니다.

for: 5m은 5분간 조건이 유지될 때만 알림을 보냅니다. labels에서는 심각도를 지정하고, annotations에서는 알림 메시지를 정의합니다.

실무 활용 사례 실제 현업에서는 어떻게 활용할까요? 전자상거래 서비스를 운영한다고 가정해봅시다.

평소에는 CPU가 30-40%를 유지하지만, 점심시간이나 저녁 시간대에는 60-70%까지 올라갑니다. 이런 패턴을 분석해서 임계치를 **80%**로 설정했습니다.

어느 날 오후 2시, CPU가 85%를 넘었습니다. 1분, 2분, 3분...

5분이 지나도 내려오지 않습니다. 이때 Prometheus가 알림을 발생시키고, Alertmanager가 당번 개발자에게 전달합니다.

조사 결과 새로 배포한 코드에 무한 루프가 있었고, 즉시 롤백해서 장애를 막았습니다. 다양한 알림 규칙 CPU 외에도 다양한 규칙을 만들 수 있습니다.

메모리 사용률, 디스크 공간, 응답 시간, 에러율 등 중요한 지표마다 규칙을 정의합니다. 각 규칙마다 적절한 임계치와 지속 시간을 설정해야 합니다.

디스크 공간은 빠르게 회복되지 않으므로 80% 초과시 즉시 알림을 보냅니다. 반면 응답 시간은 일시적으로 느려질 수 있으므로 3-5분 정도 여유를 둡니다.

주의사항 초보자들이 흔히 하는 실수 중 하나는 임계치를 너무 낮게 설정하는 것입니다. CPU 50% 초과시 알림을 보내면 알림이 너무 많이 옵니다.

운영하면서 점차 조정해나가는 것이 좋습니다. 또한 for 값을 너무 길게 설정하면 장애 대응이 늦어집니다.

보통 3-5분이 적절하며, 중요도에 따라 조정합니다. 정리 다시 김운영 씨의 이야기로 돌아가 봅시다.

박인프라 씨의 설명을 들은 김운영 씨는 즉시 알림 규칙을 작성했습니다. 테스트해보니 5분 후 Alertmanager에 알림이 표시됐습니다.

"드디어 작동하네!" 알림 규칙을 제대로 작성하면 중요한 문제만 골라서 알림을 받을 수 있습니다. 여러분도 오늘 배운 내용을 바탕으로 자신의 서비스에 맞는 규칙을 작성해 보세요.

실전 팁

💡 - 임계치는 운영하면서 점차 조정합니다. 처음에는 보수적으로 설정하세요

  • for 값으로 일시적인 스파이크를 걸러낼 수 있습니다
  • PromQL은 강력하지만 복잡합니다. 간단한 쿼리부터 시작하세요

3. Slack Webhook 연동

알림이 발생하는 건 확인했지만, 김운영 씨는 계속 Alertmanager 웹 UI를 새로고침해야 했습니다. "이럴 거면 의미가 없는데..." 박인프라 씨가 말했습니다.

"Slack으로 알림을 보내야죠."

Slack Webhook은 외부 시스템에서 Slack 채널로 메시지를 보낼 수 있는 기능입니다. 마치 우편함에 편지를 넣는 것처럼, 정해진 주소로 메시지를 보내면 Slack 채널에 자동으로 표시됩니다.

Alertmanager와 연동하면 알림을 실시간으로 받을 수 있습니다.

다음 코드를 살펴봅시다.

# alertmanager.yml
global:
  slack_api_url: 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX'
  # Slack Webhook URL (실제로는 Slack에서 발급받은 URL 사용)

route:
  receiver: 'slack-notifications'
  group_by: ['alertname', 'severity']
  # 같은 알림은 묶어서 전송
  group_wait: 10s
  group_interval: 5m
  repeat_interval: 3h

receivers:
  - name: 'slack-notifications'
    slack_configs:
      - channel: '#alerts'
        # 알림을 받을 Slack 채널
        title: '{{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
        # 알림 내용을 템플릿으로 구성

김운영 씨는 이제 알림이 제대로 발생하는 것을 확인했습니다. Alertmanager 웹 UI에 빨간색으로 경고가 표시됩니다.

하지만 문제가 있었습니다. 알림을 확인하려면 브라우저에서 http://localhost:9093에 접속해 페이지를 새로고침해야 했습니다.

"이건 너무 불편한데..." 김운영 씨는 답답했습니다. 회의 중에도, 점심 먹으면서도 계속 웹 페이지를 확인할 수는 없는 노릇입니다.

더 좋은 방법이 있을까요? 박인프라 씨가 답을 알려줬습니다.

"팀에서 쓰는 Slack으로 알림을 보내면 되죠." Slack Webhook이란 무엇일까요? 쉽게 비유하자면, Slack Webhook은 마치 자동 응답 시스템과 같습니다. 특정 전화번호(Webhook URL)로 전화를 걸면, 자동으로 메시지를 전달해주는 것이죠.

사람이 직접 입력하지 않아도 프로그램이 자동으로 메시지를 보낼 수 있습니다. Slack은 협업 도구로 이미 모든 팀원이 사용하고 있습니다.

채팅하고, 파일 공유하고, 회의도 합니다. 여기에 알림까지 오면 한 곳에서 모든 것을 관리할 수 있습니다.

왜 Slack인가? 이메일로 알림을 받으면 어떨까요? 하루에 수백 통의 이메일을 받는 개발자에게는 알림 메일이 묻혀버리기 쉽습니다.

또한 이메일은 실시간성이 떨어집니다. SMS로 받으면?

비용이 많이 들고, 긴 내용을 담기 어렵습니다. 심야 시간대에 문자가 오면 수면을 방해하기도 합니다.

Slack의 장점 바로 이런 이유로 많은 팀이 Slack을 알림 채널로 선택합니다. Slack을 사용하면 실시간 알림이 가능합니다.

데스크톱과 모바일 앱에서 즉시 푸시 알림을 받습니다. 또한 컨텍스트 유지도 쉽습니다.

알림을 보고 바로 같은 채널에서 팀원들과 논의할 수 있습니다. 무엇보다 무료라는 큰 이점이 있습니다.

Slack의 무료 플랜에서도 Webhook 기능을 제한 없이 사용할 수 있습니다. Webhook URL 발급받기 먼저 Slack에서 Webhook URL을 발급받아야 합니다.

Slack 워크스페이스에서 Settings & administration 메뉴로 들어갑니다. 그다음 Manage apps를 클릭하고, Incoming Webhooks를 검색합니다.

Add to Slack 버튼을 누르면 어떤 채널로 메시지를 보낼지 선택하는 화면이 나옵니다. #alerts라는 채널을 선택하면, Webhook URL이 생성됩니다.

https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXX 같은 형태입니다. 이 URL을 복사해둡니다.

설정 파일 작성 위의 코드를 한 줄씩 살펴보겠습니다. 먼저 global 섹션에서 slack_api_url을 설정합니다.

여기에 아까 복사한 Webhook URL을 붙여넣습니다. 이 설정은 전역적으로 적용됩니다.

route 섹션은 알림 라우팅 규칙입니다. receiverslack-notifications로 지정했으므로, 모든 알림이 이 수신자에게 전달됩니다.

group_by는 같은 종류의 알림을 묶어서 보냅니다. 100개의 CPU 알림을 개별로 보내면 Slack이 도배되므로, 하나로 합쳐서 보내는 것입니다.

group_wait는 첫 알림이 발생한 후 10초 동안 더 올 알림을 기다립니다. repeat_interval은 같은 알림을 3시간마다 반복해서 보냅니다.

문제가 해결되지 않았다는 리마인더 역할을 합니다. receivers 섹션에서 실제로 메시지를 보낼 설정을 정의합니다.

channel#alerts로 지정했고, titletext는 Go 템플릿 문법으로 동적으로 구성됩니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

한 스타트업에서는 심각도별로 다른 채널로 알림을 보냅니다. severity: critical인 알림은 #alerts-critical 채널로, severity: warning#alerts-warning 채널로 분리합니다.

이렇게 하면 중요한 알림에 집중할 수 있습니다. 또 다른 회사에서는 서비스별로 채널을 나눕니다.

#alerts-api, #alerts-frontend, #alerts-database 같은 식입니다. 각 팀이 자기 서비스의 알림만 받으므로 노이즈가 줄어듭니다.

테스트하기 설정을 저장하고 Alertmanager를 재시작합니다. CPU 부하를 발생시켜 알림을 트리거하면, 5분 후에 Slack에 메시지가 도착합니다.

"높은 CPU 사용률 감지"라는 제목과 함께 자세한 내용이 표시됩니다. 주의사항 초보자들이 흔히 하는 실수 중 하나는 Webhook URL을 Git에 커밋하는 것입니다.

이 URL은 비밀 정보이므로, 환경 변수나 Secret 관리 도구를 사용해야 합니다. 또한 알림이 너무 많으면 Slack도 소용없습니다.

적절한 임계치와 그룹핑 설정으로 알림 수를 조절해야 합니다. 정리 다시 김운영 씨의 이야기로 돌아가 봅시다.

Slack 연동을 완료한 김운영 씨는 테스트 알림을 받았습니다. 휴대폰에서 진동이 울리고, 화면에 알림이 표시됐습니다.

"이제야 제대로 된 모니터링 시스템이네!" Slack Webhook을 제대로 설정하면 어디서든 실시간으로 알림을 받을 수 있습니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.

실전 팁

💡 - Webhook URL은 비밀 정보입니다. 환경 변수로 관리하세요

  • 심각도별로 다른 채널을 사용하면 중요한 알림에 집중할 수 있습니다
  • group_bygroup_interval로 알림 폭탄을 방지할 수 있습니다

4. PagerDuty 무료 플랜 설정

Slack 알림은 잘 오지만, 김운영 씨는 여전히 불안했습니다. "주말에 Slack을 안 보면 어떡하지?" 심각한 장애는 누군가 반드시 대응해야 합니다.

박인프라 씨가 조언했습니다. "PagerDuty를 쓰세요."

PagerDuty는 알림을 전화, SMS, 푸시 등 다양한 방법으로 전달하고, 응답하지 않으면 다음 담당자에게 에스컬레이션하는 On-Call 관리 플랫폼입니다. 마치 119처럼, 반드시 누군가 응답하도록 보장합니다.

무료 플랜으로도 기본 기능을 충분히 활용할 수 있습니다.

다음 코드를 살펴봅시다.

# alertmanager.yml에 PagerDuty 설정 추가
receivers:
  - name: 'pagerduty-critical'
    pagerduty_configs:
      - service_key: 'YOUR_PAGERDUTY_INTEGRATION_KEY'
        # PagerDuty에서 발급받은 통합 키
        description: '{{ .GroupLabels.alertname }}: {{ .GroupLabels.instance }}'
        severity: '{{ .CommonLabels.severity }}'
        client: 'Alertmanager'
        client_url: 'http://alertmanager:9093'

route:
  routes:
    - match:
        severity: critical
      receiver: 'pagerduty-critical'
      # critical 알림은 PagerDuty로 전송
    - match:
        severity: warning
      receiver: 'slack-notifications'
      # warning 알림은 Slack으로만 전송

김운영 씨는 Slack 알림 시스템을 구축하고 뿌듯했습니다. 평일 근무 시간에는 완벽하게 작동했습니다.

알림이 오면 바로 확인하고 대응할 수 있었죠. 그런데 금요일 저녁, 퇴근 후 친구들과 저녁을 먹고 있을 때였습니다.

집에 돌아와 휴대폰을 확인하니 Slack에 100개가 넘는 메시지가 쌓여 있었습니다. 3시간 전부터 데이터베이스가 응답하지 않았던 것입니다.

다음 날 월요일, 팀장님이 물으셨습니다. "주말 On-Call은 어떻게 관리하고 있나요?" 김운영 씨는 답할 말이 없었습니다.

PagerDuty란 무엇일까요? 쉽게 비유하자면, PagerDuty는 마치 소방서의 출동 시스템과 같습니다. 화재 신고가 들어오면 가장 가까운 소방서에 알립니다.

응답이 없으면 다음 소방서에 연락합니다. 반드시 누군가 출동하도록 보장하는 것입니다.

Slack은 수동적입니다. 메시지를 보낼 뿐, 누가 확인했는지, 대응하고 있는지 알 수 없습니다.

심야나 주말에는 아무도 Slack을 보지 않을 수 있습니다. PagerDuty의 핵심 기능 PagerDuty는 이런 문제를 해결하기 위해 만들어졌습니다.

첫째, 다중 채널 알림입니다. 푸시 알림, 전화, SMS를 동시에 보냅니다.

앱을 안 봐도 전화가 울리므로 놓칠 수 없습니다. 둘째, 에스컬레이션입니다.

1차 담당자가 5분 내에 응답하지 않으면 자동으로 2차 담당자에게 알립니다. 그래도 응답이 없으면 3차, 4차로 올라갑니다.

셋째, On-Call 스케줄입니다. 누가 언제 당번인지 미리 정의하고, 해당 시간대에만 알림을 받습니다.

당번이 아닌 사람은 편히 쉴 수 있습니다. 무료 플랜의 한계 PagerDuty는 유료 서비스이지만, 무료 플랜도 제공합니다.

무료 플랜에서는 사용자 5명까지, 알림 무제한으로 사용할 수 있습니다. 작은 팀이라면 충분합니다.

다만 무료 플랜에는 제약이 있습니다. 고급 스케줄링, 상세한 리포트, 통합 기능 일부가 제한됩니다.

하지만 기본적인 On-Call 관리는 충분히 가능합니다. 회원가입과 서비스 생성 PagerDuty 웹사이트에서 회원가입을 합니다.

회사 이메일을 사용하면 팀 단위로 관리할 수 있습니다. 가입 후 Services 메뉴에서 새 서비스를 생성합니다.

서비스 이름은 Production Alerts 같은 식으로 정합니다. Integration Type에서 Events API v2를 선택합니다.

그러면 Integration Key가 생성됩니다. 이 키를 복사해둡니다.

코드 분석 위의 코드를 한 줄씩 살펴보겠습니다. receivers 섹션에 새로운 수신자 pagerduty-critical을 추가합니다.

pagerduty_configs에서 아까 복사한 service_key를 입력합니다. 이것이 Alertmanager와 PagerDuty를 연결하는 핵심입니다.

description은 PagerDuty에 표시될 알림 내용입니다. 알림 이름과 인스턴스 정보를 포함합니다.

severity는 심각도를 전달하고, client_url은 Alertmanager 링크를 포함합니다. route 섹션에서 라우팅 규칙을 정의합니다.

severity: critical인 알림만 PagerDuty로 보냅니다. severity: warning은 Slack으로만 보내므로, 불필요한 전화를 피할 수 있습니다.

실무 활용 사례 실제 현업에서는 어떻게 활용할까요? 한 스타트업에서는 팀원 5명이 돌아가며 On-Call을 담당합니다.

월요일은 김개발, 화요일은 이백엔드, 수요일은 박데브옵스... 이런 식입니다.

PagerDuty 스케줄에 이를 등록하면, 해당 요일의 담당자만 전화를 받습니다. 어느 날 새벽 2시, 데이터베이스 CPU가 95%를 넘었습니다.

오늘 당번인 이백엔드 씨의 전화가 울렸습니다. 푸시 알림, 전화, SMS가 동시에 왔습니다.

이백엔드 씨는 즉시 PagerDuty 앱에서 Acknowledge 버튼을 눌러 "내가 처리하겠다"고 알렸습니다. 로그를 확인하니 슬로우 쿼리가 원인이었습니다.

임시로 해당 쿼리를 비활성화하고, Resolve 버튼을 눌러 사건을 종료했습니다. 전체 소요 시간 15분, 고객은 장애를 느끼지 못했습니다.

Acknowledge와 Resolve PagerDuty의 핵심은 상태 관리입니다. 알림이 오면 상태는 Triggered입니다.

누군가 Acknowledge를 누르면 "처리 중"으로 바뀝니다. 다른 담당자들에게는 더 이상 알림이 가지 않습니다.

문제를 해결하고 Resolve를 누르면 사건이 종료됩니다. 만약 Acknowledge를 누르지 않으면 5분 후 다음 담당자에게 에스컬레이션됩니다.

이렇게 해서 반드시 누군가 대응하도록 보장합니다. 주의사항 초보자들이 흔히 하는 실수 중 하나는 모든 알림을 PagerDuty로 보내는 것입니다.

Warning 수준의 알림까지 전화로 받으면 잠을 잘 수 없습니다. Critical만 PagerDuty로, 나머지는 Slack으로 보내는 것이 좋습니다.

또한 Integration Key는 비밀 정보입니다. Git에 커밋하지 말고, 환경 변수로 관리해야 합니다.

정리 다시 김운영 씨의 이야기로 돌아가 봅시다. PagerDuty를 도입한 김운영 씨는 이제 안심하고 퇴근할 수 있게 됐습니다.

주말에도 당번이 정해져 있고, 문제가 생기면 자동으로 전화가 갑니다. PagerDuty를 제대로 설정하면 24시간 안정적인 서비스 운영이 가능합니다.

여러분도 오늘 배운 내용을 바탕으로 On-Call 시스템을 구축해 보세요.

실전 팁

💡 - Critical 알림만 PagerDuty로 보내세요. Warning은 Slack으로 충분합니다

  • 무료 플랜은 5명까지 사용 가능하므로 작은 팀에 적합합니다
  • Acknowledge 기능으로 중복 대응을 방지할 수 있습니다

5. rotation csv로 당번 관리

PagerDuty는 강력하지만, 김운영 씨의 팀은 3명뿐이었습니다. 유료 플랜을 쓰기엔 부담스럽고, 무료 플랜의 스케줄링은 제한적이었습니다.

"직접 당번 스크립트를 만들면 어떨까?" 김운영 씨는 CSV 파일로 간단한 로테이션 시스템을 구축하기로 했습니다.

당번 로테이션은 팀원들이 돌아가며 On-Call을 담당하는 시스템입니다. CSV 파일에 주차별 당번을 기록하고, 스크립트로 현재 당번을 확인해 알림을 보냅니다.

복잡한 도구 없이도 간단하게 구현할 수 있습니다.

다음 코드를 살펴봅시다.

# rotation.csv
week_start,oncall_engineer,backup_engineer
2025-12-01,kim@company.com,lee@company.com
2025-12-08,lee@company.com,park@company.com
2025-12-15,park@company.com,kim@company.com
2025-12-22,kim@company.com,lee@company.com

# get_oncall.py - 현재 당번 확인 스크립트
import csv
from datetime import datetime, timedelta

def get_current_oncall():
    today = datetime.now().date()
    # 오늘 날짜 가져오기
    with open('rotation.csv', 'r') as f:
        reader = csv.DictReader(f)
        for row in reader:
            week_start = datetime.strptime(row['week_start'], '%Y-%m-%d').date()
            week_end = week_start + timedelta(days=7)
            # 해당 주의 시작과 끝 계산
            if week_start <= today < week_end:
                return row['oncall_engineer'], row['backup_engineer']
    return None, None

if __name__ == '__main__':
    oncall, backup = get_current_oncall()
    print(f"Current: {oncall}, Backup: {backup}")

김운영 씨의 팀은 3명입니다. 김운영, 이백엔드, 박프론트 세 명이서 서비스를 운영하고 있습니다.

PagerDuty의 유료 플랜은 한 달에 수십만 원이 들어서 예산이 부담됩니다. 무료 플랜의 스케줄링 기능은 복잡한 로테이션을 지원하지 않습니다.

"우리 팀은 간단해. 매주 한 명씩 돌아가며 당번을 서면 돼." 김운영 씨는 생각했습니다.

복잡한 도구는 필요 없습니다. CSV 파일과 간단한 스크립트면 충분합니다.

당번 로테이션이란 무엇일까요? 쉽게 비유하자면, 당번 로테이션은 마치 청소 당번표와 같습니다. 학창 시절 교실 뒤에 붙어 있던 당번표를 떠올려보세요.

월요일은 1번, 화요일은 2번... 돌아가며 청소를 담당했습니다.

On-Call도 마찬가지입니다. 매주 또는 매일 한 명씩 돌아가며 담당합니다.

당번인 사람은 알림을 받고, 장애가 생기면 대응합니다. 당번이 아닌 사람은 편히 쉴 수 있습니다.

왜 CSV 파일인가? 데이터베이스를 쓸 수도 있고, 전용 도구를 쓸 수도 있습니다. 하지만 CSV 파일이 가장 간단합니다.

첫째, 누구나 편집할 수 있습니다. 엑셀이나 구글 스프레드시트로 열어서 수정하면 됩니다.

코드를 몰라도 됩니다. 둘째, Git으로 버전 관리가 쉽습니다.

누가 언제 당번표를 수정했는지 히스토리가 남습니다. 셋째, 백업과 공유가 간편합니다.

파일 하나만 복사하면 됩니다. CSV 파일 구조 위의 CSV 파일을 살펴보겠습니다.

첫 번째 줄은 헤더입니다. week_start는 해당 주의 시작 날짜, oncall_engineer는 주 당번, backup_engineer는 백업 당번입니다.

각 행은 한 주를 나타냅니다. 2025년 12월 1일부터 시작하는 주는 김운영 씨가 당번이고, 이백엔드 씨가 백업입니다.

다음 주는 이백엔드 씨가 당번이 되고, 박프론트 씨가 백업입니다. 이런 식으로 계속 돌아갑니다.

스크립트 작성 이제 현재 당번이 누구인지 확인하는 스크립트를 작성합니다. Python의 csv 모듈로 파일을 읽습니다.

datetime 모듈로 오늘 날짜를 가져옵니다. CSV 파일의 각 행을 순회하며, 오늘이 어느 주에 속하는지 확인합니다.

week_start부터 7일간이 해당 주입니다. 오늘이 그 범위 안에 들어가면, 해당 행의 oncall_engineerbackup_engineer를 반환합니다.

코드 분석 get_current_oncall() 함수를 자세히 봅시다. 먼저 datetime.now().date()로 오늘 날짜를 가져옵니다.

open('rotation.csv', 'r')로 파일을 열고, csv.DictReader로 읽습니다. 이렇게 하면 각 행이 딕셔너리 형태로 읽힙니다.

for 루프에서 각 행을 처리합니다. row['week_start']를 날짜 객체로 변환하고, 7일을 더해서 week_end를 계산합니다.

if week_start <= today < week_end 조건으로 오늘이 이번 주인지 확인합니다. 조건이 참이면 당번과 백업을 반환합니다.

어느 주에도 속하지 않으면 None, None을 반환합니다. 실무 활용 사례 실제 현업에서는 어떻게 활용할까요?

이 스크립트를 Alertmanager와 연동할 수 있습니다. 알림이 발생하면 스크립트를 실행해 현재 당번을 확인하고, 그 사람에게만 알림을 보냅니다.

당번이 아닌 사람은 알림을 받지 않으므로 잠을 방해받지 않습니다. 예를 들어 Alertmanager의 receiver를 동적으로 설정하는 Webhook을 만들 수 있습니다.

알림이 오면 Webhook이 get_oncall.py를 실행하고, 반환된 이메일로 PagerDuty 알림을 보냅니다. 백업 당번의 역할 주 당번이 휴가를 가거나 아프면 어떻게 할까요?

바로 백업 당번이 대신합니다. CSV에 backup_engineer 열을 추가한 이유입니다.

주 당번이 5분 내에 응답하지 않으면, 자동으로 백업 당번에게 에스컬레이션됩니다. 이렇게 해서 반드시 누군가 대응하도록 보장합니다.

자동화된 업데이트 CSV 파일을 매주 수동으로 업데이트하는 건 번거롭습니다. 스크립트로 자동화할 수 있습니다.

팀원 목록을 배열로 정의하고, 매주 자동으로 다음 사람으로 로테이션하는 스크립트를 작성합니다. Cron Job으로 매주 월요일 아침에 실행하면, 자동으로 당번표가 업데이트됩니다.

주의사항 초보자들이 흔히 하는 실수 중 하나는 날짜 계산을 잘못하는 것입니다. 주의 시작을 월요일로 할지, 일요일로 할지 명확히 정해야 합니다.

또한 년도가 바뀌는 시점도 고려해야 합니다. CSV 파일이 없거나 형식이 잘못되면 스크립트가 에러를 냅니다.

예외 처리를 추가해서 안전하게 만들어야 합니다. 정리 다시 김운영 씨의 이야기로 돌아가 봅시다.

CSV 로테이션 시스템을 구축한 김운영 씨는 팀원들에게 공유했습니다. "이제 구글 스프레드시트에서 당번표를 확인할 수 있어요." 모두 만족스러워했습니다.

간단한 CSV 파일과 스크립트로도 충분히 실용적인 당번 시스템을 만들 수 있습니다. 여러분도 오늘 배운 내용을 바탕으로 자신의 팀에 맞는 로테이션을 구축해 보세요.

실전 팁

💡 - CSV 파일은 구글 스프레드시트로 관리하면 팀원 모두 편집 가능합니다

  • 백업 당번을 지정해 유연하게 대응하세요
  • Cron Job으로 자동화하면 수동 관리 부담이 줄어듭니다

6. oncall.yml 완성과 runbook 링크

당번 시스템은 완성됐지만, 김운영 씨는 또 다른 문제에 직면했습니다. 새벽에 알림을 받은 당번 개발자가 "어떻게 대응해야 하죠?"라고 물어왔습니다.

매번 설명하기엔 너무 번거로웠습니다. "매뉴얼을 만들어야겠어." 김운영 씨는 Runbook을 작성하기로 했습니다.

oncall.yml은 On-Call 시스템의 모든 설정을 담은 최종 설정 파일입니다. 알림 규칙, 담당자, 에스컬레이션 정책을 정의하고, 각 알림마다 Runbook 링크를 추가해 대응 방법을 안내합니다.

Runbook은 장애 대응 매뉴얼로, 단계별로 무엇을 해야 하는지 문서화합니다.

다음 코드를 살펴봅시다.

# oncall.yml - 최종 통합 설정
alerts:
  - name: HighCPUUsage
    condition: cpu > 80% for 5m
    severity: warning
    oncall: "{{ get_current_oncall() }}"
    # 동적으로 현재 당번 가져오기
    escalation:
      - level: 1
        target: "{{ oncall_engineer }}"
        timeout: 5m
      - level: 2
        target: "{{ backup_engineer }}"
        timeout: 5m
    runbook: "https://wiki.company.com/runbooks/high-cpu"
    # 대응 매뉴얼 링크

  - name: DatabaseDown
    condition: db_up == 0 for 1m
    severity: critical
    escalation:
      - level: 1
        target: "{{ oncall_engineer }}"
        timeout: 3m
      - level: 2
        target: "{{ backup_engineer }}"
        timeout: 3m
      - level: 3
        target: "cto@company.com"
    runbook: "https://wiki.company.com/runbooks/database-down"

김운영 씨는 어느 토요일 새벽, 백업 당번이었습니다. 잠들어 있는데 전화벨이 울렸습니다.

주 당번인 이백엔드 씨가 응답하지 않아서 에스컬레이션된 것입니다. "CPU가 90%래요.

어떻게 해야 하죠?" PagerDuty 앱을 열어보니 "HighCPUUsage" 알림만 덩그러니 있었습니다. 무엇을 확인해야 할까요?

어떤 명령어를 실행해야 할까요? 반쯤 잠든 상태에서 판단하기 어려웠습니다.

"매번 이렇게 헤매면 안 되는데..." 김운영 씨는 다음 날 팀 회의에서 제안했습니다. "알림마다 대응 매뉴얼을 만들어요.

링크를 첨부해서 바로 볼 수 있게요." Runbook이란 무엇일까요? 쉽게 비유하자면, Runbook은 마치 응급처치 매뉴얼과 같습니다. 환자가 쓰러졌을 때 어떻게 해야 하는지 단계별로 적혀 있죠.

당황하지 않고 매뉴얼대로 따라하면 됩니다. Runbook은 장애 상황별 대응 절차를 문서화한 것입니다.

어떤 명령어를 실행할지, 어떤 로그를 확인할지, 누구에게 연락할지 상세히 기록합니다. 새벽에 잠이 덜 깬 상태에서도 따라할 수 있도록 명확해야 합니다.

왜 필요한가? 숙련된 개발자도 새벽 3시에는 판단력이 흐려집니다. 평소에는 당연히 아는 것도 긴장 상황에서는 잊어버립니다.

더 큰 문제는 신입 개발자가 처음으로 On-Call을 맡았을 때입니다. 한 스타트업에서는 신입 개발자가 첫 On-Call을 섰습니다.

새벽에 알림이 왔지만 어떻게 대응해야 할지 몰라서 1시간 동안 헤맸습니다. 결국 CTO를 깨워서 도움을 받았고, 서비스는 2시간 동안 중단됐습니다.

Runbook의 구조 바로 이런 문제를 해결하기 위해 Runbook을 작성합니다. Runbook은 보통 위키나 노션에 작성합니다.

각 알림마다 별도의 페이지를 만들고, URL을 알림에 첨부합니다. 알림을 받은 사람은 링크를 클릭해서 즉시 대응 방법을 확인할 수 있습니다.

Runbook의 기본 구조는 다음과 같습니다: - 증상: 무엇이 잘못됐는지 - 영향: 고객에게 어떤 영향이 있는지 - 확인 단계: 어떤 로그와 메트릭을 확인할지 - 대응 절차: 단계별로 무엇을 해야 하는지 - 복구 확인: 문제가 해결됐는지 확인하는 방법 - 사후 조치: 근본 원인 분석과 재발 방지책 oncall.yml 파일 구조 위의 코드를 한 줄씩 살펴보겠습니다. oncall.yml은 On-Call 시스템의 모든 설정을 통합한 파일입니다.

YAML 형식으로 작성하며, 가독성이 좋습니다. alerts 섹션에 알림들을 정의합니다.

첫 번째 알림은 HighCPUUsage입니다. condition에서 발생 조건을 정의하고, severity에서 심각도를 지정합니다.

oncall 필드는 동적으로 현재 당번을 가져옵니다. 앞서 작성한 get_current_oncall() 함수를 호출합니다.

escalation 섹션에서 에스컬레이션 정책을 정의합니다. Level 1은 주 당번, 5분 내에 응답 없으면 Level 2인 백업 당번에게 전달됩니다.

Runbook 링크 추가 핵심은 runbook 필드입니다. 위키 페이지의 URL을 입력합니다.

Slack이나 PagerDuty 알림에 이 링크가 함께 표시되므로, 클릭 한 번으로 대응 방법을 확인할 수 있습니다. DatabaseDown 알림은 더 심각합니다.

severity: critical로 설정했고, 에스컬레이션도 3단계까지 있습니다. Level 3는 CTO에게 전달됩니다.

데이터베이스 장애는 서비스 전체에 영향을 미치므로, 최고 책임자까지 알려야 합니다. Runbook 작성 예시 실제 Runbook을 어떻게 작성할까요?

HighCPUUsage Runbook의 예시입니다: --- 증상: 서버 CPU 사용률이 80%를 5분 이상 초과했습니다. 영향: 응답 시간이 느려지고, 타임아웃이 발생할 수 있습니다.

확인 단계:


4. 문제가 지속되면 인스턴스 추가 고려

실전 팁

💡 - Runbook은 간결하고 실행 가능하게 작성하세요. 명령어는 복사해서 바로 쓸 수 있어야 합니다

  • 알림마다 Runbook 링크를 첨부하면 대응 시간이 크게 줄어듭니다
  • 주기적으로 Runbook 훈련을 하면 실전 대응 능력이 향상됩니다

이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!

#DevOps#Alertmanager#PagerDuty#Slack#OnCall#DevOps,모니터링,알림

댓글 (0)

댓글을 작성하려면 로그인이 필요합니다.