์ฝ˜ํ…์ธ  ๋Œ€ํ‘œ ์ด๋ฏธ์ง€ - ๐Ÿš€ Prometheus + Grafana ๋ชจ๋‹ˆํ„ฐ๋ง ๊ตฌ์ถ• ์™„๋ฒฝ ๊ฐ€์ด๋“œ

๐Ÿš€ Prometheus + Grafana ๋ชจ๋‹ˆํ„ฐ๋ง ๊ตฌ์ถ• ์™„๋ฒฝ ๊ฐ€์ด๋“œ

์‹œ์Šคํ…œ์„ ์ง€ํ‚ค๋Š” ์ตœ๊ฐ• ๋ชจ๋‹ˆํ„ฐ๋ง ๋“€์˜ค์™€ ํ•จ๊ป˜ํ•˜๋Š” ์—ฌ์ •

์•ˆ๋…•! ๐Ÿ‘‹ ์˜ค๋Š˜์€ DevOps ์—”์ง€๋‹ˆ์–ด๋“ค์˜ ํ•„์ˆ˜ ๋ฌด๊ธฐ์ธ Prometheus์™€ Grafana๋ฅผ ํ™œ์šฉํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ์ด์•ผ๊ธฐํ•ด๋ณผ๊ฒŒ.

์„œ๋ฒ„๊ฐ€ ๊ฐ‘์ž๊ธฐ ๋‹ค์šด๋˜๊ฑฐ๋‚˜, CPU ์‚ฌ์šฉ๋ฅ ์ด ์น˜์†Ÿ๊ฑฐ๋‚˜, ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ํ„ฐ์งˆ ๊ฒƒ ๊ฐ™์€ ์ƒํ™ฉ... ๐Ÿ˜ฑ ์ด๋Ÿฐ ์•…๋ชฝ ๊ฐ™์€ ์ˆœ๊ฐ„๋“ค์„ ๋ฏธ๋ฆฌ ๊ฐ์ง€ํ•˜๊ณ  ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋‹ค๋ฉด ์–ผ๋งˆ๋‚˜ ์ข‹์„๊นŒ?

๋ฐ”๋กœ ๊ทธ๊ฒŒ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ์˜ ํž˜์ด์•ผ! ํŠนํžˆ Prometheus์™€ Grafana ์กฐํ•ฉ์€ ํด๋ผ์šฐ๋“œ ๋„ค์ดํ‹ฐ๋ธŒ ํ™˜๊ฒฝ์—์„œ ๊ฐ€์žฅ ์ธ๊ธฐ ์žˆ๋Š” ์˜คํ”ˆ์†Œ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง ์†”๋ฃจ์…˜์ด์ง€. ๐ŸŽฏ

Prometheus ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘ Grafana ์‹œ๊ฐํ™” ๋ฉ”ํŠธ๋ฆญ ์ „์†ก ์„œ๋ฒ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์ปจํ…Œ์ด๋„ˆ ์ถ”์  ์•Œ๋ฆผ ์‹œ์Šคํ…œ

๐ŸŽฏ ์™œ Prometheus์™€ Grafana์ธ๊ฐ€?

๋จผ์ € ์ด ๋‘ ์นœ๊ตฌ๊ฐ€ ์™œ ์ด๋ ‡๊ฒŒ ์ธ๊ธฐ๊ฐ€ ๋งŽ์€์ง€ ์•Œ์•„๋ณผ๊นŒ? ๐Ÿค”

์š”์ฆ˜ ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ์—์„œ๋Š” ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜๊ฐ€ ๋Œ€์„ธ์ž–์•„? ์ˆ˜์‹ญ, ์ˆ˜๋ฐฑ ๊ฐœ์˜ ์ปจํ…Œ์ด๋„ˆ๊ฐ€ ๋™์‹œ์— ๋Œ์•„๊ฐ€๋Š” ํ™˜๊ฒฝ์—์„œ ์ „ํ†ต์ ์ธ ๋ชจ๋‹ˆํ„ฐ๋ง ๋„๊ตฌ๋กœ๋Š” ํ•œ๊ณ„๊ฐ€ ์žˆ์–ด.

Prometheus๋Š” CNCF(Cloud Native Computing Foundation)์˜ ์กธ์—… ํ”„๋กœ์ ํŠธ๋กœ, Kubernetes์™€ ์ฐฐ๋–ก๊ถํ•ฉ์ด์•ผ. ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ํ•˜๊ณ , Pull ๋ฐฉ์‹์œผ๋กœ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๋Š” ๊ฒŒ ํŠน์ง•์ด์ง€. ๐Ÿ’ช

๐Ÿ”ฅ Prometheus์˜ ํ•ต์‹ฌ ๊ฐ•์ 

โ€ข ๋‹ค์ฐจ์› ๋ฐ์ดํ„ฐ ๋ชจ๋ธ: ๋ ˆ์ด๋ธ” ๊ธฐ๋ฐ˜์œผ๋กœ ๋ฉ”ํŠธ๋ฆญ์„ ์œ ์—ฐํ•˜๊ฒŒ ๊ด€๋ฆฌ
โ€ข ๊ฐ•๋ ฅํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด: PromQL๋กœ ๋ณต์žกํ•œ ๋ฐ์ดํ„ฐ ๋ถ„์„ ๊ฐ€๋Šฅ
โ€ข ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ: ๋™์  ํ™˜๊ฒฝ์—์„œ ์ž๋™์œผ๋กœ ํƒ€๊ฒŸ ๋ฐœ๊ฒฌ
โ€ข ๋…๋ฆฝ์  ์šด์˜: ์™ธ๋ถ€ ์˜์กด์„ฑ ์—†์ด ๋‹จ๋… ์‹คํ–‰ ๊ฐ€๋Šฅ
โ€ข ํ’๋ถ€ํ•œ Exporter: ๋‹ค์–‘ํ•œ ์‹œ์Šคํ…œ๊ณผ ํ†ตํ•ฉ ๊ฐ€๋Šฅ

๊ทธ๋Ÿผ Grafana๋Š”? ๐ŸŽจ

Grafana๋Š” ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™”์˜ ๋ํŒ์™•์ด์•ผ. Prometheus๊ฐ€ ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์•„๋ฆ„๋‹ต๊ณ  ์ง๊ด€์ ์ธ ๋Œ€์‹œ๋ณด๋“œ๋กœ ๋งŒ๋“ค์–ด์ฃผ์ง€. ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ฐจํŠธ๊ฐ€ ์—…๋ฐ์ดํŠธ๋˜๋Š” ๊ฑธ ๋ณด๋ฉด ์ •๋ง ๊ฐ๋™์ด์•ผ!

๊ฒŒ๋‹ค๊ฐ€ Prometheus๋ฟ๋งŒ ์•„๋‹ˆ๋ผ InfluxDB, Elasticsearch, MySQL ๋“ฑ ๋‹ค์–‘ํ•œ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ์ง€์›ํ•ด์„œ ํ™•์žฅ์„ฑ๋„ ๋›ฐ์–ด๋‚˜. ๐Ÿ“Š

๐Ÿ’ก ์žฌ๋Šฅ๋„ท TIP ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์ด ์ฒ˜์Œ์ด๋ผ๋ฉด ์žฌ๋Šฅ๋„ท์—์„œ DevOps ์ „๋ฌธ๊ฐ€์˜ ์ปจ์„คํŒ…์„ ๋ฐ›์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ๋ฐฉ๋ฒ•์ด์•ผ. ์‹ค๋ฌด ๊ฒฝํ—˜์ด ํ’๋ถ€ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋‹น์‹ ์˜ ํ™˜๊ฒฝ์— ๋งž๋Š” ์ตœ์ ์˜ ๊ตฌ์„ฑ์„ ์ œ์•ˆํ•ด์ค„ ๊ฑฐ์•ผ!

๐Ÿ—๏ธ ์•„ํ‚คํ…์ฒ˜ ์ดํ•ดํ•˜๊ธฐ

๋ณธ๊ฒฉ์ ์œผ๋กœ ๊ตฌ์ถ•ํ•˜๊ธฐ ์ „์— ์ „์ฒด ์•„ํ‚คํ…์ฒ˜๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒŒ ์ค‘์š”ํ•ด. ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์–ด๋–ป๊ฒŒ ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š”์ง€ ์•Œ์•„์•ผ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ์„ ๋•Œ ๋น ๋ฅด๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ ! ๐Ÿงฉ

๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ์•„ํ‚คํ…์ฒ˜ ๋ฐ์ดํ„ฐ ์†Œ์Šค ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ Node Exporter cAdvisor Custom Exporter ๊ธฐํƒ€ ์„œ๋น„์Šค Prometheus ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ Pull ๋ฐฉ์‹ ์‹œ๊ณ„์—ด DB TSDB ์ €์žฅ PromQL ์—”์ง„ ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ Alertmanager ์•Œ๋ฆผ ๊ทœ์น™ ํ‰๊ฐ€ ์•Œ๋ฆผ ์ „์†ก Grafana ๋Œ€์‹œ๋ณด๋“œ ์‹ค์‹œ๊ฐ„ ์‹œ๊ฐํ™” ํŒจ๋„ ๊ตฌ์„ฑ ์ฐจํŠธ ๊ทธ๋ž˜ํ”„ ์•Œ๋ฆผ ์„ค์ • ์ž„๊ณ„๊ฐ’ ๋ชจ๋‹ˆํ„ฐ๋ง ์‚ฌ์šฉ์ž ์ธํ„ฐํŽ˜์ด์Šค ์›น UI Scrape Query

๐Ÿ“‹ ์ฃผ์š” ์ปดํฌ๋„ŒํŠธ ์—ญํ• 

1. Exporter: ๋‹ค์–‘ํ•œ ์‹œ์Šคํ…œ์˜ ๋ฉ”ํŠธ๋ฆญ์„ Prometheus ํ˜•์‹์œผ๋กœ ๋ณ€ํ™˜
2. Prometheus Server: ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘, ์ €์žฅ, ์ฟผ๋ฆฌ ์ฒ˜๋ฆฌ์˜ ํ•ต์‹ฌ
3. Alertmanager: ์•Œ๋ฆผ ๊ทœ์น™ ํ‰๊ฐ€ ๋ฐ ์•Œ๋ฆผ ์ „์†ก ๊ด€๋ฆฌ
4. Grafana: ์ˆ˜์ง‘๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„
5. Service Discovery: ๋™์  ํ™˜๊ฒฝ์—์„œ ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์ƒ ์ž๋™ ๋ฐœ๊ฒฌ

์ด ๊ตฌ์กฐ์˜ ํ•ต์‹ฌ์€ ๋ถ„๋ฆฌ๋œ ์ฑ…์ž„์ด์•ผ. ๊ฐ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ์ž๊ธฐ ์—ญํ• ์—๋งŒ ์ง‘์ค‘ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ™•์žฅ์„ฑ๊ณผ ์œ ์ง€๋ณด์ˆ˜์„ฑ์ด ๋›ฐ์–ด๋‚˜์ง€. ๐ŸŽฏ

Prometheus๋Š” ๋ฐ์ดํ„ฐ ์ˆ˜์ง‘๊ณผ ์ €์žฅ์— ์ง‘์ค‘ํ•˜๊ณ , Grafana๋Š” ์‹œ๊ฐํ™”์— ์ง‘์ค‘ํ•ด. ์ด๋Ÿฐ ๊ตฌ์กฐ ๋•๋ถ„์— ๊ฐ๊ฐ์„ ๋…๋ฆฝ์ ์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ฑฐ๋‚˜ ๊ต์ฒดํ•  ์ˆ˜ ์žˆ์–ด!

