본문으로 건너뛰기
AIDevOps
  • Learn
  • Learning Paths
  • Practice
  • Open Source
  • Books
  • Engineering

    AI DevOpsAI 서비스 개발·운영 전체 지도LLMOpsLLM 배포·평가·관측실전 프로젝트AI Agent 프로젝트 실습

    Knowledge

    Docs기술 문서 모음Blog엔지니어링 아티클Plogger개발 기록 피드

    Validate

    Certification3단계 역량 인증 · 준비 중
AI Models
LlamaMistralGemmaDeepSeekQwen
🐳 DevOps
DevOps 입문 & 로드맵LinuxDockerCI/CD|Kubernetes 기본K8s 심화/실무PrometheusGrafana
🤖 AI 실전 개발
AI 실전 입문 & 로드맵Hugging FaceLangChainLlamaIndexLLMOps|LangGraphMCPMulti-AgentAgent Evaluation
🧠 AI Core
AI 입문 & 로드맵ML FundamentalsLLM Fundamentals|Python AIC++|PyTorchTensorFlowJAX
🧠 AI Agent 개발
금융 AI AgentLLM API 서버주식 투자 AgentAIOps AI Agent교육 AI Agent코딩 AI Agent
🌱 Spring Cloud
Spring 입문 & 로드맵Spring Cloud GatewaySpring BootJava|Spring AISpring SecuritySpring BatchSpring JPA
🧱 인프라
인프라 입문 & 로드맵NginxRedis
☁️ 클라우드
클라우드 입문 & 로드맵AWSGCPAzureNCPCloudflare
🎨 Frontend
Frontend 입문 & 로드맵JavaScriptTypeScript|ReactNext.js|VueNuxt
📱 Mobile
Mobile 입문 & 로드맵KotlinAndroidFlutter
⚙️ Backend
Backend 입문 & 로드맵Python 기본FastAPIDjangoFlask|CGoGinNode.js
💾 Database
DB 입문 & 로드맵공통 SQLOracleMySQLPostgreSQL|MongoDB벡터 DB
🧪 검증
k6JMeternGrinder
AIDevOps

Engineering AI. From Code to Production.
AI와 AI Agent를 개발하고 운영하기 위한 엔지니어링 학습 플랫폼

Learn

  • 전체 가이드
  • Learning Paths
  • Practice
  • Books

Resources

  • AI DevOps
  • LLMOps
  • 실전 프로젝트
  • Docs
  • Blog
  • Plogger
  • Open Source
  • Certification (준비 중)

Start Here

  • AI Core 로드맵
  • AI 실전 개발 로드맵
  • Spring Cloud 로드맵
  • DevOps 로드맵
  • 인프라 로드맵

 

  • 클라우드 로드맵
  • Frontend 로드맵
  • Mobile 로드맵
  • Backend 로드맵
  • Database 로드맵
© 2026 AI DevOps Korea. All rights reserved.
이용약관개인정보처리방침Sitemaptestforge.kr
  1. Home
  2. Learn
  3. DevOps
  4. Prometheus
모니터링 & 관찰 가능성 가이드

📊 Prometheus 완전 가이드

Visitors

Prometheus + Grafana로 서버와 애플리케이션을 모니터링하세요. 메트릭 수집, Exporter 생태계, PromQL, Grafana 대시보드 프로비저닝, AlertManager 알림 라우팅, kube-prometheus-stack 설치·CRD 확장·운영까지 완전 가이드.

  • Advanced · 심화
  • 업데이트 2026.09.20
  • 약 39분 읽기
  • 15개 섹션
  • 예제 코드 35개
  • 웹 IDE 실습 제공
📊

Prometheus 웹 IDE

설치 없이 브라우저에서 코드를 실행하고 단계별 예제로 익혀보세요.

웹 IDE 열기 →
메트릭 수집 & Exporter 운영PromQL 쿼리 & 레코딩 규칙Grafana 대시보드 as CodeAlertManager 알림 라우팅kube-prometheus-stack 설치 & 프로덕션 운영

관련 프레임워크 & 개발환경

📈Grafana→☸️Kubernetes 기본→☸️K8s 심화/실무→🐳Docker→CICI/CD→

목차

0 / 17
  1. 가이드 사용법
  2. 구조 다이어그램
  3. 관찰 가능성이란?
  4. Docker Compose 설치
  5. Exporter 생태계 & 커스텀 메트릭
  6. 헬스체크 vs 메트릭 — Probe와 Actuator
  7. PromQL 기초 & 레코딩 규칙
  8. Grafana 연동
  9. AlertManager 알림
  10. CRD란? — Kubernetes API 확장의 기본
  11. 설치 전 준비 — 사전 요구사항 & 클러스터 사이징
  12. Kubernetes 통합 — kube-prometheus-stack
  13. CRD 확장 — ServiceMonitor · PodMonitor · Probe
  14. 검증 · 업그레이드 · 트러블슈팅
  15. Prometheus 설계
  16. 운영 기준
  17. 검증 전략
목차 17개 섹션
  1. 가이드 사용법
  2. 구조 다이어그램
  3. 관찰 가능성이란?
  4. Docker Compose 설치
  5. Exporter 생태계 & 커스텀 메트릭
  6. 헬스체크 vs 메트릭 — Probe와 Actuator
  7. PromQL 기초 & 레코딩 규칙
  8. Grafana 연동
  9. AlertManager 알림
  10. CRD란? — Kubernetes API 확장의 기본
  11. 설치 전 준비 — 사전 요구사항 & 클러스터 사이징
  12. Kubernetes 통합 — kube-prometheus-stack
  13. CRD 확장 — ServiceMonitor · PodMonitor · Probe
  14. 검증 · 업그레이드 · 트러블슈팅
  15. Prometheus 설계
  16. 운영 기준
  17. 검증 전략

가이드 사용법

읽는 방향

Prometheus를 실무 흐름으로 이해하기

Prometheus + Grafana로 서버와 애플리케이션을 모니터링하세요. 메트릭 수집, Exporter 생태계, PromQL, Grafana 대시보드 프로비저닝, AlertManager 알림 라우팅, kube-prometheus-stack 설치·CRD 확장·운영까지 완전 가이드. 이 가이드는 개념을 나열하기보다, 실제 프로젝트에서 판단해야 하는 순서대로 내용을 따라갈 수 있게 구성했습니다.

핵심 관점

인프라 / 운영

설치 명령을 외우기보다 트래픽, 런타임, 관측, 장애 대응이 어떤 순서로 이어지는지 파악합니다.

메트릭 수집 & Exporter 운영PromQL 쿼리 & 레코딩 규칙Grafana 대시보드 as CodeAlertManager 알림 라우팅kube-prometheus-stack 설치 & 프로덕션 운영

구조 다이어그램

