DevOpsDevOps 학습 로드맵 · 5/9

Prometheus·Loki 관측 스택 구축과 장애 주입 실험 설계 절차

관측성(메트릭/로그/트레이스) 개념부터 kube-prometheus-stack 설치, Alertmanager 알림 라우팅, Loki 로그 보존 정책, 노드 다운·OOMKill·디스크풀 장애 주입 실험과 포스트모템 템플릿, 선택 확장인 OpenTelemetry 분산 트레이싱까지.

2026-08-0211 min read
#Prometheus#Grafana#Alertmanager#Loki#장애 주입#OpenTelemetry

목표

메트릭(Prometheus)·시각화(Grafana)·알림(Alertmanager)·로그(Loki)를 클러스터에 설치하고, 의도적으로 장애를 주입해 "알림이 실제로 오는지, 얼마나 걸리는지"를 검증한다. (선택 확장으로 분산 트레이싱까지 붙인다.)

개념: 관측성(Observability)이란 무엇인가

시스템이 커질수록 "지금 뭐가 잘못됐는지"를 눈으로 추측하는 게 불가능해진다. 관측성은 시스템이 내보내는 신호로 내부 상태를 외부에서 알아내는 능력이고, 보통 세 종류의 신호로 나뉜다 - 각각이 답하는 질문이 다르다.

신호답하는 질문이 시리즈의 도구
메트릭(Metrics)"지금 수치가 얼마인가" (에러율, 응답시간, CPU 등 시계열 숫자)Prometheus (수집) + Grafana (시각화)
로그(Logs)"그때 정확히 무슨 일이 있었나" (텍스트 기록)Loki
알림(Alerts)"지금 사람이 봐야 하는 상황인가" (메트릭이 임계치를 넘었을 때 통지)Alertmanager
(확장) 트레이스(Traces)"이 요청이 여러 서비스를 거치며 어디서 느려졌나"OpenTelemetry + Tempo (아래 확장 절 참고)

메트릭만으로는 "에러율이 올랐다"는 건 알아도 "왜"는 알 수 없고, 로그만 뒤지면 "왜"는 나오지만 "언제부터 이상했는지"를 미리 알 방법이 없다. 세 신호를 같이 둬야 서로의 빈틈을 메운다.

실제 구축 절차

1. kube-prometheus-stack 설치

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm install monitoring prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace \
  --set grafana.adminPassword=<시크릿으로 관리>

이 차트 하나로 Prometheus, Grafana, Alertmanager, node-exporter, kube-state-metrics가 함께 설치된다. api-server/inference-worker/metrics를 이미 노출하고 있다면(시리즈 2), ServiceMonitor로 수집 대상에 등록한다.

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: api-server
  labels: {release: monitoring}     # kube-prometheus-stack의 셀렉터와 맞춰야 수집됨
spec:
  selector:
    matchLabels: {app: api-server}
  endpoints:
    - port: http
      path: /metrics

2. Alertmanager - 알림 라우팅

apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: api-server-alerts
  labels: {release: monitoring}
spec:
  groups:
    - name: api-server
      rules:
        - alert: HighErrorRate
          expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.05
          for: 2m
          labels: {severity: warning}
          annotations:
            summary: "api-server 5xx 비율이 5% 초과"
# alertmanager config
route:
  receiver: slack-default
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 3h
receivers:
  - name: slack-default
    slack_configs:
      - api_url: <Slack Incoming Webhook URL>
        channel: "#alerts"

group_wait/group_interval이 "장애 알림이 늦게 오는" 원인이 되는 경우가 많다 - 값이 크면 초기 알림이 그만큼 지연된다. 실험 단계에서 이 값을 조정하며 지연 시간을 직접 재본다.

3. Loki - 로그 수집 + 보존 정책

helm repo add grafana https://grafana.github.io/helm-charts
helm install loki grafana/loki-stack \
  --namespace monitoring \
  --set promtail.enabled=true

보존 기간은 limits_config에서 설정한다 - 이 값 자체가 나중에 ISMS-P 2.9(운영관리) 증적 자료가 된다.

limits_config:
  retention_period: 720h   # 30일
compactor:
  retention_enabled: true
  retention_delete_delay: 2h

4. 장애 주입 실험 설계 (3종 이상 택)

카오스 엔지니어링이란: 장애가 언젠가 난다는 걸 전제로, 실제로 터지기 전에 통제된 환경에서 미리 장애를 일으켜보고 시스템과 사람(알림·대응 절차)이 제대로 반응하는지 검증하는 방법론이다. 목적은 "장애를 일으키는 것"이 아니라 **"장애가 났을 때 탐지까지 얼마나 걸리는지를 미리 재보는 것"**이다 - 이 시리즈의 모든 실험은 그 시간을 재는 게 진짜 목적이다.

각 실험은 주입 → 관측 → 기록의 순서로 진행하고, 시작 시각을 먼저 기록해야 나중에 "알림까지 걸린 시간"을 정확히 잴 수 있다.

노드 다운

# 실험 대상 워커 노드에서
sudo systemctl stop kubelet
# 또는 VM 자체를 강제 종료

# 관측할 것
# - kubectl get nodes 에서 NotReady로 바뀌는 시점
# - 해당 노드의 파드가 다른 노드로 재스케줄되기까지 걸리는 시간 (기본 pod-eviction-timeout 5분)
# - Alertmanager 알림이 Slack에 도착하는 시점