โš™๏ธ Prometheus ์„ค์น˜ ๋ฐ ์„ค์ •

์ž, ์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ์„ค์น˜ํ•ด๋ณผ๊นŒ? ์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์ด ์žˆ์ง€๋งŒ ๊ฐ€์žฅ ์‹ค์šฉ์ ์ธ ๋ฐฉ๋ฒ•๋“ค์„ ์†Œ๊ฐœํ• ๊ฒŒ! ๐Ÿ› ๏ธ

๐Ÿ“ฆ ๋ฐฉ๋ฒ• 1: Docker๋กœ ๋น ๋ฅด๊ฒŒ ์‹œ์ž‘ํ•˜๊ธฐ

Docker๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ •๋ง ๊ฐ„๋‹จํ•ด. ํ™˜๊ฒฝ ์„ค์ • ๊ฑฑ์ • ์—†์ด ๋ฐ”๋กœ ์‹œ์ž‘ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ !
docker-compose.yml
version: '3.8'

services:
  prometheus:
    image: prom/prometheus:latest
    container_name: prometheus
    ports:
      - "9090:9090"
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
      - prometheus-data:/prometheus
    command:
      - '--config.file=/etc/prometheus/prometheus.yml'
      - '--storage.tsdb.path=/prometheus'
      - '--storage.tsdb.retention.time=30d'
      - '--web.enable-lifecycle'
    restart: unless-stopped
    networks:
      - monitoring

volumes:
  prometheus-data:

networks:
  monitoring:
    driver: bridge

์œ„ ์„ค์ •์—์„œ ์ฃผ๋ชฉํ•  ์ ๋“ค์ด ์žˆ์–ด! ๐Ÿ‘€

โ€ข storage.tsdb.retention.time: ๋ฐ์ดํ„ฐ ๋ณด๊ด€ ๊ธฐ๊ฐ„์„ 30์ผ๋กœ ์„ค์ •ํ–ˆ์–ด. ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋””์Šคํฌ ์šฉ๋Ÿ‰์„ ๊ณ ๋ คํ•ด์„œ ์กฐ์ •ํ•ด์•ผ ํ•ด.
โ€ข web.enable-lifecycle: API๋ฅผ ํ†ตํ•ด ์„ค์ •์„ ๋ฆฌ๋กœ๋“œํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ค˜. ์žฌ์‹œ์ž‘ ์—†์ด ์„ค์ • ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•˜์ง€!
โ€ข volumes: ์„ค์ • ํŒŒ์ผ๊ณผ ๋ฐ์ดํ„ฐ๋ฅผ ์˜๊ตฌ ์ €์žฅํ•˜๋„๋ก ๋ณผ๋ฅจ์„ ๋งˆ์šดํŠธํ–ˆ์–ด.

๐Ÿ“ Prometheus ์„ค์ • ํŒŒ์ผ ์ž‘์„ฑ

prometheus.yml์€ Prometheus์˜ ๋‘๋‡Œ์•ผ. ์—ฌ๊ธฐ์„œ ๋ชจ๋“  ๊ฑธ ์ œ์–ดํ•˜์ง€!
prometheus.yml
global:
  scrape_interval: 15s
  evaluation_interval: 15s
  external_labels:
    cluster: 'production'
    region: 'ap-northeast-2'

alerting:
  alertmanagers:
    - static_configs:
        - targets:
            - alertmanager:9093

rule_files:
  - "alerts/*.yml"

scrape_configs:
  # Prometheus ์ž์ฒด ๋ชจ๋‹ˆํ„ฐ๋ง
  - job_name: 'prometheus'
    static_configs:
      - targets: ['localhost:9090']
        labels:
          env: 'production'

  # Node Exporter - ์„œ๋ฒ„ ๋ฉ”ํŠธ๋ฆญ
  - job_name: 'node-exporter'
    static_configs:
      - targets: 
          - 'node-exporter:9100'
        labels:
          instance: 'server-01'
          env: 'production'

  # ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ
  - job_name: 'application'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets:
          - 'app-server:8080'
        labels:
          service: 'api-server'
          version: 'v1.2.3'

  # Kubernetes ์„œ๋น„์Šค ๋””์Šค์ปค๋ฒ„๋ฆฌ
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod
    relabel_configs:
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
        action: keep
        regex: true
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        regex: ([^:]+)(?::\d+)?;(\d+)
        replacement: $1:$2
        target_label: __address__
๐Ÿ’ก ์„ค์ • ํŒŒ์ผ ํ•ต์‹ฌ ํฌ์ธํŠธ scrape_interval: ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ ์ฃผ๊ธฐ. ๋„ˆ๋ฌด ์งง์œผ๋ฉด ๋ถ€ํ•˜๊ฐ€ ํฌ๊ณ , ๋„ˆ๋ฌด ๊ธธ๋ฉด ์‹ค์‹œ๊ฐ„์„ฑ์ด ๋–จ์–ด์ ธ. 15์ดˆ๊ฐ€ ์ผ๋ฐ˜์ ์ธ ๋ฐธ๋Ÿฐ์Šค์•ผ.

external_labels: ์—ฌ๋Ÿฌ Prometheus ์ธ์Šคํ„ด์Šค๋ฅผ ์šด์˜ํ•  ๋•Œ ๊ตฌ๋ถ„ํ•˜๋Š” ์šฉ๋„. Federation ๊ตฌ์„ฑ ์‹œ ํ•„์ˆ˜!

relabel_configs: Kubernetes ํ™˜๊ฒฝ์—์„œ ๋™์ ์œผ๋กœ ํƒ€๊ฒŸ์„ ๋ฐœ๊ฒฌํ•˜๊ณ  ๋ ˆ์ด๋ธ”์„ ์žฌ๊ตฌ์„ฑํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ๊ธฐ๋Šฅ์ด์•ผ.
๐Ÿš€ ๋ฐฉ๋ฒ• 2: Kubernetes์— Helm์œผ๋กœ ๋ฐฐํฌ

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์ด๋ผ๋ฉด Kubernetes + Helm ์กฐํ•ฉ์ด ์ตœ๊ณ ์•ผ!
Helm์œผ๋กœ ์„ค์น˜ํ•˜๊ธฐ
# Prometheus Community Helm Chart ์ €์žฅ์†Œ ์ถ”๊ฐ€
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update

# ๋„ค์ž„์ŠคํŽ˜์ด์Šค ์ƒ์„ฑ
kubectl create namespace monitoring

# values.yaml ํŒŒ์ผ ์ค€๋น„ ํ›„ ์„ค์น˜
helm install prometheus prometheus-community/kube-prometheus-stack \
  --namespace monitoring \
  --values custom-values.yaml

# ์„ค์น˜ ํ™•์ธ
kubectl get pods -n monitoring
kubectl get svc -n monitoring
custom-values.yaml (์ฃผ์š” ์„ค์ •)
prometheus:
  prometheusSpec:
    retention: 30d
    storageSpec:
      volumeClaimTemplate:
        spec:
          accessModes: ["ReadWriteOnce"]
          resources:
            requests:
              storage: 50Gi
    resources:
      requests:
        cpu: 500m
        memory: 2Gi
      limits:
        cpu: 2000m
        memory: 4Gi
    
    # ์„œ๋น„์Šค ๋ชจ๋‹ˆํ„ฐ ์ž๋™ ๋ฐœ๊ฒฌ
    serviceMonitorSelectorNilUsesHelmValues: false
    podMonitorSelectorNilUsesHelmValues: false

grafana:
  enabled: true
  adminPassword: "your-secure-password"
  persistence:
    enabled: true
    size: 10Gi
  
  ingress:
    enabled: true
    hosts:
      - grafana.yourdomain.com
    tls:
      - secretName: grafana-tls
        hosts:
          - grafana.yourdomain.com

alertmanager:
  enabled: true
  config:
    global:
      resolve_timeout: 5m
      slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'
    
    route:
      group_by: ['alertname', 'cluster', 'service']
      group_wait: 10s
      group_interval: 10s
      repeat_interval: 12h
      receiver: 'slack-notifications'
    
    receivers:
      - name: 'slack-notifications'
        slack_configs:
          - channel: '#alerts'
            title: '๐Ÿšจ {{ .GroupLabels.alertname }}'
            text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'

Helm Chart๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Prometheus, Grafana, Alertmanager๊ฐ€ ํ•œ ๋ฒˆ์— ์„ค์น˜๋ผ. ๊ฒŒ๋‹ค๊ฐ€ Kubernetes ํด๋Ÿฌ์Šคํ„ฐ ๋ชจ๋‹ˆํ„ฐ๋ง์— ํ•„์š”ํ•œ ๋ชจ๋“  Exporter์™€ ServiceMonitor๋„ ํ•จ๊ป˜ ์„ค์น˜๋˜์ง€! ๐Ÿ˜

kube-prometheus-stack์€ ์ •๋ง ๊ฐ•๋ ฅํ•œ ํŒจํ‚ค์ง€์•ผ. ๋ณ„๋„ ์„ค์ • ์—†์ด๋„ ๋…ธ๋“œ, ํŒŒ๋“œ, ์„œ๋น„์Šค ๋ฉ”ํŠธ๋ฆญ์„ ์ž๋™์œผ๋กœ ์ˆ˜์ง‘ํ•ด์ค˜.

โš ๏ธ ์ฃผ์˜์‚ฌํ•ญ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ฐ˜๋“œ์‹œ ๋ฆฌ์†Œ์Šค ์ œํ•œ์„ ์„ค์ •ํ•ด์•ผ ํ•ด! Prometheus๋Š” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋งŽ์ด ์‚ฌ์šฉํ•˜๋Š” ํŽธ์ด๋ผ ์ œํ•œ ์—†์ด ์šด์˜ํ•˜๋ฉด ๋…ธ๋“œ ์ „์ฒด๊ฐ€ ๋‹ค์šด๋  ์ˆ˜ ์žˆ์–ด. ์œ„ ์˜ˆ์‹œ์ฒ˜๋Ÿผ requests์™€ limits๋ฅผ ์ ์ ˆํžˆ ์„ค์ •ํ•˜์ž!

๐Ÿ“Š Exporter ์„ค์ •ํ•˜๊ธฐ

Prometheus๋Š” Pull ๋ฐฉ์‹์ด๋ผ ๋ฉ”ํŠธ๋ฆญ์„ ๋…ธ์ถœํ•˜๋Š” Exporter๊ฐ€ ํ•„์š”ํ•ด. ๋‹ค์–‘ํ•œ ์‹œ์Šคํ…œ์— ๋งž๋Š” Exporter๋ฅผ ์„ค์น˜ํ•ด๋ณด์ž! ๐Ÿ”Œ

๐Ÿ–ฅ๏ธ Node Exporter - ์„œ๋ฒ„ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘

CPU, ๋ฉ”๋ชจ๋ฆฌ, ๋””์Šคํฌ, ๋„คํŠธ์›Œํฌ ๋“ฑ ์‹œ์Šคํ…œ ๋ ˆ๋ฒจ ๋ฉ”ํŠธ๋ฆญ์„ ์ˆ˜์ง‘ํ•˜๋Š” ํ•„์ˆ˜ Exporter์•ผ!
Docker๋กœ Node Exporter ์‹คํ–‰
docker run -d \
  --name node-exporter \
  --net="host" \
  --pid="host" \
  -v "/:/host:ro,rslave" \
  prom/node-exporter:latest \
  --path.rootfs=/host