글로 읽은 내용을 머릿속에 오래 남기려면 먼저 흐름을 그림으로 잡는 편이 좋습니다. 아래 두 그림은 Prometheus를 학습할 때 계속 되돌아볼 수 있는 기준 지도입니다.

학습 흐름

다이어그램 렌더링 중…

아키텍처 관점

다이어그램 렌더링 중…

관찰 가능성 3가지 기둥

Prometheus를 처음 펼칠 때는 세부 명령보다 큰 그림이 먼저입니다. 이 섹션에서는 앞으로 배울 개념들이 어떤 문제를 풀기 위해 등장했는지부터 잡아봅니다.

서비스가 정상 동작하는지 확인하려면 서로 다른 질문에 답하는 세 가지 신호가 필요합니다. 하나만으로는 장애의 전체 그림을 볼 수 없기 때문에, 실무에서는 이 세 신호를 함께 수집하고 서로 연결해 봅니다.
신호도구질문
Metrics (메트릭)Prometheus, Grafana지금 얼마나 많은 요청이 오는가?
Logs (로그)Loki, ELK무엇이 잘못되었는가?
Traces (추적)Jaeger, Tempo어디서 느린가?

Docker Compose 설치

여기서는 Docker Compose 설치을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

prometheus.yml은 "무엇을, 얼마나 자주, 어디서 읽어올지"를 정의하는 핵심 설정입니다. scrape_configs로 수집 대상을 등록하고, rule_files로 레코딩/알림 규칙 파일을 불러오고, alerting.alertmanagers로 AlertManager 주소를 연결합니다.
docker-compose.ymlYAML
services:
  prometheus:
    image: prom/prometheus:latest
    ports: ["9090:9090"]
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - ./alert_rules.yml:/etc/prometheus/alert_rules.yml
      - promdata:/prometheus
    command:
      - --config.file=/etc/prometheus/prometheus.yml
      - --web.enable-lifecycle          # curl -X POST 로 재시작 없이 설정 리로드

  grafana:
    image: grafana/grafana:latest
    ports: ["3000:3000"]
    environment:
      GF_SECURITY_ADMIN_PASSWORD: admin
    volumes:
      - grafdata:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning   # 데이터소스·대시보드 as Code

  alertmanager:
    image: prom/alertmanager:latest
    ports: ["9093:9093"]
    volumes:
      - ./alertmanager.yml:/etc/alertmanager/alertmanager.yml

  node-exporter:
    image: prom/node-exporter:latest
    ports: ["9100:9100"]

volumes:
  promdata:
  grafdata:
prometheus.ymlYAML
global:
  scrape_interval: 15s        # 기본 수집 주기
  evaluation_interval: 15s    # 레코딩/알림 규칙 평가 주기

rule_files:
  - "alert_rules.yml"         # 레코딩 규칙 + 알림 규칙

alerting:
  alertmanagers:
    - static_configs:
        - targets: ["alertmanager:9093"]

scrape_configs:
  - job_name: prometheus
    static_configs:
      - targets: ["localhost:9090"]

  - job_name: node
    static_configs:
      - targets: ["node-exporter:9100"]

  - job_name: myapp
    metrics_path: /metrics
    static_configs:
      - targets: ["myapp:8080"]
        labels: { env: production, team: backend }
BASH
docker compose up -d

# 수집 대상(Target) 상태 확인 — UP이어야 정상
curl -s localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health}'

# 설정 파일만 리로드 (컨테이너 재시작 없이 반영, --web.enable-lifecycle 필요)
curl -X POST localhost:9090/-/reload

# 룰 파일 문법 검증 (배포 전 CI에서 실행 권장)
docker run --rm -v $(pwd):/rules prom/prometheus:latest \
  promtool check rules /rules/alert_rules.yml

Exporter 생태계 & 커스텀 메트릭

여기서는 Exporter 생태계 & 커스텀 메트릭을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Prometheus는 pull 모델입니다. Prometheus가 각 대상의 /metrics 엔드포인트를 주기적으로 긁어오므로, 모니터링하려는 시스템마다 그에 맞는 exporter를 배치해 메트릭을 텍스트 형식으로 노출해야 합니다. 직접 만든 서비스는 언어별 client 라이브러리로 원하는 지표를 커스텀 메트릭으로 노출할 수 있습니다.
app_metrics.pyPYTHON
from prometheus_client import Counter, Histogram, start_http_server
import time

# Counter — 누적 증가만 하는 값 (요청 수, 에러 수)
REQUEST_COUNT = Counter(
    "http_requests_total", "Total HTTP requests",
    ["method", "endpoint", "status"]
)

# Histogram — 분포 측정 (응답시간 p50/p95/p99 계산용 버킷)
REQUEST_LATENCY = Histogram(
    "http_request_duration_seconds", "Request latency",
    ["endpoint"], buckets=[0.05, 0.1, 0.3, 0.5, 1, 2, 5]
)

def handle_request(endpoint: str):
    start = time.time()
    try:
        ...  # 실제 처리 로직
        REQUEST_COUNT.labels("GET", endpoint, "200").inc()
    finally:
        REQUEST_LATENCY.labels(endpoint).observe(time.time() - start)

start_http_server(8080)   # /metrics 엔드포인트 자동 노출
blackbox-scrape.ymlYAML
# blackbox_exporter — 외부 관점에서 엔드포인트 가용성을 확인 (synthetic monitoring)
# blackbox.yml — exporter 자체 설정
modules:
  http_2xx:
    prober: http
    timeout: 5s
    http:
      valid_status_codes: [200]
      method: GET

---
# prometheus.yml에 추가할 scrape job — 실제 타깃은 params.target으로 전달
scrape_configs:
  - job_name: blackbox
    metrics_path: /probe
    params:
      module: [http_2xx]
    static_configs:
      - targets:
          - https://api.example.com/health
          - https://example.com
    relabel_configs:
      - source_labels: [__address__]
        target_label: __param_target
      - source_labels: [__param_target]
        target_label: instance
      - target_label: __address__
        replacement: blackbox-exporter:9115   # 실제 프로브를 수행하는 exporter 주소로 리라우팅
Exporter수집 대상기본 포트
node_exporter호스트 CPU · 메모리 · 디스크 · 네트워크9100
cAdvisor컨테이너별 리소스 사용량 (Docker/K8s)8080
blackbox_exporterHTTP/TCP/ICMP 프로브 — 엔드포인트 가용성·응답시간9115
mysqld_exporter / postgres_exporterDB 커넥션·슬로우쿼리·복제 지연9104 / 9187
redis_exporterRedis 메모리·커맨드 처리량·hit rate9121
kube-state-metricsK8s 오브젝트 상태 (Pod/Deployment/PVC 등)8080

헬스체크 vs 메트릭 — Probe와 Actuator