OOMKill

리눅스 커널은 메모리가 부족해지면 임의로 프로세스를 골라 강제 종료해서 시스템 전체가 멎는 걸 막는다 - 이 메커니즘을 OOM(Out Of Memory) Killer라 부른다. 컨테이너에 메모리 limits를 걸어두면, 그 컨테이너가 한도를 넘었을 때 커널이 호스트 전체 대신 그 컨테이너만 골라 종료한다(OOMKilled).

# 의도적으로 낮은 메모리 제한을 건 테스트 파드
resources:
  limits: {memory: "64Mi"}
kubectl run oom-test --image=polinux/stress --limits=memory=64Mi -- \
  stress --vm 1 --vm-bytes 256M
# kubectl describe pod oom-test 에서 OOMKilled 상태 확인
# Prometheus의 container_oom_events_total 메트릭에 반영되는 시점 확인

디스크 풀

# 워커 노드에서 디스크를 의도적으로 채움
fallocate -l 10G /tmp/fillfile
# kubelet의 disk pressure 감지 → 노드가 파드 축출(evict)을 시작하는지 확인
# node-exporter의 node_filesystem_avail_bytes 알림이 임계치를 넘는 시점 확인

RabbitMQ 장애

kubectl delete pod rabbitmq-0 --grace-period=0 --force
# 시리즈 2에서 만든 ack/nack 파이프라인이 이 상황에서 실제로 메시지를 보존하는지 재검증

5. 포스트모템 문서 템플릿

실험마다 아래 형식으로 기록한다.

# 포스트모템: <실험명> (YYYY-MM-DD)

## 타임라인
- 00:00 장애 주입 (구체적 명령/조작)
- 00:XX 첫 이상 신호 감지 (메트릭/로그상 변화)
- 00:XX 알림 도착 (Slack 등)
- 00:XX 자동/수동 복구 완료

## 원인
(장애가 실제로 무엇 때문에 발생했는지)

## 탐지 공백
(장애 발생부터 알림 도착까지 얼마나 걸렸는지, 왜 그만큼 걸렸는지)

## 재발 방지
(알림 규칙 조정, 임계치 변경, 자동 복구 추가 등 - 실행한 조치)

검증 방법

각 실험에서 반드시 남겨야 하는 숫자 3가지: 장애 발생 시각, 첫 메트릭/로그 이상 시각, 알림 도착 시각. 이 세 시각의 차이가 곧 "탐지 공백"이고, 다음 단계(알림 규칙 튜닝)의 기준값이 된다.

(선택 확장) OpenTelemetry로 분산 트레이싱 붙이기

분산 트레이싱이란: 요청 하나가 api-server → RabbitMQ → inference-worker → PostgreSQL을 거치는 이 프로젝트에서, 메트릭과 로그만으로는 "이 요청이 정확히 어느 구간에서 느려졌는지"를 알기 어렵다 - 각 서비스의 로그를 시간으로 짐작해서 이어 붙여야 한다. 트레이스는 요청 하나에 고유 ID(trace ID)를 붙여서, 그 요청이 거친 모든 서비스의 처리 구간(span)을 하나로 이어 보여준다.

**OpenTelemetry(OTel)**는 이 계측을 위한 표준 규격이고, Tempo는 그 트레이스 데이터를 저장·조회하는 백엔드다.

helm repo add grafana https://grafana.github.io/helm-charts
helm install tempo grafana/tempo --namespace monitoring
# api-server - OTel 계측 최소 예시
from opentelemetry import trace
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import OTLPSpanExporter
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import BatchSpanProcessor

provider = TracerProvider()
provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter(endpoint="tempo.monitoring:4317")))
trace.set_tracer_provider(provider)
tracer = trace.get_tracer(__name__)

@app.post("/jobs")
def create_job(payload: JobCreate):
    with tracer.start_as_current_span("create_job"):
        job_id = save_job_as_pending(payload)
        publish_to_queue("jobs.upload", {"job_id": job_id, "trace_id": trace.get_current_span().get_span_context().trace_id})
        return {"job_id": job_id, "status": "PENDING"}

메시지를 큐에 넣을 때 trace_id를 함께 실어 보내면, inference-worker가 그 trace_id로 이어서 span을 기록할 수 있다 - 큐를 거치는 비동기 구간까지 하나의 트레이스로 연결하는 게 핵심이다.

검증: Grafana에서 특정 요청의 trace ID로 조회해, 게이트웨이 진입부터 DB 기록까지 각 구간이 몇 ms씩 걸렸는지 한 화면에서 확인되는지 본다. 장애 주입 실험(4번) 때 이 트레이스가 "어느 구간에서 지연이 발생했는지"를 로그보다 빠르게 짚어주는지 비교해본다.

체크리스트

  • kube-prometheus-stack 설치, 서비스 메트릭 수집
  • Alertmanager 알림 라우팅 (Slack 등)
  • Loki 로그 수집 + 보존 기간 정책 설정
  • 장애 주입 실험 3종 이상 실행 (노드 다운/OOMKill/디스크풀/RabbitMQ 중 택3)
  • 실험마다 포스트모템 문서 작성
  • (선택 확장) OpenTelemetry + Tempo로 분산 트레이싱 연결, 장애 실험 때 활용도 비교