systemd ์„œ๋น„์Šค๋กœ ์„ค์น˜ (Linux)
# Node Exporter ๋‹ค์šด๋กœ๋“œ
wget https://github.com/prometheus/node_exporter/releases/download/v1.7.0/node_exporter-1.7.0.linux-amd64.tar.gz
tar xvfz node_exporter-1.7.0.linux-amd64.tar.gz
sudo mv node_exporter-1.7.0.linux-amd64/node_exporter /usr/local/bin/

# systemd ์„œ๋น„์Šค ํŒŒ์ผ ์ƒ์„ฑ
sudo tee /etc/systemd/system/node_exporter.service << EOF
[Unit]
Description=Node Exporter
After=network.target

[Service]
Type=simple
User=prometheus
ExecStart=/usr/local/bin/node_exporter \
  --collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($$|/) \
  --collector.netclass.ignored-devices=^(veth.*|docker.*|br-.*)$$

[Install]
WantedBy=multi-user.target
EOF

# ์„œ๋น„์Šค ์‹œ์ž‘
sudo systemctl daemon-reload
sudo systemctl enable node_exporter
sudo systemctl start node_exporter

# ํ™•์ธ
curl http://localhost:9100/metrics

Node Exporter๋ฅผ ์‹คํ–‰ํ•˜๋ฉด 9100 ํฌํŠธ๋กœ ๋ฉ”ํŠธ๋ฆญ์ด ๋…ธ์ถœ๋ผ. ๋ธŒ๋ผ์šฐ์ €๋‚˜ curl๋กœ ์ ‘์†ํ•ด๋ณด๋ฉด ์—„์ฒญ๋‚˜๊ฒŒ ๋งŽ์€ ๋ฉ”ํŠธ๋ฆญ์ด ๋ณด์ผ ๊ฑฐ์•ผ! ๐Ÿ˜ฒ

node_cpu_seconds_total, node_memory_MemAvailable_bytes, node_disk_io_time_seconds_total ๊ฐ™์€ ๋ฉ”ํŠธ๋ฆญ๋“ค์ด ์‹ค์‹œ๊ฐ„์œผ๋กœ ์—…๋ฐ์ดํŠธ๋˜์ง€.

๐Ÿณ cAdvisor - ์ปจํ…Œ์ด๋„ˆ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘

Docker ์ปจํ…Œ์ด๋„ˆ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•˜๋ ค๋ฉด cAdvisor๊ฐ€ ํ•„์ˆ˜์•ผ!
cAdvisor ์‹คํ–‰
docker run -d \
  --name=cadvisor \
  --volume=/:/rootfs:ro \
  --volume=/var/run:/var/run:ro \
  --volume=/sys:/sys:ro \
  --volume=/var/lib/docker/:/var/lib/docker:ro \
  --volume=/dev/disk/:/dev/disk:ro \
  --publish=8080:8080 \
  --detach=true \
  gcr.io/cadvisor/cadvisor:latest
โ˜• Application Metrics - ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ

Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ์˜ˆ์‹œ๋ฅผ ๋ณด์—ฌ์ค„๊ฒŒ!
build.gradle (Spring Boot)
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'io.micrometer:micrometer-registry-prometheus'
}
application.yml
management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus,metrics
  metrics:
    export:
      prometheus:
        enabled: true
    tags:
      application: ${spring.application.name}
      environment: production
  endpoint:
    prometheus:
      enabled: true
์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ ์ถ”๊ฐ€ (Java)
import io.micrometer.core.instrument.Counter;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Timer;
import org.springframework.stereotype.Service;

@Service
public class OrderService {
    
    private final Counter orderCounter;
    private final Timer orderProcessingTimer;
    
    public OrderService(MeterRegistry registry) {
        this.orderCounter = Counter.builder("orders.created")
            .description("Total number of orders created")
            .tag("type", "online")
            .register(registry);
            
        this.orderProcessingTimer = Timer.builder("orders.processing.time")
            .description("Order processing time")
            .register(registry);
    }
    
    public void createOrder(Order order) {
        orderProcessingTimer.record(() -> {
            // ์ฃผ๋ฌธ ์ฒ˜๋ฆฌ ๋กœ์ง
            processOrder(order);
            orderCounter.increment();
        });
    }
}

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด /actuator/prometheus ์—”๋“œํฌ์ธํŠธ๋กœ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ฉ”ํŠธ๋ฆญ์ด ๋…ธ์ถœ๋ผ. ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ๋งž๋Š” ์ปค์Šคํ…€ ๋ฉ”ํŠธ๋ฆญ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ๊ฐ€๋Šฅํ•ด! ๐Ÿ’ช

Exporter ํฌํŠธ ์šฉ๋„ ์ฃผ์š” ๋ฉ”ํŠธ๋ฆญ
Node Exporter 9100 ์‹œ์Šคํ…œ ๋ฉ”ํŠธ๋ฆญ CPU, ๋ฉ”๋ชจ๋ฆฌ, ๋””์Šคํฌ, ๋„คํŠธ์›Œํฌ
cAdvisor 8080 ์ปจํ…Œ์ด๋„ˆ ๋ฉ”ํŠธ๋ฆญ ์ปจํ…Œ์ด๋„ˆ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋Ÿ‰
MySQL Exporter 9104 MySQL ๋ฉ”ํŠธ๋ฆญ ์ฟผ๋ฆฌ ์„ฑ๋Šฅ, ์ปค๋„ฅ์…˜ ์ˆ˜
Redis Exporter 9121 Redis ๋ฉ”ํŠธ๋ฆญ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰, ํ‚ค ํ†ต๊ณ„
Nginx Exporter 9113 ์›น์„œ๋ฒ„ ๋ฉ”ํŠธ๋ฆญ ์š”์ฒญ ์ˆ˜, ์‘๋‹ต ์‹œ๊ฐ„
Blackbox Exporter 9115 ์—”๋“œํฌ์ธํŠธ ์ฒดํฌ HTTP, TCP, ICMP ํ”„๋กœ๋ธŒ

๐ŸŽจ Grafana ์„ค์น˜ ๋ฐ ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ

์ด์ œ ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฉ‹์ง€๊ฒŒ ์‹œ๊ฐํ™”ํ•  ์ฐจ๋ก€์•ผ! Grafana๋Š” ์ •๋ง ์ง๊ด€์ ์ด๊ณ  ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ. ๐ŸŽฏ

๐Ÿ“ฆ Grafana ์„ค์น˜
Docker Compose์— Grafana ์ถ”๊ฐ€
version: '3.8'

services:
  prometheus:
    # ... (์ด์ „ ์„ค์ •)

  grafana:
    image: grafana/grafana:latest
    container_name: grafana
    ports:
      - "3000:3000"
    environment:
      - GF_SECURITY_ADMIN_USER=admin
      - GF_SECURITY_ADMIN_PASSWORD=your-secure-password
      - GF_USERS_ALLOW_SIGN_UP=false
      - GF_SERVER_ROOT_URL=http://grafana.yourdomain.com
      - GF_INSTALL_PLUGINS=grafana-piechart-panel,grafana-worldmap-panel
    volumes:
      - grafana-data:/var/lib/grafana
      - ./grafana/provisioning:/etc/grafana/provisioning
    depends_on:
      - prometheus
    restart: unless-stopped
    networks:
      - monitoring

volumes:
  prometheus-data:
  grafana-data:

networks:
  monitoring:
    driver: bridge

Grafana๋ฅผ ์‹คํ–‰ํ•˜๊ณ  http://localhost:3000์œผ๋กœ ์ ‘์†ํ•˜๋ฉด ๋กœ๊ทธ์ธ ํ™”๋ฉด์ด ๋‚˜์™€. ๊ธฐ๋ณธ ๊ณ„์ •์€ admin/admin์ด์ง€๋งŒ, ์œ„ ์„ค์ •์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณ€๊ฒฝํ–ˆ์œผ๋‹ˆ ๊ทธ๊ฑธ ์‚ฌ์šฉํ•˜๋ฉด ๋ผ! ๐Ÿ”

๐Ÿ”— Prometheus ๋ฐ์ดํ„ฐ ์†Œ์Šค ์—ฐ๊ฒฐ

Grafana์—์„œ ๊ฐ€์žฅ ๋จผ์ € ํ•  ์ผ์€ Prometheus๋ฅผ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์ถ”๊ฐ€ํ•˜๋Š” ๊ฑฐ์•ผ. ์ˆ˜๋™์œผ๋กœ ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, Provisioning์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™ํ™”ํ•  ์ˆ˜ ์žˆ์–ด!

grafana/provisioning/datasources/prometheus.yml
apiVersion: 1

datasources:
  - name: Prometheus
    type: prometheus
    access: proxy
    url: http://prometheus:9090
    isDefault: true
    editable: true
    jsonData:
      timeInterval: 15s
      queryTimeout: 60s
      httpMethod: POST
    version: 1
๐Ÿ“Š ๋Œ€์‹œ๋ณด๋“œ ๋งŒ๋“ค๊ธฐ

์ด์ œ ๋ณธ๊ฒฉ์ ์œผ๋กœ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ๋งŒ๋“ค์–ด๋ณด์ž! Grafana์˜ ์ง„๊ฐ€๋Š” ์—ฌ๊ธฐ์„œ ๋ฐœํœ˜๋ผ. ๐Ÿ˜Ž

์ฒ˜์Œ๋ถ€ํ„ฐ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ์ง€๋งŒ, Grafana Labs์—์„œ ์ œ๊ณตํ•˜๋Š” ์ปค๋ฎค๋‹ˆํ‹ฐ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ importํ•˜๋Š” ๊ฒŒ ํ›จ์”ฌ ๋น ๋ฅด๊ณ  ํšจ์œจ์ ์ด์•ผ!

โœจ ์ถ”์ฒœ ๋Œ€์‹œ๋ณด๋“œ ID โ€ข Node Exporter Full: 1860 - ์„œ๋ฒ„ ์ „์ฒด ๋ฉ”ํŠธ๋ฆญ์„ ํ•œ๋ˆˆ์—!
โ€ข Docker Container & Host Metrics: 10619 - Docker ํ™˜๊ฒฝ ํ•„์ˆ˜
โ€ข Kubernetes Cluster Monitoring: 7249 - K8s ํด๋Ÿฌ์Šคํ„ฐ ์ „์ฒด ๋ทฐ
โ€ข Spring Boot Statistics: 12900 - Spring Boot ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜
โ€ข MySQL Overview: 7362 - MySQL ์„ฑ๋Šฅ ๋ชจ๋‹ˆํ„ฐ๋ง

๋Œ€์‹œ๋ณด๋“œ๋ฅผ importํ•˜๋Š” ๋ฐฉ๋ฒ•์€ ๊ฐ„๋‹จํ•ด:
1. Grafana ์ขŒ์ธก ๋ฉ”๋‰ด์—์„œ "+" โ†’ "Import" ํด๋ฆญ
2. ๋Œ€์‹œ๋ณด๋“œ ID ์ž…๋ ฅ (์˜ˆ: 1860)
3. Prometheus ๋ฐ์ดํ„ฐ ์†Œ์Šค ์„ ํƒ
4. Import ๋ฒ„ํŠผ ํด๋ฆญ!