여기서는 헬스체크 vs 메트릭 — Probe와 Actuator을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Kubernetes의 Liveness/Readiness Probe는 Prometheus가 스크레이프하는 대상이 아닙니다. kubelet이 직접 애플리케이션의 헬스체크 엔드포인트를 호출해 "재시작할지(liveness)", "트래픽을 받을지(readiness)"만 판단하는 이진(UP/DOWN) 신호이고, Prometheus는 그와 별개로 /metrics 엔드포인트에서 시계열 수치를 긁어와 추세를 분석·알림하는 신호입니다. 같은 애플리케이션이 두 종류의 엔드포인트를 동시에 노출하는 경우가 많다 보니 "헬스체크"와 "메트릭"을 같은 것으로 착각하기 쉽습니다.
다이어그램 렌더링 중…
application.yml — Spring Boot ActuatorYAML
management:
  endpoints:
    web:
      exposure:
        include: health, prometheus, metrics   # 필요한 엔드포인트만 명시적으로 노출
  endpoint:
    health:
      probes:
        enabled: true   # /actuator/health/liveness, /actuator/health/readiness를 K8s용으로 분리
  prometheus:
    metrics:
      export:
        enabled: true    # micrometer 메트릭을 Prometheus 형식(/actuator/prometheus)으로 노출
deployment.yaml — 두 엔드포인트를 각자의 용도로 연결YAML
spec:
  containers:
  - name: myapp
    livenessProbe:
      httpGet: { path: /actuator/health/liveness, port: 8080 }
      periodSeconds: 10
    readinessProbe:
      httpGet: { path: /actuator/health/readiness, port: 8080 }
      periodSeconds: 5
---
# prometheus.yml (또는 ServiceMonitor)는 /actuator/prometheus를 별도로 scrape
scrape_configs:
  - job_name: myapp
    metrics_path: /actuator/prometheus
    static_configs:
      - targets: ["myapp:8080"]
PromQL — probe 실패(재시작)를 시계열로 관측TEXT
# 최근 15분간 재시작이 3회 이상 발생한 컨테이너 — liveness probe 실패가 반복되고 있다는 신호
increase(kube_pod_container_status_restarts_total[15m]) >= 3
항목Liveness/Readiness ProbePrometheus 메트릭
호출 주체kubelet (K8s 내부)Prometheus 서버 (외부에서 주기적 scrape)
값의 형태이진 — 성공/실패(UP/DOWN)시계열 수치 — 추세·비율·분포 계산 가능
실패 시 결과컨테이너 재시작 또는 Service에서 즉시 제외즉각적인 조치 없음 — 규칙에 따라 Alertmanager가 알림
목적"지금 이 순간 이 인스턴스가 정상인가""시간에 따라 시스템이 어떻게 변하고 있는가"

Tip

  • 뒤에 나올 k8s-crds 섹션의 Prometheus Operator "Probe" CRD는 이름이 같을 뿐 완전히 다른 개념입니다 — Kubernetes의 liveness/readiness probe가 아니라, blackbox_exporter로 외부 URL의 가용성을 원격에서 검사하는 리소스입니다. "Probe"라는 단어를 볼 때는 항상 어느 맥락인지(kubelet 헬스체크 vs blackbox 원격 점검) 확인하세요.
  • Actuator의 /actuator/health는 DB·디스크 등 의존성까지 확인해 무거울 수 있으므로, probes.enabled=true로 liveness/readiness를 분리하면 liveness는 "프로세스가 살아있는가"만 가볍게, readiness는 "의존성까지 포함해 트래픽을 받을 준비가 됐는가"를 확인하도록 나눌 수 있습니다.

PromQL 기초 & 레코딩 규칙

여기서는 PromQL 기초 & 레코딩 규칙을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

counter 타입은 재시작하면 0으로 리셋될 수 있어 값 자체보다 rate()로 증가 속도를 봐야 합니다. 대시보드에서 자주 쓰는 복잡한 쿼리는 레코딩 규칙으로 미리 계산해두면 쿼리 시점의 부하를 줄이고 응답도 빨라집니다.
PromQL 예제TEXT
# 초당 HTTP 요청 수 (5분 평균)
rate(http_requests_total[5m])

# 에러율 (4xx + 5xx)
sum(rate(http_requests_total{status=~"4..|5.."}[5m]))
/ sum(rate(http_requests_total[5m]))

# 엔드포인트별 p95 응답시간
histogram_quantile(0.95, sum by (le, endpoint) (rate(http_request_duration_seconds_bucket[5m])))