Grafana ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ ์š”์†Œ ๊ทธ๋ž˜ํ”„ ํŒจ๋„ ๊ฒŒ์ด์ง€ ํŒจ๋„ 73% Stat ํŒจ๋„ 1,234 โ†‘ 15.3% ํ…Œ์ด๋ธ” ํŒจ๋„ ์„œ๋ฒ„๋ช… ์ƒํƒœ server-01 server-02 server-03 ํžˆํŠธ๋งต ํŒจ๋„ ๋ฐ” ์ฐจํŠธ ํŒจ๋„ ๋ณ€์ˆ˜์™€ ํ…œํ”Œ๋ฆฟ ํ™˜๊ฒฝ: Production ์„œ๋ฒ„: server-01 ๋™์ ์œผ๋กœ ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ํ•„ํ„ฐ๋งํ•˜๊ณ  ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•˜๊ฒŒ ๋งŒ๋“ค์–ด์š”!
๐ŸŽฏ ์ปค์Šคํ…€ ํŒจ๋„ ๋งŒ๋“ค๊ธฐ

์ด์ œ ์ง์ ‘ ํŒจ๋„์„ ๋งŒ๋“ค์–ด๋ณด์ž! PromQL์„ ์‚ฌ์šฉํ•ด์„œ ์›ํ•˜๋Š” ๋ฉ”ํŠธ๋ฆญ์„ ์ฟผ๋ฆฌํ•˜๊ณ  ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ์–ด. ๐Ÿ’ก

๐Ÿ“ˆ ์œ ์šฉํ•œ PromQL ์ฟผ๋ฆฌ ์˜ˆ์‹œ

CPU ์‚ฌ์šฉ๋ฅ  (%):

100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)


๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ  (%):
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100


๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ  (%):
100 - ((node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) * 100)


HTTP ์š”์ฒญ ์†๋„ (req/s):
rate(http_requests_total[5m])

์‘๋‹ต ์‹œ๊ฐ„ 95 ๋ฐฑ๋ถ„์œ„์ˆ˜:
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))


์—๋Ÿฌ์œจ (%):
(sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))) * 100

PromQL์€ ์ฒ˜์Œ์—” ์ข€ ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์–ด. ํ•˜์ง€๋งŒ ์ต์ˆ™ํ•ด์ง€๋ฉด ์ •๋ง ๊ฐ•๋ ฅํ•œ ๋„๊ตฌ์•ผ! ๐Ÿš€

rate(), increase(), sum(), avg() ๊ฐ™์€ ํ•จ์ˆ˜๋“ค์„ ์กฐํ•ฉํ•˜๋ฉด ๊ฑฐ์˜ ๋ชจ๋“  ๋ฉ”ํŠธ๋ฆญ์„ ์›ํ•˜๋Š” ํ˜•ํƒœ๋กœ ๊ฐ€๊ณตํ•  ์ˆ˜ ์žˆ์ง€.

๐Ÿ’ก ๋Œ€์‹œ๋ณด๋“œ ๋””์ž์ธ ํŒ 1. ๊ณ„์ธต์  ๊ตฌ์กฐ: ์ „์ฒด โ†’ ์ƒ์„ธ ์ˆœ์„œ๋กœ ํŒจ๋„ ๋ฐฐ์น˜
2. ์ƒ‰์ƒ ์ผ๊ด€์„ฑ: ๊ฐ™์€ ๋ฉ”ํŠธ๋ฆญ์€ ๊ฐ™์€ ์ƒ‰์ƒ ์‚ฌ์šฉ
3. ์ž„๊ณ„๊ฐ’ ์„ค์ •: ์ •์ƒ/๊ฒฝ๊ณ /์œ„ํ—˜ ๊ตฌ๊ฐ„์„ ์ƒ‰์ƒ์œผ๋กœ ํ‘œ์‹œ
4. ๋ณ€์ˆ˜ ํ™œ์šฉ: ํ™˜๊ฒฝ, ์„œ๋ฒ„, ์„œ๋น„์Šค๋ณ„๋กœ ํ•„ํ„ฐ๋ง ๊ฐ€๋Šฅํ•˜๊ฒŒ
5. ๋งํฌ ์—ฐ๊ฒฐ: ํŒจ๋„ ํด๋ฆญ ์‹œ ์ƒ์„ธ ๋Œ€์‹œ๋ณด๋“œ๋กœ ์ด๋™
๐Ÿ”” ์•Œ๋ฆผ ์„ค์ •

Grafana์—์„œ๋„ ์•Œ๋ฆผ์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์–ด! Alerting ๋ฉ”๋‰ด์—์„œ Alert Rule์„ ๋งŒ๋“ค์–ด๋ณด์ž.

์•Œ๋ฆผ ๊ทœ์น™ ์˜ˆ์‹œ (JSON)
{
  "alert": "HighCPUUsage",
  "expr": "100 - (avg by(instance) (rate(node_cpu_seconds_total{mode=\"idle\"}[5m])) * 100) > 80",
  "for": "5m",
  "labels": {
    "severity": "warning",
    "team": "infrastructure"
  },
  "annotations": {
    "summary": "High CPU usage detected on {{ $labels.instance }}",
    "description": "CPU usage is {{ $value }}% for more than 5 minutes"
  }
}

์•Œ๋ฆผ์€ Slack, Email, PagerDuty, Webhook ๋“ฑ ๋‹ค์–‘ํ•œ ์ฑ„๋„๋กœ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์–ด. ํŒ€์˜ ์ปค๋ฎค๋‹ˆ์ผ€์ด์…˜ ๋„๊ตฌ์™€ ์—ฐ๋™ํ•˜๋ฉด ์ •๋ง ํŽธ๋ฆฌํ•˜์ง€! ๐Ÿ“ฑ

โšก ๊ณ ๊ธ‰ ์„ค์ • ๋ฐ ์ตœ์ ํ™”

๊ธฐ๋ณธ ๊ตฌ์ถ•์€ ๋๋‚ฌ์–ด! ์ด์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์•ˆ์ •์ ์œผ๋กœ ์šด์˜ํ•˜๊ธฐ ์œ„ํ•œ ๊ณ ๊ธ‰ ์„ค์ •๋“ค์„ ์•Œ์•„๋ณด์ž. ๐ŸŽ“

๐Ÿ’พ ๋ฐ์ดํ„ฐ ๋ณด๊ด€ ๋ฐ ์Šคํ† ๋ฆฌ์ง€ ์ตœ์ ํ™”

Prometheus๋Š” ์‹œ๊ณ„์—ด ๋ฐ์ดํ„ฐ๋ฅผ ๋กœ์ปฌ ๋””์Šคํฌ์— ์ €์žฅํ•ด. ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋ฐ์ดํ„ฐ๊ฐ€ ๊ณ„์† ์Œ“์ด๋‹ˆ๊นŒ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜์ง€!

Prometheus ์Šคํ† ๋ฆฌ์ง€ ์„ค์ •
# ๋ฐ์ดํ„ฐ ๋ณด๊ด€ ๊ธฐ๊ฐ„ ์„ค์ •
--storage.tsdb.retention.time=30d

# ์ตœ๋Œ€ ์Šคํ† ๋ฆฌ์ง€ ํฌ๊ธฐ ์„ค์ •
--storage.tsdb.retention.size=50GB

# ์••์ถ• ์„ค์ •
--storage.tsdb.min-block-duration=2h
--storage.tsdb.max-block-duration=24h

# WAL ์••์ถ• ํ™œ์„ฑํ™”
--storage.tsdb.wal-compression

๐Ÿ“Š ์Šคํ† ๋ฆฌ์ง€ ์šฉ๋Ÿ‰ ๊ณ„์‚ฐ

๋Œ€๋žต์ ์ธ ๊ณ„์‚ฐ ๊ณต์‹:
ํ•„์š” ์šฉ๋Ÿ‰ = ์ƒ˜ํ”Œ ์ˆ˜ ร— ์ƒ˜ํ”Œ ํฌ๊ธฐ ร— ๋ณด๊ด€ ๊ธฐ๊ฐ„

์˜ˆ์‹œ: 1000๊ฐœ ๋ฉ”ํŠธ๋ฆญ, 15์ดˆ ๊ฐ„๊ฒฉ, 30์ผ ๋ณด๊ด€
โ€ข ์ดˆ๋‹น ์ƒ˜ํ”Œ: 1000 / 15 = 67๊ฐœ
โ€ข ์ผ์ผ ์ƒ˜ํ”Œ: 67 ร— 86400 = 5,788,800๊ฐœ
โ€ข 30์ผ ์ƒ˜ํ”Œ: 5,788,800 ร— 30 = 173,664,000๊ฐœ
โ€ข ์ƒ˜ํ”Œ๋‹น ํฌ๊ธฐ: ์•ฝ 1-2 bytes
โ€ข ์ด ์šฉ๋Ÿ‰: ์•ฝ 173MB ~ 347MB (์••์ถ• ์ „)
โ€ข ์••์ถ• ํ›„: ์•ฝ 50MB ~ 100MB

๐Ÿ”„ Federation - ๊ณ„์ธต์  ๋ชจ๋‹ˆํ„ฐ๋ง

์—ฌ๋Ÿฌ ๋ฐ์ดํ„ฐ์„ผํ„ฐ๋‚˜ ํด๋Ÿฌ์Šคํ„ฐ๋ฅผ ๋ชจ๋‹ˆํ„ฐ๋งํ•œ๋‹ค๋ฉด Federation์ด ๋‹ต์ด์•ผ! ์ค‘์•™ Prometheus๊ฐ€ ์—ฌ๋Ÿฌ ํ•˜์œ„ Prometheus์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜๋Š” ๊ตฌ์กฐ์ง€. ๐ŸŒ

Federation ์„ค์ •
scrape_configs:
  - job_name: 'federate'
    scrape_interval: 30s
    honor_labels: true
    metrics_path: '/federate'
    params:
      'match[]':
        - '{job="prometheus"}'
        - '{__name__=~"job:.*"}'
        - '{__name__=~"node_.*"}'
    static_configs:
      - targets:
          - 'prometheus-dc1:9090'
          - 'prometheus-dc2:9090'
          - 'prometheus-dc3:9090'
        labels:
          datacenter: 'global'
Federation ์•„ํ‚คํ…์ฒ˜ Global Prometheus ์ค‘์•™ ์ง‘๊ณ„ ์„œ๋ฒ„ Prometheus DC1 ์„œ์šธ ๋ฆฌ์ „ Prometheus DC2 ๋„์ฟ„ ๋ฆฌ์ „ Prometheus DC3 ์‹ฑ๊ฐ€ํฌ๋ฅด ๋ฆฌ์ „ Federation Federation Federation ์„œ๋ฒ„ 100๋Œ€ ์„œ๋ฒ„ 150๋Œ€ ์„œ๋ฒ„ 80๋Œ€ ์ด 330๋Œ€ ์„œ๋ฒ„๋ฅผ ์ค‘์•™์—์„œ ํ†ตํ•ฉ ๋ชจ๋‹ˆํ„ฐ๋ง!
๐ŸŽฏ Recording Rules - ์ฟผ๋ฆฌ ์„ฑ๋Šฅ ์ตœ์ ํ™”

๋ณต์žกํ•œ PromQL ์ฟผ๋ฆฌ๋ฅผ ๋งค๋ฒˆ ์‹คํ–‰ํ•˜๋ฉด ๋А๋ ค์งˆ ์ˆ˜ ์žˆ์–ด. Recording Rules๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฏธ๋ฆฌ ๊ณ„์‚ฐํ•ด์„œ ์ €์žฅํ•  ์ˆ˜ ์žˆ์ง€! โšก

recording_rules.yml
groups:
  - name: node_rules
    interval: 30s
    rules:
      # CPU ์‚ฌ์šฉ๋ฅ  ์‚ฌ์ „ ๊ณ„์‚ฐ
      - record: instance:node_cpu_utilization:rate5m
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
      
      # ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ  ์‚ฌ์ „ ๊ณ„์‚ฐ
      - record: instance:node_memory_utilization:ratio
        expr: 1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)
      
      # ๋””์Šคํฌ ์‚ฌ์šฉ๋ฅ  ์‚ฌ์ „ ๊ณ„์‚ฐ
      - record: instance:node_disk_utilization:ratio
        expr: 1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})
      
      # ๋„คํŠธ์›Œํฌ ํŠธ๋ž˜ํ”ฝ ์‚ฌ์ „ ๊ณ„์‚ฐ
      - record: instance:node_network_receive_bytes:rate5m
        expr: rate(node_network_receive_bytes_total[5m])
      
      - record: instance:node_network_transmit_bytes:rate5m
        expr: rate(node_network_transmit_bytes_total[5m])

  - name: application_rules
    interval: 30s
    rules:
      # HTTP ์š”์ฒญ ์†๋„
      - record: job:http_requests:rate5m
        expr: sum by(job, status) (rate(http_requests_total[5m]))
      
      # ์—๋Ÿฌ์œจ
      - record: job:http_errors:rate5m
        expr: sum by(job) (rate(http_requests_total{status=~"5.."}[5m]))
      
      # ํ‰๊ท  ์‘๋‹ต ์‹œ๊ฐ„
      - record: job:http_request_duration:avg
        expr: |
          sum by(job) (rate(http_request_duration_seconds_sum[5m]))
          /
          sum by(job) (rate(http_request_duration_seconds_count[5m]))

Recording Rules๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋Œ€์‹œ๋ณด๋“œ ๋กœ๋”ฉ ์†๋„๊ฐ€ ์—„์ฒญ ๋นจ๋ผ์ ธ! ํŠนํžˆ ๋ณต์žกํ•œ ์ง‘๊ณ„ ์ฟผ๋ฆฌ๋‚˜ ์—ฌ๋Ÿฌ ํŒจ๋„์—์„œ ๊ฐ™์€ ๊ณ„์‚ฐ์„ ๋ฐ˜๋ณตํ•  ๋•Œ ํšจ๊ณผ์ ์ด์•ผ. ๐Ÿš€

๐Ÿ” ๋ณด์•ˆ ์„ค์ •

ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋Š” ๋ณด์•ˆ์ด ์ •๋ง ์ค‘์š”ํ•ด! ๊ธฐ๋ณธ ์„ค์ •์œผ๋กœ๋Š” ๋ˆ„๊ตฌ๋‚˜ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๐Ÿ˜ฑ

Prometheus ๊ธฐ๋ณธ ์ธ์ฆ ์„ค์ •
# web.yml ํŒŒ์ผ ์ƒ์„ฑ
basic_auth_users:
  admin: $2y$10$hashed_password_here

# Prometheus ์‹คํ–‰ ์‹œ ์˜ต์…˜ ์ถ”๊ฐ€
--web.config.file=web.yml
Grafana ๋ณด์•ˆ ์„ค์ •
# grafana.ini ๋˜๋Š” ํ™˜๊ฒฝ๋ณ€์ˆ˜
[security]
admin_user = admin
admin_password = your-secure-password
secret_key = your-secret-key-for-signing

[auth]
disable_login_form = false
disable_signout_menu = false

[auth.anonymous]
enabled = false

[auth.basic]
enabled = true

[users]
allow_sign_up = false
allow_org_create = false