# CPU 사용률
100 - (avg(rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

# 최근 1시간 내 재시작한 Pod (K8s)
increase(kube_pod_container_status_restarts_total[1h]) > 0
alert_rules.yml (recording group)YAML
groups:
  - name: myapp.recording-rules
    interval: 30s
    rules:
      # 자주 조회하는 무거운 쿼리를 미리 계산해 job:metric:operation 이름 규칙으로 저장
      - record: job:http_requests:rate5m
        expr: sum by (job) (rate(http_requests_total[5m]))

      - record: job:http_errors:ratio5m
        expr: |
          sum by (job) (rate(http_requests_total{status=~"5.."}[5m]))
          / sum by (job) (rate(http_requests_total[5m]))

      - record: job:http_request_duration:p95_5m
        expr: histogram_quantile(0.95, sum by (job, le) (rate(http_request_duration_seconds_bucket[5m])))
함수/연산용도주의점
rate(v[5m])5분 구간의 초당 평균 증가율counter 전용. 카운터 리셋을 자동 보정
irate(v[5m])가장 최근 두 샘플만으로 순간 증가율 계산그래프 노이즈가 큼 — 대시보드보다 알림 임계값에는 부적합
histogram_quantile()histogram 버킷으로 백분위수(p95/p99) 근사 계산buckets 경계값 설계가 정확도를 좌우
sum by (label)(...)특정 라벨 기준으로만 그룹핑해 합산by와 without을 헷갈리면 카디널리티 폭발 위험

Grafana 연동

여기서는 Grafana 연동을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

📈
Prometheus 데이터소스 연결과 대시보드 provisioning만 다룹니다. 패널 제작, 변수, Unified Alerting 등 Grafana 자체를 깊이 배우려면 Grafana 가이드를 참고하세요.
Grafana UI에서 수동으로 데이터소스·대시보드를 클릭해 만들면 재현이 안 됩니다. Provisioning(파일 기반 자동 구성)으로 데이터소스와 대시보드를 코드로 관리하면 Grafana 컨테이너가 새로 뜨거나 재배포되어도 동일한 상태가 자동 복원됩니다. 클러스터가 여러 개라면 Prometheus의 external_labels로 각 클러스터를 식별시키고, 클러스터별 데이터소스 등록 또는 $cluster 템플릿 변수로 대시보드에서 전환할 수 있게 구성해야 합니다.
provisioning/datasources/prometheus.ymlYAML
apiVersion: 1
datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    jsonData:
      timeInterval: 15s          # global.scrape_interval과 맞춰두면 그래프가 자연스러움
      httpMethod: POST
provisioning/dashboards/default.ymlYAML
apiVersion: 1
providers:
  - name: default
    folder: "Services"
    type: file
    updateIntervalSeconds: 30   # 파일 변경을 주기적으로 감지해 자동 리로드
    options:
      path: /etc/grafana/provisioning/dashboards/files
      foldersFromFilesStructure: true
files/myapp-red-metrics.json (핵심 필드 발췌)JSON
{
  "title": "MyApp - RED Metrics",
  "templating": {
    "list": [
      { "name": "job", "type": "query", "query": "label_values(http_requests_total, job)" }
    ]
  },
  "panels": [
    {
      "title": "Request Rate",
      "type": "timeseries",
      "targets": [
        { "expr": "sum(rate(http_requests_total{job=\"$job\"}[5m]))", "legendFormat": "req/s" }
      ]
    },
    {
      "title": "Error Ratio",
      "type": "timeseries",
      "targets": [
        { "expr": "job:http_errors:ratio5m{job=\"$job\"}", "legendFormat": "error %" }
      ],
      "fieldConfig": { "defaults": { "unit": "percentunit", "thresholds": { "steps": [
        { "color": "green", "value": 0 }, { "color": "red", "value": 0.05 }
      ]}}}
    },
    {
      "title": "P95 Duration",
      "type": "timeseries",
      "targets": [
        { "expr": "job:http_request_duration:p95_5m{job=\"$job\"}", "legendFormat": "p95" }
      ]
    }
  ]
}
BASH
# 대시보드가 정상 로드됐는지 API로 확인
curl -s -u admin:admin localhost:3000/api/search?query=RED | jq '.[].title'

# 대시보드 JSON을 코드로 export (버전 관리에 커밋)
curl -s -u admin:admin localhost:3000/api/dashboards/uid/<uid> | jq '.dashboard' > myapp-red-metrics.json
prometheus.yml (cluster 식별 라벨)YAML
# 클러스터가 여러 개면, 각 Prometheus가 자기 자신을 어느 클러스터인지 스스로 표시해야
# 나중에 Grafana나 중앙 저장소에서 클러스터별로 구분·필터링할 수 있습니다.
global:
  external_labels:
    cluster: prod-seoul       # 클러스터마다 고유한 이름 (prod-seoul, prod-tokyo, staging ...)
    region: ap-northeast-2
provisioning/datasources/multi-cluster.ymlYAML
# 방식 A — 클러스터별로 Prometheus 데이터소스를 따로 등록
# 대시보드 상단의 데이터소스 드롭다운으로 클러스터를 전환하는 구조
apiVersion: 1
datasources:
  - name: Prometheus-Seoul
    uid: prom-seoul
    type: prometheus
    access: proxy
    url: http://prometheus-seoul.monitoring.svc:9090
    jsonData: { timeInterval: 15s }

  - name: Prometheus-Tokyo
    uid: prom-tokyo
    type: prometheus
    access: proxy
    url: http://prometheus-tokyo.monitoring.svc:9090
    jsonData: { timeInterval: 15s }
cluster-selector-panel.json (핵심 필드 발췌)JSON
{
  "templating": {
    "list": [
      {
        "name": "datasource",
        "type": "datasource",
        "query": "prometheus",
        "current": { "text": "Prometheus-Seoul", "value": "prom-seoul" }
      },
      {
        "name": "cluster",
        "type": "query",
        "datasource": "${datasource}",
        "query": "label_values(up, cluster)",
        "refresh": 2
      }
    ]
  },
  "panels": [
    {
      "title": "Cluster Node Count",
      "type": "stat",
      "datasource": "${datasource}",
      "targets": [
        { "expr": "count(up{job=\"node\", cluster=\"$cluster\"} == 1)" }
      ]
    }
  ]
}
values.yaml (커뮤니티 대시보드 자동 임포트)YAML
# kube-prometheus-stack — grafana.com의 검증된 클러스터 대시보드를 gnetId로 자동 로드
# (Kubernetes 통합 섹션의 helm install -f values.yaml 에 추가)
grafana:
  dashboardProviders:
    dashboardproviders.yaml:
      apiVersion: 1
      providers:
        - name: community
          orgId: 1
          folder: "Community"
          type: file
          options:
            path: /var/lib/grafana/dashboards/community
  dashboards:
    community:
      k8s-cluster-monitoring:
        gnetId: 315            # Kubernetes cluster monitoring (via Prometheus) — 클러스터 전체 개요
        revision: 3
        datasource: Prometheus
      node-exporter-full:
        gnetId: 1860           # Node Exporter Full — 노드별 CPU/메모리/디스크/네트워크 상세
        revision: 37
        datasource: Prometheus
      # revision은 grafana.com/grafana/dashboards/<gnetId> 페이지에서 최신 값 확인 후 갱신
BASH
# Docker Compose 환경 등 UI로 직접 임포트할 때
# Grafana → Dashboards → New → Import → ID 입력 (315 또는 1860) → 데이터소스 선택

# 이미 설치된 커뮤니티 대시보드를 API로 확인
curl -s -u admin:admin localhost:3000/api/search?query=Kubernetes | jq '.[].title'

# 클러스터 목록 확인 (external_labels.cluster가 붙은 모든 클러스터)
curl -s -u admin:admin --data-urlencode 'query=label_values(up, cluster)' \
  localhost:3000/api/datasources/proxy/uid/prom-seoul/api/v1/query
구성 요소역할파일 위치 (기본값)
Data source provisioningPrometheus 등 데이터소스를 UI 클릭 없이 자동 등록/etc/grafana/provisioning/datasources/*.yml
Dashboard provisioning대시보드 JSON을 폴더 기준으로 자동 로드/etc/grafana/provisioning/dashboards/*.yml
Template variable$job, $instance 등으로 대시보드를 파라미터화대시보드 JSON의 templating.list
Folder / 권한팀·서비스별 대시보드 폴더 분리, RBAC으로 편집 권한 제한Grafana 조직 설정
Multi-cluster datasource클러스터별 Prometheus를 별도 데이터소스로 등록해 상단 드롭다운으로 전환provisioning/datasources/*.yml
Community 대시보드 임포트검증된 커뮤니티 대시보드를 grafana.com ID로 즉시 가져오기Dashboards → New → Import (또는 gnetId 프로비저닝)

AlertManager 알림

여기서는 AlertManager 알림을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Prometheus는 규칙(rule)이 조건을 만족하면 알림을 발생시키기만 하고, 그 알림을 "누구에게 어떻게" 보낼지는 AlertManager가 담당합니다. 라우팅 트리로 심각도별 수신자를 분리하고, 같은 알림이 반복 발송되지 않도록 grouping·inhibition을 설정하는 것이 핵심입니다.
alert_rules.yml (alerting group)YAML
groups:
  - name: myapp.alerts
    rules:
      - alert: HighErrorRate
        expr: job:http_errors:ratio5m > 0.05
        for: 5m                          # 5분 이상 지속돼야 발화 — 순간 스파이크로 인한 오탐 방지
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.job }} 에러율 {{ $value | humanizePercentage }}"
          runbook_url: "https://wiki.internal/runbooks/high-error-rate"

      - alert: HighMemoryUsage
        expr: (node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes) / node_memory_MemTotal_bytes > 0.9
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "{{ $labels.instance }} 메모리 사용률 90% 초과"

      - alert: PodCrashLooping
        expr: increase(kube_pod_container_status_restarts_total[15m]) > 3
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "{{ $labels.namespace }}/{{ $labels.pod }} 반복 재시작 중"
alertmanager.ymlYAML
route:
  receiver: default-webhook
  group_by: [alertname, job]
  group_wait: 30s           # 그룹 생성 후 30초 동안 관련 알림을 더 모아서 발송
  group_interval: 5m        # 같은 그룹에 새 알림이 추가됐을 때 재발송 최소 간격
  repeat_interval: 4h       # 미해결 알림 재발송 주기
  routes:
    - matchers: ["severity = critical"]
      receiver: slack-critical
      continue: false
    - matchers: ["severity = warning"]
      receiver: slack-warning

inhibit_rules:
  # critical 알림이 켜져 있으면 같은 job의 warning 알림은 노이즈이므로 억제
  - source_matchers: ["severity = critical"]
    target_matchers: ["severity = warning"]
    equal: [job]

receivers:
  - name: default-webhook
    webhook_configs:
      - url: http://ops-bot:9000/alert

  - name: slack-critical
    slack_configs:
      - api_url: "${SLACK_WEBHOOK_URL}"
        channel: "#alerts-critical"
        title: "{{ .CommonAnnotations.summary }}"
        send_resolved: true

  - name: slack-warning
    slack_configs:
      - api_url: "${SLACK_WEBHOOK_URL}"
        channel: "#alerts-warning"
        send_resolved: true
BASH
# 설정 문법 검증 (배포 전 CI에서 실행)
amtool check-config alertmanager.yml

# 현재 활성화된 알림 목록 확인
amtool alert query --alertmanager.url=http://localhost:9093

# 점검 시간 동안 특정 알림 음소거 (2시간)
amtool silence add alertname=HighMemoryUsage instance=web-01 \
  --alertmanager.url=http://localhost:9093 \
  --duration=2h --comment="정기 점검"

# 활성 silence 목록 확인 / 조기 해제
amtool silence query --alertmanager.url=http://localhost:9093
amtool silence expire <silence-id> --alertmanager.url=http://localhost:9093
개념역할
route알림 라벨을 기준으로 어느 receiver로 보낼지 결정하는 트리 구조
receiverSlack, Email, PagerDuty, Webhook 등 실제 알림을 받는 채널
group_by / group_wait같은 그룹의 알림을 모아 한 번에 발송 — 알림 폭주(alert storm) 방지
repeat_interval해결되지 않은 알림을 재발송하는 주기
inhibit_rule심각한 알림(critical)이 활성화되면 관련된 하위 알림(warning)을 억제
silence점검·배포 등 예상된 상황에서 특정 알림을 일정 기간 수동으로 음소거

CRD(Custom Resource Definition)란?

여기서는 CRD(Custom Resource Definition)란?을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Kubernetes API가 기본 제공하는 리소스는 Pod, Deployment, Service처럼 K8s 코어 코드에 미리 정의되어 있습니다. CRD는 이 목록에 없는 리소스 종류(kind)를 사용자가 직접 추가로 등록하는 "스키마 정의"입니다. CRD를 클러스터에 apply하면 kube-apiserver는 그 순간부터 `kubectl get servicemonitor`, `kubectl apply -f servicemonitor.yaml`처럼 마치 Pod를 다루듯 그 새 리소스를 다룰 수 있게 됩니다 — 저장(etcd), 조회, RBAC 권한 부여가 모두 내장 리소스와 동일하게 동작합니다.

다만 CRD는 "이런 필드를 가진 리소스"라는 정의일 뿐, 그 자체로는 아무 동작도 하지 않습니다. 실제로 무언가를 하려면 그 CR(Custom Resource) 인스턴스를 계속 지켜보다가(watch) 원하는 상태로 만들어주는(reconcile) 별도 프로그램인 Controller가 떠 있어야 합니다. "CRD + 그 CRD를 다루는 전용 Controller"의 조합을 Operator 패턴이라고 부릅니다 — 앞서 나온 kube-prometheus-stack의 Prometheus Operator가 정확히 이 패턴입니다: ServiceMonitor라는 CRD를 만들고, Prometheus Operator라는 Controller가 그 인스턴스들을 읽어 실제 Prometheus의 scrape 설정에 반영합니다.
explore.shBASH
# kube-prometheus-stack이 실제로 등록한 CRD 목록 확인
kubectl get crd | grep monitoring.coreos.com
# alertmanagerconfigs.monitoring.coreos.com
# alertmanagers.monitoring.coreos.com
# podmonitors.monitoring.coreos.com
# probes.monitoring.coreos.com
# prometheuses.monitoring.coreos.com
# prometheusrules.monitoring.coreos.com
# servicemonitors.monitoring.coreos.com
# thanosrulers.monitoring.coreos.com

# CRD가 정의한 스키마(필드 구조)를 kubectl explain으로 그대로 조회 가능 — Pod 보듯 동일하게 동작
kubectl explain servicemonitor.spec
kubectl explain servicemonitor.spec.endpoints

# CRD 하나를 자세히 보면 group/version/kind와 openAPIV3Schema(필드 검증 규칙)로 구성돼 있음
kubectl get crd servicemonitors.monitoring.coreos.com -o yaml | head -30

# 이 CRD를 만든 Controller(Prometheus Operator)가 실제로 떠 있는지 확인
# — Controller가 없으면 CR을 apply해도 etcd에 저장만 될 뿐 아무 일도 일어나지 않음
kubectl get deploy -n monitoring -l app=kube-prometheus-stack-operator
toy-crd-example.yamlYAML
# 개념 이해를 위한 최소 예시 — "Website"라는 가상의 리소스 종류를 새로 등록
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
  name: websites.example.com          # <복수형>.<group>
spec:
  group: example.com
  scope: Namespaced
  names:
    plural: websites
    singular: website
    kind: Website                     # 이제부터 kubectl get website 가 가능해짐
  versions:
    - name: v1
      served: true
      storage: true
      schema:
        openAPIV3Schema:               # CR이 반드시 지켜야 할 필드 구조 (spec.url은 string 필수)
          type: object
          properties:
            spec:
              type: object
              required: ["url"]
              properties:
                url:
                  type: string
---
# 위 CRD를 apply한 뒤에는 아래처럼 CR 인스턴스를 만들 수 있음
apiVersion: example.com/v1
kind: Website
metadata:
  name: aidevops
spec:
  url: https://www.aidevops.kr
# 주의: 이 CR을 apply해도 실제로 웹사이트를 배포/점검하는 동작은 없음.
# 그 동작을 수행하려면 Website CR을 watch하는 Controller를 별도로 만들어 배포해야 함
# (kube-prometheus-stack에서는 이 Controller 역할을 Prometheus Operator가 대신 해줌)
용어의미
CRD (Custom Resource Definition)새 리소스 종류(kind)를 K8s API에 등록하는 스키마 정의 그 자체 — "명세서"
CR (Custom Resource)CRD가 정의한 스키마를 따르는 실제 인스턴스 — kubectl apply한 YAML 한 건 한 건
ControllerCR의 생성·변경·삭제를 watch하며 원하는 상태(desired state)로 맞춰주는 프로그램
OperatorCRD + 전용 Controller를 묶어 특정 소프트웨어의 운영 지식을 자동화한 것 (예: Prometheus Operator)
내장 리소스와의 차이Pod/Service는 K8s 코어에 하드코딩된 리소스, CR은 누구나 추가할 수 있는 "플러그인 리소스"

설치 전 준비 — 사전 요구사항 & 클러스터 사이징

여기서는 설치 전 준비 — 사전 요구사항 & 클러스터 사이징을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

kube-prometheus-stack은 CRD와 여러 컴포넌트를 한 번에 설치하기 때문에, 클러스터 상태를 미리 점검하지 않으면 설치 중간에 애매하게 실패하는 경우가 많습니다. 특히 CRD는 매니페스트 용량이 커서 kubectl apply -f로 직접 적용하면 흔히 겪는 오류가 따로 있고, Prometheus에 할당할 리소스는 클러스터 규모(노드 수, 모니터링 대상 수)에 따라 처음부터 다르게 잡아야 합니다.
다이어그램 렌더링 중…
preflight-check.shBASH
# 1) 클러스터·Helm 버전 확인 — kube-prometheus-stack 최신 버전은 Helm 3.8+ 요구
kubectl version --short
helm version

# 2) StorageClass가 실제로 존재하는지 확인 (values.yaml의 storageClassName과 반드시 일치해야 함)
kubectl get storageclass
#   NAME (default)   PROVISIONER             ...
#   fast-ssd          ebs.csi.aws.com          ...   ← 이 이름을 values.yaml에 그대로 사용

# 3) 노드 자원 여유 확인 — Prometheus 하나만으로도 최소 500m CPU / 2Gi 메모리를 선점
kubectl top nodes
kubectl describe nodes | grep -A5 "Allocated resources"

# 4) monitoring 네임스페이스에 리소스 상한이 걸려 있지 않은지 확인
kubectl get resourcequota -n monitoring 2>/dev/null || echo "쿼터 없음 (정상)"

# 5) CRD를 kubectl apply -f로 직접 적용하면 흔히 나는 오류 —
#    "metadata.annotations: Too long: must have at most 262144 bytes"
#    kube-prometheus-stack의 CRD는 용량이 커서 kubectl apply의 last-applied-configuration
#    annotation 저장 한도를 초과합니다. helm install은 이 문제를 우회해 CRD를 등록하므로,
#    부득이 수동으로 적용해야 한다면 반드시 --server-side를 사용하세요.
kubectl apply --server-side -f https://raw.githubusercontent.com/prometheus-community/helm-charts/main/charts/kube-prometheus-stack/crds/crd-prometheusrules.yaml
argocd-application.yaml — GitOps 방식 설치YAML
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: kube-prometheus-stack
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://prometheus-community.github.io/helm-charts
    chart: kube-prometheus-stack
    targetRevision: 65.5.1        # 버전을 반드시 고정 — Chart.yaml appVersion과 별개로 관리됨
    helm:
      valueFiles: ["values-production.yaml"]   # 같은 Git 저장소의 values 파일 참조
  destination:
    server: https://kubernetes.default.svc
    namespace: monitoring
  syncPolicy:
    automated: { prune: true, selfHeal: true }
    syncOptions: ["CreateNamespace=true"]
클러스터 규모Prometheus 리소스 권장값retention비고
소규모 (~20 노드, ServiceMonitor 수십 개)requests: 500m CPU / 2Gi15d기본값에서 크게 벗어나지 않아도 무방
중규모 (20~100 노드)requests: 1~2 CPU / 4~8Gi30dretentionSize를 함께 설정해 볼륨 초과를 사전 방지
대규모 (100+ 노드, 카디널리티 높음)requests: 4 CPU+ / 16Gi+15d + remoteWrite단일 Prometheus 한계에 근접 — Thanos/Mimir로 샤딩·장기 보관 분리 검토

Tip

CRD 관련 오류는 대부분 "kubectl apply -f로 CRD를 직접 넣었을 때" 발생합니다 — kube-prometheus-stack은 helm install(또는 위 ArgoCD 예시처럼 Helm 소스를 쓰는 GitOps 도구)로 설치하면 Helm이 CRD를 별도 경로로 처리해 이 문제 자체를 겪지 않습니다.

Kubernetes 통합 — kube-prometheus-stack

여기서는 Kubernetes 통합 — kube-prometheus-stack을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

kube-prometheus-stack은 Prometheus, Alertmanager, Grafana를 개별로 설치·연동하는 대신 하나의 Helm 차트로 묶어주는 "Opinionated" 번들입니다. 핵심은 함께 설치되는 Prometheus Operator입니다 — Operator가 ServiceMonitor·PodMonitor·PrometheusRule 같은 CRD를 감시하다가 매니페스트가 생성/변경되면 Prometheus의 scrape 설정과 알림 규칙에 자동 반영합니다. 즉 prometheus.yml을 직접 편집하고 파드를 재시작하는 대신, 쿠버네티스 리소스를 kubectl apply 하는 것만으로 모니터링 대상을 늘릴 수 있습니다.
install.shBASH
# 1) Helm repo 등록
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# 2) 버전 확인 — 프로덕션은 반드시 버전을 고정해서 설치 (latest 금지)
helm search repo prometheus-community/kube-prometheus-stack --versions | head -5

# 3) 설치 (CRD는 차트에 포함되어 함께 설치됨)
helm install kube-prom prometheus-community/kube-prometheus-stack \
  --namespace monitoring --create-namespace \
  --version 65.5.1 \
  -f values.yaml

# 4) 설치 확인 — Prometheus/Alertmanager/Grafana/Operator/node-exporter/kube-state-metrics 모두 Running
kubectl get pods -n monitoring
kubectl get prometheus,alertmanager -n monitoring   # Operator가 생성한 CR 상태 확인

# 5) Grafana 접속 (admin 계정 초기 비밀번호)
kubectl get secret kube-prom-grafana -n monitoring \
  -o jsonpath="{.data.admin-password}" | base64 -d; echo
kubectl port-forward -n monitoring svc/kube-prom-grafana 3000:80
values.yamlYAML
prometheus:
  prometheusSpec:
    retention: 30d                        # 로컬 TSDB 보관 기간
    retentionSize: "45GB"                 # 볼륨 대비 여유를 두고 용량 상한도 함께 설정
    resources:
      requests: { cpu: 500m, memory: 2Gi }
      limits:   { memory: 4Gi }           # CPU limit은 스로틀링 유발 — 보통 미설정 권장
    storageSpec:
      volumeClaimTemplate:
        spec:
          storageClassName: fast-ssd
          resources: { requests: { storage: 50Gi } }
    # false로 설정하면 release 라벨과 무관하게 클러스터 전체 ServiceMonitor/PodMonitor/Probe/Rule을 인식
    serviceMonitorSelectorNilUsesHelmValues: false
    podMonitorSelectorNilUsesHelmValues: false
    probeSelectorNilUsesHelmValues: false
    ruleSelectorNilUsesHelmValues: false
    additionalScrapeConfigs: []           # ServiceMonitor로 커버 안 되는 정적 타깃 추가 시 사용
    # remoteWrite:                        # 장기 보관이 필요하면 Thanos/Mimir/Grafana Cloud 등으로 원격 저장
    #   - url: https://mimir.example.com/api/v1/push

# 관리형 K8s(EKS/GKE/AKS)는 컨트롤 플레인 메트릭에 접근 불가 — 기본 Off 권장 (Pending Target 방지)
kubeControllerManager: { enabled: false }
kubeScheduler:         { enabled: false }
kubeEtcd:               { enabled: false }
kubeProxy:               { enabled: false }

alertmanager:
  alertmanagerSpec:
    resources:
      requests: { cpu: 100m, memory: 256Mi }
    storage:
      volumeClaimTemplate:
        spec:
          resources: { requests: { storage: 5Gi } }

grafana:
  admin:
    existingSecret: grafana-admin-credentials   # 평문 비밀번호 대신 별도 Secret 참조 권장
  persistence: { enabled: true, size: 10Gi }
  sidecar:
    dashboards: { enabled: true, label: grafana_dashboard }   # ConfigMap 라벨 기반 대시보드 자동 로드
    datasources: { enabled: true }
  ingress:
    enabled: true
    ingressClassName: nginx
    annotations:
      cert-manager.io/cluster-issuer: letsencrypt-prod
    hosts: ["grafana.aidevops.kr"]
    tls:
      - secretName: grafana-tls
        hosts: ["grafana.aidevops.kr"]

defaultRules:
  rules:
    etcd: false          # 컨트롤 플레인 규칙도 관리형 K8s에서는 대부분 비활성화 대상
    kubeScheduler: false
구성 요소종류역할
Prometheus OperatorDeploymentCRD를 감시해 Prometheus/Alertmanager StatefulSet과 설정을 자동 생성·갱신
PrometheusStatefulSet (Operator가 생성)메트릭 저장 엔진 — 직접 만들지 않고 Prometheus CRD로 선언
AlertmanagerStatefulSet (Operator가 생성)알림 그룹핑·중복 제거·라우팅 — Alertmanager/AlertmanagerConfig CRD로 선언
GrafanaDeployment대시보드 시각화. sidecar 컨테이너가 라벨 붙은 ConfigMap을 감지해 자동 로드
node-exporterDaemonSet모든 노드의 CPU/메모리/디스크/네트워크 OS 메트릭 노출
kube-state-metricsDeploymentPod/Deployment/PVC 등 K8s API 오브젝트 상태를 메트릭으로 변환
kubelet / cAdvisor기존 kubelet 내장컨테이너 리소스 사용량 — 차트가 기본 scrape 설정을 자동 구성
기본 PrometheusRule/대시보드CRD + ConfigMapkube-apiserver, etcd, kubelet 등에 대한 검증된 알림·대시보드가 기본 포함

CRD로 수집·알림 확장 — ServiceMonitor · PodMonitor · Probe

여기서는 CRD로 수집·알림 확장 — ServiceMonitor · PodMonitor · Probe을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

Operator는 세 가지 방식으로 scrape 대상을 정의합니다. ServiceMonitor는 Service 리소스를 매개로(가장 흔한 방식), PodMonitor는 안정적인 Service가 없는 Pod를 직접, Probe는 blackbox-exporter를 통해 클러스터 내부/외부 URL의 가용성을 원격으로 검사합니다. 세 CRD 모두 labels가 Prometheus CR의 selector(위 values.yaml의 xxxSelectorNilUsesHelmValues 설정)와 일치해야 인식된다는 점이 가장 흔한 실수 포인트입니다. 이 Probe CRD는 앞서 health-vs-metrics 섹션에서 설명한 Kubernetes의 liveness/readiness probe와는 이름만 같을 뿐 전혀 다른 리소스이니 혼동하지 마세요.
servicemonitor.yamlYAML
# Operator가 이 리소스를 보고 자동으로 myapp을 scrape 대상에 추가
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: myapp
  namespace: production
  labels:
    release: kube-prom          # serviceMonitorSelectorNilUsesHelmValues: true일 때만 필요
spec:
  selector:
    matchLabels:
      app: myapp                # 대상 Service의 라벨
  endpoints:
    - port: metrics              # 대상 Service의 포트 이름
      path: /metrics
      interval: 15s
podmonitor.yamlYAML
# 안정적인 Service 없이 Pod를 직접 스크랩 (예: Job/배치성 워크로드, 사이드카 메트릭)
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: myapp-batch
  namespace: production
spec:
  selector:
    matchLabels:
      app: myapp-batch
  podMetricsEndpoints:
    - port: metrics
      path: /metrics
      interval: 30s
probe-blackbox.yamlYAML
# 외부/내부 엔드포인트 가용성 원격 점검 — blackbox-exporter 별도 설치 필요
# helm install blackbox-exporter prometheus-community/prometheus-blackbox-exporter -n monitoring
apiVersion: monitoring.coreos.com/v1
kind: Probe
metadata:
  name: aidevops-uptime
  namespace: monitoring
  labels:
    release: kube-prom
spec:
  jobName: blackbox-http
  interval: 30s
  module: http_2xx
  prober:
    url: blackbox-exporter-prometheus-blackbox-exporter.monitoring.svc:19115
  targets:
    staticConfig:
      static:
        - https://www.aidevops.kr
        - https://www.aidevops.kr/learn/prometheus/
prometheusrule.yamlYAML
# alert_rules.yml을 수동 마운트하는 대신 CRD로 선언 — GitOps로 관리 가능
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
  name: myapp-alerts
  namespace: production
  labels:
    release: kube-prom
spec:
  groups:
    - name: myapp.recording
      rules:
        - record: job:http_errors:ratio5m
          expr: sum(rate(http_requests_total{status=~"5.."}[5m])) by (job) / sum(rate(http_requests_total[5m])) by (job)
    - name: myapp.alerts
      rules:
        - alert: HighErrorRate
          expr: job:http_errors:ratio5m{namespace="production"} > 0.05
          for: 5m
          labels: { severity: critical }
          annotations:
            summary: "{{ $labels.job }} 에러율 5% 초과"
        - alert: ProbeFailing
          expr: probe_success{job="blackbox-http"} == 0
          for: 5m
          labels: { severity: critical }
          annotations:
            summary: "{{ $labels.instance }} 헬스체크 실패"
grafana-dashboard-configmap.yamlYAML
# grafana_dashboard 라벨을 붙이면 sidecar가 클러스터 전체 네임스페이스에서 자동 감지해 로드
apiVersion: v1
kind: ConfigMap
metadata:
  name: myapp-dashboard
  namespace: monitoring
  labels:
    grafana_dashboard: "1"
data:
  myapp-red-metrics.json: |
    { "title": "MyApp - RED Metrics", "panels": [] }

검증 · 업그레이드 · 트러블슈팅

여기서는 검증 · 업그레이드 · 트러블슈팅을 실제 코드와 함께 확인합니다. 예제를 그대로 따라 하기보다, 입력과 출력, 그리고 바뀌기 쉬운 부분이 어디인지 보면서 읽어보세요.

CRD 기반이라 설정 오류가 나도 Prometheus 재시작 없이 조용히 무시되는 경우가 많습니다. 배포 후에는 반드시 Target 상태와 Operator가 생성한 Prometheus CR의 Condition을 확인하는 습관이 필요합니다. 업그레이드는 helm upgrade로 안전하지만, helm uninstall은 CRD를 삭제하지 않습니다 — 데이터 손실 방지를 위한 Helm 3의 의도된 동작이므로, 완전 제거 시 CRD도 별도로 지워야 재설치 충돌을 피할 수 있습니다.
verify.shBASH
# Target 상태 확인 (모두 up이어야 정상)
kubectl port-forward -n monitoring svc/kube-prom-kube-prome-prometheus 9090:9090 &
curl -s localhost:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health}'

# Operator가 생성한 Prometheus CR이 정상 반영됐는지 확인
kubectl get prometheus -n monitoring -o jsonpath='{.items[0].status.conditions}' | jq

# 어떤 ServiceMonitor/PodMonitor/Rule을 Operator가 실제로 인식했는지 확인
kubectl get servicemonitors,podmonitors,prometheusrules -A

# PrometheusRule 문법 검증 (배포 전 CI에서 실행 권장)
kubectl get prometheusrule myapp-alerts -n production -o jsonpath='{.spec}' > /tmp/rule.yaml
promtool check rules /tmp/rule.yaml
upgrade-uninstall.shBASH
# 업그레이드 — values.yaml 변경 후 재적용
helm upgrade kube-prom prometheus-community/kube-prometheus-stack \
  --namespace monitoring -f values.yaml

# 특정 버전으로 업그레이드 시 CRD 변경 여부를 먼저 확인 (major 버전 업은 CRD 스키마가 바뀔 수 있음)
helm show crds prometheus-community/kube-prometheus-stack --version 65.5.1 | grep "kind: CustomResourceDefinition" -A2

# 완전 제거 — Helm은 CRD를 지우지 않으므로 재설치 충돌 방지를 위해 수동 삭제 필요
helm uninstall kube-prom --namespace monitoring
kubectl delete crd -l app.kubernetes.io/part-of=kube-prometheus-stack
증상원인해결
ServiceMonitor를 만들었는데 Target에 안 뜸label이 selector와 불일치하거나 selectorNilUsesHelmValues가 trueServiceMonitor에 release 라벨 추가 또는 values.yaml에서 false로 전환
kube-controller-manager/kube-scheduler Target이 계속 down관리형 K8s는 컨트롤 플레인 미노출values.yaml에서 kubeControllerManager/kubeScheduler.enabled: false
PVC가 Pending에서 멈춤지정한 storageClassName이 클러스터에 없음kubectl get storageclass로 실제 이름 확인 후 values.yaml 수정
Grafana sidecar가 대시보드를 못 찾음ConfigMap 라벨이 grafana.sidecar.dashboards.label과 불일치라벨 값(기본 grafana_dashboard)과 네임스페이스 감시 범위 확인
helm uninstall 후 재설치가 실패함이전 설치의 CRD/PVC가 잔존kubectl delete crd, kubectl delete pvc -n monitoring 로 정리 후 재설치

Prometheus 실무 설계

Prometheus 실무 설계은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

Prometheus는 무엇을 측정할지 먼저 정해야 합니다. RED/USE 지표와 label cardinality 정책을 세우지 않으면 쿼리와 저장 비용이 커집니다.
결정 지점확인 질문실무 기준
경계Prometheus 코드에서 바뀌기 쉬운 부분은 어디인가?입출력, 설정, 외부 연동, 핵심 규칙을 분리합니다.
상태상태가 어디서 생성되고 어디서 사라지는가?상태 소유자와 수명 주기를 코드로 드러냅니다.
장애실패했을 때 호출자는 무엇을 받는가?timeout, fallback, error contract를 먼저 정합니다.

Prometheus 운영 기준

이 섹션은 Prometheus 운영 기준을 실무 관점에서 정리합니다. 개념을 외우기보다, 어떤 상황에서 이 기준을 꺼내 쓸지에 초점을 맞춰보세요.

scrape interval, retention, recording rule, alert fatigue, dashboard ownership을 관리해야 합니다.

Tip

  • label cardinality
  • recording rules
  • alert fatigue
  • runbook link

Prometheus 검증 전략

Prometheus 검증 전략은 선택지가 갈리는 지점입니다. 표를 기준으로 각 방법의 쓰임새와 운영상의 차이를 비교해두면 이후 판단이 훨씬 쉬워집니다.

alert rule test, dashboard review, synthetic metric, runbook link를 포함해야 합니다.
품질 축검증 방법완료 기준
정확성정상/실패 케이스를 자동화합니다.핵심 시나리오가 재현 가능하게 통과합니다.
회귀 방지버그 수정 시 동일 케이스를 테스트로 남깁니다.같은 장애가 다시 배포되지 않습니다.
운영성로그, 메트릭, 알림을 확인합니다.문제가 생겼을 때 원인 추적 경로가 있습니다.
← 이전 가이드Kubernetes 심화/실무다음 가이드 →Grafana