[session]
cookie_secure = true
cookie_samesite = strict
โš ๏ธ ๋ณด์•ˆ ์ฒดํฌ๋ฆฌ์ŠคํŠธ
  • โœ… ๊ธฐ๋ณธ ๋น„๋ฐ€๋ฒˆํ˜ธ ๋ณ€๊ฒฝ
  • โœ… HTTPS ์‚ฌ์šฉ (Let's Encrypt ๋“ฑ)
  • โœ… ๋ฐฉํ™”๋ฒฝ ์„ค์ • (ํ•„์š”ํ•œ ํฌํŠธ๋งŒ ์˜คํ”ˆ)
  • โœ… ์ธ์ฆ ํ™œ์„ฑํ™”
  • โœ… ์ •๊ธฐ์ ์ธ ์—…๋ฐ์ดํŠธ
  • โœ… ์ ‘๊ทผ ๋กœ๊ทธ ๋ชจ๋‹ˆํ„ฐ๋ง
  • โœ… ๋ฏผ๊ฐํ•œ ๋ฉ”ํŠธ๋ฆญ ํ•„ํ„ฐ๋ง
๐Ÿ“ˆ ์„ฑ๋Šฅ ํŠœ๋‹
ํ•ญ๋ชฉ ๊ธฐ๋ณธ๊ฐ’ ๊ถŒ์žฅ๊ฐ’ ์„ค๋ช…
scrape_interval 1m 15s ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ ์ฃผ๊ธฐ
scrape_timeout 10s 10s ์ˆ˜์ง‘ ํƒ€์ž„์•„์›ƒ
evaluation_interval 1m 15s ๊ทœ์น™ ํ‰๊ฐ€ ์ฃผ๊ธฐ
retention.time 15d 30d ๋ฐ์ดํ„ฐ ๋ณด๊ด€ ๊ธฐ๊ฐ„
query.timeout 2m 1m ์ฟผ๋ฆฌ ํƒ€์ž„์•„์›ƒ
query.max-samples 50000000 50000000 ์ตœ๋Œ€ ์ƒ˜ํ”Œ ์ˆ˜

๐Ÿ’ก ์„ฑ๋Šฅ ์ตœ์ ํ™” ํŒ

1. ๋ฉ”ํŠธ๋ฆญ ํ•„ํ„ฐ๋ง: ๋ถˆํ•„์š”ํ•œ ๋ฉ”ํŠธ๋ฆญ์€ ์ˆ˜์ง‘ํ•˜์ง€ ์•Š๊ธฐ
2. Recording Rules ํ™œ์šฉ: ๋ณต์žกํ•œ ์ฟผ๋ฆฌ ์‚ฌ์ „ ๊ณ„์‚ฐ
3. ์ ์ ˆํ•œ scrape_interval: ๋„ˆ๋ฌด ์งง์œผ๋ฉด ๋ถ€ํ•˜ ์ฆ๊ฐ€
4. ๋ ˆ์ด๋ธ” ์ตœ์†Œํ™”: ์นด๋””๋„๋ฆฌํ‹ฐ ํญ๋ฐœ ๋ฐฉ์ง€
5. ๋ฆฌ์†Œ์Šค ๋ชจ๋‹ˆํ„ฐ๋ง: Prometheus ์ž์ฒด๋„ ๋ชจ๋‹ˆํ„ฐ๋ง
6. SSD ์‚ฌ์šฉ: TSDB๋Š” I/O ์ง‘์•ฝ์ 
7. ๋ฉ”๋ชจ๋ฆฌ ์ถฉ๋ถ„ํžˆ ํ• ๋‹น: ์ตœ์†Œ 2GB ์ด์ƒ ๊ถŒ์žฅ

๐Ÿšจ ์•Œ๋ฆผ ์‹œ์Šคํ…œ ๊ตฌ์ถ•

๋ชจ๋‹ˆํ„ฐ๋ง์˜ ๊ฝƒ์€ ์•Œ๋ฆผ์ด์•ผ! ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๋•Œ ์ฆ‰์‹œ ์•Œ์•„์•ผ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๊ฑฐ๋“ . ๐Ÿ””

โšก Alertmanager ์„ค์ •
alertmanager.yml
global:
  resolve_timeout: 5m
  slack_api_url: 'https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK'

# ์•Œ๋ฆผ ๋ผ์šฐํŒ… ๊ทœ์น™
route:
  group_by: ['alertname', 'cluster', 'service']
  group_wait: 10s
  group_interval: 10s
  repeat_interval: 12h
  receiver: 'default'
  
  routes:
    # ์‹ฌ๊ฐํ•œ ์•Œ๋ฆผ์€ ์ฆ‰์‹œ ์ „์†ก
    - match:
        severity: critical
      receiver: 'pagerduty'
      continue: true
    
    # ๊ฒฝ๊ณ ๋Š” Slack์œผ๋กœ
    - match:
        severity: warning
      receiver: 'slack-warnings'
    
    # ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ๊ด€๋ จ์€ DBA ํŒ€์œผ๋กœ
    - match_re:
        service: ^(mysql|postgresql|redis)$
      receiver: 'dba-team'

# ์•Œ๋ฆผ ์ˆ˜์‹ ์ž ์„ค์ •
receivers:
  - name: 'default'
    slack_configs:
      - channel: '#monitoring'
        title: '๐Ÿ”” {{ .GroupLabels.alertname }}'
        text: |
          {{ range .Alerts }}
          *Alert:* {{ .Labels.alertname }}
          *Severity:* {{ .Labels.severity }}
          *Instance:* {{ .Labels.instance }}
          *Description:* {{ .Annotations.description }}
          {{ end }}

  - name: 'slack-warnings'
    slack_configs:
      - channel: '#alerts-warning'
        title: 'โš ๏ธ {{ .GroupLabels.alertname }}'
        color: 'warning'

  - name: 'pagerduty'
    pagerduty_configs:
      - service_key: 'YOUR_PAGERDUTY_KEY'
        description: '{{ .GroupLabels.alertname }}'

  - name: 'dba-team'
    email_configs:
      - to: 'dba-team@company.com'
        from: 'alertmanager@company.com'
        smarthost: 'smtp.gmail.com:587'
        auth_username: 'alertmanager@company.com'
        auth_password: 'your-password'

# ์•Œ๋ฆผ ์–ต์ œ ๊ทœ์น™
inhibit_rules:
  # ๋…ธ๋“œ ๋‹ค์šด ์‹œ ํ•ด๋‹น ๋…ธ๋“œ์˜ ๋‹ค๋ฅธ ์•Œ๋ฆผ ์–ต์ œ
  - source_match:
      severity: 'critical'
      alertname: 'NodeDown'
    target_match:
      severity: 'warning'
    equal: ['instance']
๐Ÿ“‹ ์•Œ๋ฆผ ๊ทœ์น™ ์ž‘์„ฑ
alert_rules.yml
groups:
  - name: infrastructure_alerts
    interval: 30s
    rules:
      # ๋…ธ๋“œ ๋‹ค์šด ๊ฐ์ง€
      - alert: NodeDown
        expr: up{job="node-exporter"} == 0
        for: 1m
        labels:
          severity: critical
          team: infrastructure
        annotations:
          summary: "Node {{ $labels.instance }} is down"
          description: "{{ $labels.instance }} has been down for more than 1 minute"

      # ๋†’์€ CPU ์‚ฌ์šฉ๋ฅ 
      - alert: HighCPUUsage
        expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
        for: 5m
        labels:
          severity: warning
          team: infrastructure
        annotations:
          summary: "High CPU usage on {{ $labels.instance }}"
          description: "CPU usage is {{ $value | humanize }}% for more than 5 minutes"

      # ๋†’์€ ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ 
      - alert: HighMemoryUsage
        expr: (1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100 > 85
        for: 5m
        labels:
          severity: warning
          team: infrastructure
        annotations:
          summary: "High memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value | humanize }}%"

      # ๋””์Šคํฌ ๊ณต๊ฐ„ ๋ถ€์กฑ
      - alert: DiskSpaceLow
        expr: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 85
        for: 5m
        labels:
          severity: warning
          team: infrastructure
        annotations:
          summary: "Low disk space on {{ $labels.instance }}"
          description: "Disk usage is {{ $value | humanize }}%"

      # ๋””์Šคํฌ ๊ณต๊ฐ„ ์‹ฌ๊ฐ
      - alert: DiskSpaceCritical
        expr: (1 - (node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"})) * 100 > 95
        for: 1m
        labels:
          severity: critical
          team: infrastructure
        annotations:
          summary: "Critical disk space on {{ $labels.instance }}"
          description: "Disk usage is {{ $value | humanize }}%. Immediate action required!"

  - name: application_alerts
    interval: 30s
    rules:
      # ๋†’์€ ์—๋Ÿฌ์œจ
      - alert: HighErrorRate
        expr: |
          (
            sum by(job) (rate(http_requests_total{status=~"5.."}[5m]))
            /
            sum by(job) (rate(http_requests_total[5m]))
          ) * 100 > 5
        for: 5m
        labels:
          severity: critical
          team: backend
        annotations:
          summary: "High error rate in {{ $labels.job }}"
          description: "Error rate is {{ $value | humanize }}%"

      # ๋А๋ฆฐ ์‘๋‹ต ์‹œ๊ฐ„
      - alert: SlowResponseTime
        expr: |
          histogram_quantile(0.95,
            sum by(job, le) (rate(http_request_duration_seconds_bucket[5m]))
          ) > 1
        for: 5m
        labels:
          severity: warning
          team: backend
        annotations:
          summary: "Slow response time in {{ $labels.job }}"
          description: "95th percentile response time is {{ $value | humanize }}s"

      # ์„œ๋น„์Šค ๋‹ค์šด
      - alert: ServiceDown
        expr: up{job="application"} == 0
        for: 1m
        labels:
          severity: critical
          team: backend
        annotations:
          summary: "Service {{ $labels.job }} is down"
          description: "{{ $labels.instance }} has been down for more than 1 minute"

      # ๋†’์€ ์š”์ฒญ ์ˆ˜
      - alert: HighRequestRate
        expr: sum by(job) (rate(http_requests_total[5m])) > 1000
        for: 10m
        labels:
          severity: warning
          team: backend
        annotations:
          summary: "High request rate in {{ $labels.job }}"
          description: "Request rate is {{ $value | humanize }} req/s"

  - name: database_alerts
    interval: 30s
    rules:
      # MySQL ์—ฐ๊ฒฐ ์ˆ˜ ๋†’์Œ
      - alert: MySQLHighConnections
        expr: mysql_global_status_threads_connected / mysql_global_variables_max_connections * 100 > 80
        for: 5m
        labels:
          severity: warning
          team: dba
        annotations:
          summary: "High MySQL connections on {{ $labels.instance }}"
          description: "Connection usage is {{ $value | humanize }}%"

      # MySQL ์Šฌ๋กœ์šฐ ์ฟผ๋ฆฌ
      - alert: MySQLSlowQueries
        expr: rate(mysql_global_status_slow_queries[5m]) > 0.1
        for: 5m
        labels:
          severity: warning
          team: dba
        annotations:
          summary: "MySQL slow queries detected on {{ $labels.instance }}"
          description: "Slow query rate is {{ $value | humanize }} queries/s"

      # Redis ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋ฅ 
      - alert: RedisHighMemory
        expr: redis_memory_used_bytes / redis_memory_max_bytes * 100 > 90
        for: 5m
        labels:
          severity: warning
          team: dba
        annotations:
          summary: "High Redis memory usage on {{ $labels.instance }}"
          description: "Memory usage is {{ $value | humanize }}%"
์•Œ๋ฆผ ์ฒ˜๋ฆฌ ํ๋ฆ„ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘ Prometheus ๊ทœ์น™ ํ‰๊ฐ€ Alert Rules ์•Œ๋ฆผ ๋ฐœ์ƒ Alertmanager ์•Œ๋ฆผ ์ „์†ก Slack ํŒ€ ์ฑ„๋„ ์‹ค์‹œ๊ฐ„ ์•Œ๋ฆผ Email ๋‹ด๋‹น์ž ์ƒ์„ธ ์ •๋ณด PagerDuty ์˜จ์ฝœ ์—”์ง€๋‹ˆ์–ด ๊ธด๊ธ‰ ํ˜ธ์ถœ Webhook ์ž๋™ํ™” ์‹œ์Šคํ…œ ์ž๋™ ๋Œ€์‘
โœจ ์•Œ๋ฆผ ๋ฒ ์ŠคํŠธ ํ”„๋ž™ํ‹ฐ์Šค 1. ์˜๋ฏธ ์žˆ๋Š” ์•Œ๋ฆผ๋งŒ: ๋…ธ์ด์ฆˆ ์ตœ์†Œํ™”, ์‹ค์ œ ์•ก์…˜์ด ํ•„์š”ํ•œ ๊ฒƒ๋งŒ
2. ์ ์ ˆํ•œ ์ž„๊ณ„๊ฐ’: ๋„ˆ๋ฌด ๋ฏผ๊ฐํ•˜๋ฉด ํ”ผ๋กœ๋„ ์ฆ๊ฐ€
3. ๋ช…ํ™•ํ•œ ์„ค๋ช…: ๋ฌด์—‡์ด ๋ฌธ์ œ์ธ์ง€, ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ• ์ง€ ํฌํ•จ
4. ์‹ฌ๊ฐ๋„ ๊ตฌ๋ถ„: Critical, Warning, Info ๋ ˆ๋ฒจ ๋ถ„๋ฆฌ
5. ๊ทธ๋ฃนํ™”: ๊ด€๋ จ ์•Œ๋ฆผ์„ ๋ฌถ์–ด์„œ ์ „์†ก
6. ์–ต์ œ ๊ทœ์น™: ์ค‘๋ณต ์•Œ๋ฆผ ๋ฐฉ์ง€
7. ์—์Šค์ปฌ๋ ˆ์ด์…˜: ์‹œ๊ฐ„ ๊ฒฝ๊ณผ์— ๋”ฐ๋ผ ์•Œ๋ฆผ ๋ ˆ๋ฒจ ์ƒ์Šน

๐Ÿ” ์‹ค์ „ ํ™œ์šฉ ์‚ฌ๋ก€

์ด๋ก ์€ ์ถฉ๋ถ„ํžˆ ๋ฐฐ์› ์œผ๋‹ˆ ์ด์ œ ์‹ค์ „ ์‚ฌ๋ก€๋ฅผ ๋ณด์ž! ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ ์–ด๋–ป๊ฒŒ ํ™œ์šฉํ•˜๋Š”์ง€ ์•Œ์•„๋ณผ๊ฒŒ. ๐Ÿ’ผ

๐ŸŽฏ ์‚ฌ๋ก€ 1: E-์ปค๋จธ์Šค ํ”Œ๋žซํผ ๋ชจ๋‹ˆํ„ฐ๋ง

๋Œ€๊ทœ๋ชจ ์‡ผํ•‘๋ชฐ์„ ์šด์˜ํ•œ๋‹ค๊ณ  ๊ฐ€์ •ํ•ด๋ณด์ž. ์ฃผ๋ฌธ, ๊ฒฐ์ œ, ์žฌ๊ณ  ๊ด€๋ฆฌ ๋“ฑ ์—ฌ๋Ÿฌ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค๊ฐ€ ์žˆ์–ด.

๐Ÿ“Š ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์ƒ

โ€ข ์ฃผ๋ฌธ ์„œ๋น„์Šค: ์ฃผ๋ฌธ ์ƒ์„ฑ ์†๋„, ์‹คํŒจ์œจ, ์ฒ˜๋ฆฌ ์‹œ๊ฐ„
โ€ข ๊ฒฐ์ œ ์„œ๋น„์Šค: ๊ฒฐ์ œ ์„ฑ๊ณต๋ฅ , ์‘๋‹ต ์‹œ๊ฐ„, ์™ธ๋ถ€ API ์ƒํƒœ
โ€ข ์žฌ๊ณ  ์„œ๋น„์Šค: ์žฌ๊ณ  ์กฐํšŒ ์†๋„, ๋™์‹œ์„ฑ ์ด์Šˆ
โ€ข ์ธํ”„๋ผ: ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค, ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์„ฑ๋Šฅ, ์บ์‹œ ํžˆํŠธ์œจ
โ€ข ๋น„์ฆˆ๋‹ˆ์Šค: ์‹ค์‹œ๊ฐ„ ๋งค์ถœ, ์ „ํ™˜์œจ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ดํƒˆ๋ฅ 

๋น„์ฆˆ๋‹ˆ์Šค ๋ฉ”ํŠธ๋ฆญ ์˜ˆ์‹œ
// ์ฃผ๋ฌธ ์ƒ์„ฑ ๋ฉ”ํŠธ๋ฆญ
order_created_total{status="success"} 1234
order_created_total{status="failed"} 5
order_amount_sum{currency="KRW"} 15000000

// ๊ฒฐ์ œ ๋ฉ”ํŠธ๋ฆญ
payment_processed_total{method="card",status="success"} 890
payment_processed_total{method="card",status="failed"} 10
payment_processing_duration_seconds{quantile="0.95"} 0.8

// ์žฌ๊ณ  ๋ฉ”ํŠธ๋ฆญ
inventory_check_total 5678
inventory_low_stock_items 23
inventory_out_of_stock_items 3
๐ŸŽฏ ์‚ฌ๋ก€ 2: SaaS ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ชจ๋‹ˆํ„ฐ๋ง

SaaS ์„œ๋น„์Šค๋Š” ์‚ฌ์šฉ์ž ๊ฒฝํ—˜์ด ์ •๋ง ์ค‘์š”ํ•ด. ์‘๋‹ต ์‹œ๊ฐ„, ๊ฐ€์šฉ์„ฑ, ์—๋Ÿฌ์œจ์„ ์ฒ ์ €ํžˆ ๋ชจ๋‹ˆํ„ฐ๋งํ•ด์•ผ ํ•ด!

SLA ๋ชจ๋‹ˆํ„ฐ๋ง ๋Œ€์‹œ๋ณด๋“œ ์ฟผ๋ฆฌ
# ๊ฐ€์šฉ์„ฑ (Availability) - ๋ชฉํ‘œ: 99.9%
(
  sum(rate(http_requests_total{status!~"5.."}[30d]))
  /
  sum(rate(http_requests_total[30d]))
) * 100

# ์‘๋‹ต ์‹œ๊ฐ„ (Latency) - ๋ชฉํ‘œ: 95%ile < 200ms
histogram_quantile(0.95,
  sum by(le) (rate(http_request_duration_seconds_bucket[5m]))
)

# ์—๋Ÿฌ์œจ (Error Rate) - ๋ชฉํ‘œ: < 0.1%
(
  sum(rate(http_requests_total{status=~"5.."}[5m]))
  /
  sum(rate(http_requests_total[5m]))
) * 100

# ์ฒ˜๋ฆฌ๋Ÿ‰ (Throughput)
sum(rate(http_requests_total[5m]))

SLA ๋‹ฌ์„ฑ๋ฅ 

99.95%

์ง€๋‚œ 30์ผ ํ‰๊ท 

๐ŸŽฏ ์‚ฌ๋ก€ 3: Kubernetes ํด๋Ÿฌ์Šคํ„ฐ ๋ชจ๋‹ˆํ„ฐ๋ง

Kubernetes ํ™˜๊ฒฝ์€ ๋™์ ์ด๋ผ ๋ชจ๋‹ˆํ„ฐ๋ง์ด ๋” ๋ณต์žกํ•ด. ํŒŒ๋“œ๊ฐ€ ๊ณ„์† ์ƒ์„ฑ๋˜๊ณ  ์‚ญ์ œ๋˜๋‹ˆ๊นŒ!

Kubernetes ํ•ต์‹ฌ ๋ฉ”ํŠธ๋ฆญ
# ํŒŒ๋“œ ์ƒํƒœ
sum by(namespace, pod) (kube_pod_status_phase{phase="Running"})
sum by(namespace, pod) (kube_pod_status_phase{phase="Pending"})
sum by(namespace, pod) (kube_pod_status_phase{phase="Failed"})

# ์ปจํ…Œ์ด๋„ˆ ์žฌ์‹œ์ž‘ ํšŸ์ˆ˜
sum by(namespace, pod) (rate(kube_pod_container_status_restarts_total[5m]))

# ๋…ธ๋“œ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋ฅ 
sum by(node) (
  node_memory_MemTotal_bytes - node_memory_MemAvailable_bytes
) / sum by(node) (node_memory_MemTotal_bytes) * 100

# ํŒŒ๋“œ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ๋ฅ 
sum by(namespace, pod) (
  rate(container_cpu_usage_seconds_total[5m])
)

# HPA ์ƒํƒœ
kube_horizontalpodautoscaler_status_current_replicas
kube_horizontalpodautoscaler_status_desired_replicas

# PVC ์‚ฌ์šฉ๋ฅ 
(
  kubelet_volume_stats_used_bytes
  /
  kubelet_volume_stats_capacity_bytes
) * 100

์žฌ๋Šฅ๋„ท ๊ฐ™์€ ํ”Œ๋žซํผ์—์„œ DevOps ์ „๋ฌธ๊ฐ€๋ฅผ ์ฐพ์•„ ์ปจ์„คํŒ…์„ ๋ฐ›์œผ๋ฉด, ์ด๋Ÿฐ ์‹ค์ „ ๋…ธํ•˜์šฐ๋ฅผ ์ง์ ‘ ๋ฐฐ์šธ ์ˆ˜ ์žˆ์–ด! ํŠนํžˆ ์ฒ˜์Œ ๊ตฌ์ถ•ํ•  ๋•Œ๋Š” ๊ฒฝํ—˜์ž์˜ ์กฐ์–ธ์ด ์ •๋ง ํฐ ๋„์›€์ด ๋˜์ง€. ๐ŸŽ“

๐Ÿ› ๏ธ ํŠธ๋Ÿฌ๋ธ”์ŠˆํŒ… ๊ฐ€์ด๋“œ

๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ๋„ ๊ฐ€๋” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒจ. ์ž์ฃผ ๋ฐœ์ƒํ•˜๋Š” ์ด์Šˆ๋“ค๊ณผ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ •๋ฆฌํ•ด๋ดค์–ด! ๐Ÿ”ง

โš ๏ธ ๋ฌธ์ œ 1: Prometheus๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ๋„ˆ๋ฌด ๋งŽ์ด ์‚ฌ์šฉํ•ด์š” ์›์ธ:
โ€ข ๋„ˆ๋ฌด ๋งŽ์€ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘
โ€ข ๋†’์€ ์นด๋””๋„๋ฆฌํ‹ฐ (๋ ˆ์ด๋ธ” ์กฐํ•ฉ์ด ๋„ˆ๋ฌด ๋งŽ์Œ)
โ€ข ๊ธด ๋ณด๊ด€ ๊ธฐ๊ฐ„

ํ•ด๊ฒฐ์ฑ…:
โ€ข ๋ถˆํ•„์š”ํ•œ ๋ฉ”ํŠธ๋ฆญ ํ•„ํ„ฐ๋ง
โ€ข ๋ ˆ์ด๋ธ” ์ˆ˜ ์ค„์ด๊ธฐ
โ€ข retention ๊ธฐ๊ฐ„ ๋‹จ์ถ•
โ€ข ๋ฉ”๋ชจ๋ฆฌ ์ฆ์„ค ๋˜๋Š” Federation ๊ตฌ์„ฑ
๋ฉ”ํŠธ๋ฆญ ํ•„ํ„ฐ๋ง ์˜ˆ์‹œ
scrape_configs:
  - job_name: 'node-exporter'
    static_configs:
      - targets: ['localhost:9100']
    metric_relabel_configs:
      # ํŠน์ • ๋ฉ”ํŠธ๋ฆญ๋งŒ ์ˆ˜์ง‘
      - source_labels: [__name__]
        regex: 'node_(cpu|memory|disk|network).*'
        action: keep
      
      # ๋ถˆํ•„์š”ํ•œ ๋ ˆ์ด๋ธ” ์ œ๊ฑฐ
      - regex: 'job'
        action: labeldrop
โš ๏ธ ๋ฌธ์ œ 2: Grafana ๋Œ€์‹œ๋ณด๋“œ๊ฐ€ ๋А๋ ค์š” ์›์ธ:
โ€ข ๋ณต์žกํ•œ PromQL ์ฟผ๋ฆฌ
โ€ข ๋„ˆ๋ฌด ๊ธด ์‹œ๊ฐ„ ๋ฒ”์œ„
โ€ข ๋งŽ์€ ํŒจ๋„ ์ˆ˜

ํ•ด๊ฒฐ์ฑ…:
โ€ข Recording Rules ์‚ฌ์šฉ
โ€ข ์ฟผ๋ฆฌ ์ตœ์ ํ™”
โ€ข ํŒจ๋„ ์ˆ˜ ์ค„์ด๊ธฐ
โ€ข ์บ์‹ฑ ํ™œ์„ฑํ™”
โš ๏ธ ๋ฌธ์ œ 3: ๋ฉ”ํŠธ๋ฆญ์ด ์ˆ˜์ง‘๋˜์ง€ ์•Š์•„์š” ์ฒดํฌ๋ฆฌ์ŠคํŠธ:
โœ… Exporter๊ฐ€ ์ •์ƒ ์‹คํ–‰ ์ค‘์ธ๊ฐ€?
โœ… ๋ฐฉํ™”๋ฒฝ์ด ํฌํŠธ๋ฅผ ๋ง‰๊ณ  ์žˆ์ง€ ์•Š์€๊ฐ€?
โœ… Prometheus ์„ค์ •์— ํƒ€๊ฒŸ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‚˜?
โœ… ๋„คํŠธ์›Œํฌ ์—ฐ๊ฒฐ์ด ์ •์ƒ์ธ๊ฐ€?
โœ… ์ธ์ฆ ์„ค์ •์ด ์˜ฌ๋ฐ”๋ฅธ๊ฐ€?
๋””๋ฒ„๊น… ๋ช…๋ น์–ด
# Exporter ์ƒํƒœ ํ™•์ธ
curl http://localhost:9100/metrics

# Prometheus ํƒ€๊ฒŸ ์ƒํƒœ ํ™•์ธ
curl http://localhost:9090/api/v1/targets

# ํŠน์ • ๋ฉ”ํŠธ๋ฆญ ์ฟผ๋ฆฌ
curl 'http://localhost:9090/api/v1/query?query=up'

# Prometheus ์„ค์ • ๊ฒ€์ฆ
promtool check config prometheus.yml

# ์•Œ๋ฆผ ๊ทœ์น™ ๊ฒ€์ฆ
promtool check rules alert_rules.yml
โš ๏ธ ๋ฌธ์ œ 4: ์•Œ๋ฆผ์ด ๋„ˆ๋ฌด ๋งŽ์ด ์™€์š” (Alert Fatigue) ํ•ด๊ฒฐ์ฑ…:
โ€ข ์ž„๊ณ„๊ฐ’ ์žฌ์กฐ์ •
โ€ข for ๊ธฐ๊ฐ„ ๋Š˜๋ฆฌ๊ธฐ
โ€ข ๊ทธ๋ฃนํ™” ์„ค์ • ๊ฐœ์„ 
โ€ข ์–ต์ œ ๊ทœ์น™ ์ถ”๊ฐ€
โ€ข ๋ถˆํ•„์š”ํ•œ ์•Œ๋ฆผ ์ œ๊ฑฐ
โœจ ์„ฑ๋Šฅ ์ง„๋‹จ ํŒ

Prometheus ์ž์ฒด ๋ฉ”ํŠธ๋ฆญ์„ ํ™œ์šฉํ•ด์„œ ์„ฑ๋Šฅ์„ ๋ชจ๋‹ˆํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์–ด:

prometheus_tsdb_head_series - ๋ฉ”๋ชจ๋ฆฌ์— ๋กœ๋“œ๋œ ์‹œ๊ณ„์—ด ์ˆ˜
prometheus_tsdb_head_chunks - ๋ฉ”๋ชจ๋ฆฌ ์ฒญํฌ ์ˆ˜
prometheus_engine_query_duration_seconds - ์ฟผ๋ฆฌ ์‹คํ–‰ ์‹œ๊ฐ„
prometheus_rule_evaluation_duration_seconds - ๊ทœ์น™ ํ‰๊ฐ€ ์‹œ๊ฐ„
prometheus_target_scrapes_exceeded_sample_limit_total
- ์ƒ˜ํ”Œ ์ œํ•œ ์ดˆ๊ณผ

๐Ÿš€ ๋‹ค์Œ ๋‹จ๊ณ„์™€ ๊ณ ๊ธ‰ ์ฃผ์ œ

๊ธฐ๋ณธ ๊ตฌ์ถ•์„ ๋งˆ์ณค๋‹ค๋ฉด ์ด์ œ ๋” ๊นŠ์ด ๋“ค์–ด๊ฐ€๋ณผ ์ฐจ๋ก€์•ผ! ๐ŸŽฏ

๐ŸŽ“ ํ•™์Šต ๋กœ๋“œ๋งต

1. Thanos ๋˜๋Š” Cortex: ์žฅ๊ธฐ ์Šคํ† ๋ฆฌ์ง€์™€ ๊ณ ๊ฐ€์šฉ์„ฑ
2. Loki: ๋กœ๊ทธ ์ง‘๊ณ„ ์‹œ์Šคํ…œ (Prometheus for logs)
3. Tempo: ๋ถ„์‚ฐ ์ถ”์  ์‹œ์Šคํ…œ
4. OpenTelemetry: ํ†ตํ•ฉ ๊ด€์ธก์„ฑ ํ”„๋ ˆ์ž„์›Œํฌ
5. Service Mesh ๋ชจ๋‹ˆํ„ฐ๋ง: Istio, Linkerd ๋ฉ”ํŠธ๋ฆญ
6. PromQL ๊ณ ๊ธ‰ ๊ธฐ๋ฒ•: ๋ณต์žกํ•œ ์ฟผ๋ฆฌ ์ž‘์„ฑ
7. ์ปค์Šคํ…€ Exporter ๊ฐœ๋ฐœ: ํŠนํ™”๋œ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘
8. GitOps ํ†ตํ•ฉ: ๋ชจ๋‹ˆํ„ฐ๋ง as Code

๐ŸŒŸ Thanos - ๋ฌดํ•œ ํ™•์žฅ ๊ฐ€๋Šฅํ•œ Prometheus

Prometheus๋Š” ๋‹จ์ผ ์„œ๋ฒ„๋ผ ํ™•์žฅ์„ฑ์— ํ•œ๊ณ„๊ฐ€ ์žˆ์–ด. Thanos๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์—ฌ๋Ÿฌ Prometheus๋ฅผ ํ†ตํ•ฉํ•˜๊ณ  ์žฅ๊ธฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•  ์ˆ˜ ์žˆ์ง€!

Thanos ์•„ํ‚คํ…์ฒ˜ ๊ตฌ์„ฑ
# Prometheus with Thanos Sidecar
prometheus:
  --storage.tsdb.min-block-duration=2h
  --storage.tsdb.max-block-duration=2h

thanos-sidecar:
  --prometheus.url=http://localhost:9090
  --tsdb.path=/prometheus
  --objstore.config-file=/etc/thanos/bucket.yml

# Thanos Query - ํ†ตํ•ฉ ์ฟผ๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค
thanos-query:
  --http-address=0.0.0.0:9090
  --store=thanos-sidecar-1:10901
  --store=thanos-sidecar-2:10901
  --store=thanos-store:10901

# Thanos Store - ์žฅ๊ธฐ ์Šคํ† ๋ฆฌ์ง€ ๊ฒŒ์ดํŠธ์›จ์ด
thanos-store:
  --data-dir=/var/thanos/store
  --objstore.config-file=/etc/thanos/bucket.yml

# Thanos Compactor - ๋ฐ์ดํ„ฐ ์••์ถ• ๋ฐ ๋‹ค์šด์ƒ˜ํ”Œ๋ง
thanos-compactor:
  --data-dir=/var/thanos/compact
  --objstore.config-file=/etc/thanos/bucket.yml
  --retention.resolution-raw=30d
  --retention.resolution-5m=90d
  --retention.resolution-1h=1y
๐Ÿ“ Loki - ๋กœ๊ทธ ์ง‘๊ณ„ ์‹œ์Šคํ…œ

๋ฉ”ํŠธ๋ฆญ๋งŒ์œผ๋กœ๋Š” ๋ถ€์กฑํ•ด! ๋กœ๊ทธ๋„ ํ•จ๊ป˜ ๋ณด๋ฉด ๋ฌธ์ œ ํ•ด๊ฒฐ์ด ํ›จ์”ฌ ์‰ฌ์›Œ์ ธ. Loki๋Š” Prometheus์ฒ˜๋Ÿผ ๋ ˆ์ด๋ธ” ๊ธฐ๋ฐ˜์œผ๋กœ ๋กœ๊ทธ๋ฅผ ์ธ๋ฑ์‹ฑํ•ด.

Loki + Promtail ์„ค์ •
# docker-compose.yml์— ์ถ”๊ฐ€
loki:
  image: grafana/loki:latest
  ports:
    - "3100:3100"
  volumes:
    - ./loki-config.yml:/etc/loki/local-config.yaml
  command: -config.file=/etc/loki/local-config.yaml

promtail:
  image: grafana/promtail:latest
  volumes:
    - /var/log:/var/log
    - ./promtail-config.yml:/etc/promtail/config.yml
  command: -config.file=/etc/promtail/config.yml

Grafana์—์„œ Loki๋ฅผ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋กœ ์ถ”๊ฐ€ํ•˜๋ฉด ๋ฉ”ํŠธ๋ฆญ๊ณผ ๋กœ๊ทธ๋ฅผ ํ•œ ํ™”๋ฉด์—์„œ ๋ณผ ์ˆ˜ ์žˆ์–ด! ์ •๋ง ๊ฐ•๋ ฅํ•˜์ง€? ๐Ÿ˜

๐Ÿ’ก ๊ด€์ธก์„ฑ์˜ 3๊ฐ€์ง€ ๊ธฐ๋‘ฅ 1. Metrics (๋ฉ”ํŠธ๋ฆญ): Prometheus - ๋ฌด์—‡์ด ์ผ์–ด๋‚˜๊ณ  ์žˆ๋Š”๊ฐ€?
2. Logs (๋กœ๊ทธ): Loki - ์™œ ์ผ์–ด๋‚ฌ๋Š”๊ฐ€?
3. Traces (์ถ”์ ): Tempo/Jaeger - ์–ด๋–ป๊ฒŒ ์ „ํŒŒ๋˜์—ˆ๋Š”๊ฐ€?

์ด ์„ธ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ๊ฐ–์ถ”๋ฉด ์™„๋ฒฝํ•œ ๊ด€์ธก์„ฑ์„ ํ™•๋ณดํ•  ์ˆ˜ ์žˆ์–ด!

๐Ÿ“š ๋งˆ๋ฌด๋ฆฌํ•˜๋ฉฐ

์™€! ์—ฌ๊ธฐ๊นŒ์ง€ ์ •๋ง ๊ธด ์—ฌ์ •์ด์—ˆ์–ด. ๐ŸŽ‰

Prometheus์™€ Grafana๋ฅผ ํ™œ์šฉํ•œ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์— ๋Œ€ํ•ด ๊ธฐ์ดˆ๋ถ€ํ„ฐ ๊ณ ๊ธ‰ ์ฃผ์ œ๊นŒ์ง€ ๋‹ค๋ค„๋ดค์–ด. ์ด์ œ ๋‹น์‹ ๋„ ์‹œ์Šคํ…œ์„ ์ง€ํ‚ค๋Š” ์ˆ˜ํ˜ธ์ž๊ฐ€ ๋  ์ค€๋น„๊ฐ€ ๋์–ด! ๐Ÿ’ช

๋ชจ๋‹ˆํ„ฐ๋ง์€ ํ•œ ๋ฒˆ ๊ตฌ์ถ•ํ•˜๊ณ  ๋์ด ์•„๋‹ˆ์•ผ. ์ง€์†์ ์œผ๋กœ ๊ฐœ์„ ํ•˜๊ณ  ์ตœ์ ํ™”ํ•ด์•ผ ํ•ด. ์ƒˆ๋กœ์šด ์„œ๋น„์Šค๊ฐ€ ์ถ”๊ฐ€๋˜๋ฉด ๋ฉ”ํŠธ๋ฆญ์„ ์ถ”๊ฐ€ํ•˜๊ณ , ์•Œ๋ฆผ ๊ทœ์น™์„ ์กฐ์ •ํ•˜๊ณ , ๋Œ€์‹œ๋ณด๋“œ๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” ๊ฑฐ์ง€.

์ฒ˜์Œ์—” ์–ด๋ ค์šธ ์ˆ˜ ์žˆ์ง€๋งŒ, ํ•˜๋‚˜์”ฉ ์ฐจ๊ทผ์ฐจ๊ทผ ๋”ฐ๋ผํ•˜๋‹ค ๋ณด๋ฉด ์–ด๋А์ƒˆ ์ „๋ฌธ๊ฐ€๊ฐ€ ๋˜์–ด ์žˆ์„ ๊ฑฐ์•ผ! ๐Ÿ˜Š

โœจ ํ•ต์‹ฌ ์š”์•ฝ 1. ์•„ํ‚คํ…์ฒ˜ ์ดํ•ด: Prometheus(์ˆ˜์ง‘) + Grafana(์‹œ๊ฐํ™”) ์กฐํ•ฉ
2. Exporter ์„ค์น˜: ๋‹ค์–‘ํ•œ ์‹œ์Šคํ…œ์˜ ๋ฉ”ํŠธ๋ฆญ ์ˆ˜์ง‘
3. PromQL ๋งˆ์Šคํ„ฐ: ๊ฐ•๋ ฅํ•œ ์ฟผ๋ฆฌ ์–ธ์–ด ํ™œ์šฉ
4. ๋Œ€์‹œ๋ณด๋“œ ๊ตฌ์„ฑ: ์ง๊ด€์ ์ด๊ณ  ์‹ค์šฉ์ ์ธ ์‹œ๊ฐํ™”
5. ์•Œ๋ฆผ ์„ค์ •: ์˜๋ฏธ ์žˆ๋Š” ์•Œ๋ฆผ์œผ๋กœ ์‹ ์†ํ•œ ๋Œ€์‘
6. ์ตœ์ ํ™”: ์„ฑ๋Šฅ๊ณผ ๋ฆฌ์†Œ์Šค ํšจ์œจ์„ฑ ๊ฐœ์„ 
7. ํ™•์žฅ์„ฑ: Federation, Thanos๋กœ ์Šค์ผ€์ผ ์•„์›ƒ
8. ํ†ตํ•ฉ ๊ด€์ธก์„ฑ: Metrics + Logs + Traces

๐ŸŽฏ ๋‹ค์Œ ์•ก์…˜ ์•„์ดํ…œ

โœ… ํ…Œ์ŠคํŠธ ํ™˜๊ฒฝ์— Prometheus + Grafana ์„ค์น˜
โœ… Node Exporter๋กœ ์„œ๋ฒ„ ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์ž‘
โœ… ์ปค๋ฎค๋‹ˆํ‹ฐ ๋Œ€์‹œ๋ณด๋“œ import ํ•ด๋ณด๊ธฐ
โœ… ์ฒซ ๋ฒˆ์งธ ์•Œ๋ฆผ ๊ทœ์น™ ์ž‘์„ฑ
โœ… ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋ฉ”ํŠธ๋ฆญ ์ถ”๊ฐ€
โœ… ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ ์ ์šฉ ๊ณ„ํš ์ˆ˜๋ฆฝ
โœ… ํŒ€์›๋“ค๊ณผ ๋Œ€์‹œ๋ณด๋“œ ๊ณต์œ 
โœ… ์ง€์†์ ์ธ ๊ฐœ์„ ๊ณผ ์ตœ์ ํ™”

๋ชจ๋‹ˆํ„ฐ๋ง์˜ ์—ฌ์ • ์‹œ์ž‘๋ถ€ํ„ฐ ์ „๋ฌธ๊ฐ€๊นŒ์ง€ ๐Ÿš€ ์‹œ์ž‘ ๐Ÿ“Š ๊ตฌ์ถ• โšก ์ตœ์ ํ™” ๐ŸŽ“ ์ „๋ฌธ๊ฐ€ ๋‹น์‹ ์˜ ์‹œ์Šคํ…œ์„ ์ง€ํ‚ค๋Š” ์ตœ๊ณ ์˜ ๋„๊ตฌ!

๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ•์ด ์ฒ˜์Œ์ด๊ฑฐ๋‚˜ ๋” ๊นŠ์ด ์žˆ๋Š” ํ•™์Šต์ด ํ•„์š”ํ•˜๋‹ค๋ฉด, ์žฌ๋Šฅ๋„ท์—์„œ DevOps ์ „๋ฌธ๊ฐ€๋“ค์˜ ๋„์›€์„ ๋ฐ›์•„๋ณด๋Š” ๊ฒƒ๋„ ์ข‹์€ ์„ ํƒ์ด์•ผ. ์‹ค๋ฌด ๊ฒฝํ—˜์ด ํ’๋ถ€ํ•œ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋‹น์‹ ์˜ ํ™˜๊ฒฝ์— ์ตœ์ ํ™”๋œ ์†”๋ฃจ์…˜์„ ์ œ์•ˆํ•ด์ค„ ๊ฑฐ์•ผ! ๐ŸŒŸ

์ด ๊ธ€์ด ๋„์›€์ด ๋˜์—ˆ๊ธฐ๋ฅผ ๋ฐ”๋ผ! ๊ถ๊ธˆํ•œ ์ ์ด ์žˆ๋‹ค๋ฉด ์–ธ์ œ๋“  ์ปค๋ฎค๋‹ˆํ‹ฐ์— ์งˆ๋ฌธํ•˜๊ณ , ๊ฒฝํ—˜์„ ๊ณต์œ ํ•˜๋ฉด์„œ ํ•จ๊ป˜ ์„ฑ์žฅํ•˜์ž! ๐Ÿ’ช

Happy Monitoring! ๐ŸŽ‰

๋Œ“๊ธ€ ์ž‘์„ฑ

์ด ๊ธ€์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ƒ๊ฐ์„ ๋“ค๋ ค์ฃผ์„ธ์š”

๋Œ“๊ธ€ 0
๋Œ“๊ธ€์„ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘์ž…๋‹ˆ๋‹ค.

์•„์ง ๋Œ“๊ธ€์ด ์—†์Šต๋‹ˆ๋‹ค.