๐ฅ Prometheus ํต์ฌ ์นํธ์ํธ
๋น ๋ฅด๊ฒ ๊ธฐ์ตํ ํต์ฌ๋ง ๋ชจ์์ต๋๋ค!
๐ 1. ํต์ฌ ๊ฐ๋ (30์ด ์์ฝ)
Prometheus๋?
- Pull ๊ธฐ๋ฐ ์๊ณ์ด ๋ฉํธ๋ฆญ DB
- Kubernetes ๊ณต์ ๋ชจ๋ํฐ๋ง ๋๊ตฌ
- CNCF Graduated ํ๋ก์ ํธ
ํต์ฌ ํน์ง:
โ
Pull ๋ฐฉ์ (์๋ฒ๊ฐ ์ฃผ๊ธฐ์ ์ผ๋ก ์์ง)
โ
Service Discovery (์๋ ํ๊ฒ ๋ฐ๊ฒฌ)
โ
PromQL (๊ฐ๋ ฅํ ์ฟผ๋ฆฌ ์ธ์ด)
โ
์๊ณ์ด ๋ฐ์ดํฐ ์ ์ฅ
๋ฐ์ดํฐ ํ๋ฆ:
Exporter(์์ง) โ Prometheus(์ ์ฅ) โ Grafana(์๊ฐํ)๐ 2. ๋ฉํธ๋ฆญ ํ์ (4๊ฐ์ง๋ง ๊ธฐ์ต!)
Counter - ๊ณ์ ์ฆ๊ฐ๋ง
ํน์ง:
- ๋์ ๊ฐ (์ฌ์์ ์์๋ง 0์ผ๋ก)
- ์ ๋ ๊ฐ์ ์ํจ
์์: http_requests_total, errors_total
ํ์ ํจ์: rate(), increase()PromQL ์์:
# โ ์๋ชป - ๋์ ๊ฐ์ ์๋ฏธ์์
http_requests_total
# โ
์ฌ๋ฐ๋ฆ - ์ด๋น ์์ฒญ ์
rate(http_requests_total[5m])
# โ
์ฌ๋ฐ๋ฆ - 5๋ถ๊ฐ ์ด ์ฆ๊ฐ๋
increase(http_requests_total[5m])Gauge - ์ฆ๊ฐ/๊ฐ์ ๊ฐ๋ฅ
ํน์ง:
- ํ์ฌ ๊ฐ
- ์ฆ๊ฐ/๊ฐ์ ๋ชจ๋ ๊ฐ๋ฅ
์์: cpu_usage_percent, memory_bytes, temperature
์ฌ์ฉ: ์ง์ ์ฌ์ฉ ๊ฐ๋ฅ (ํจ์ ๋ถํ์)PromQL ์์:
# โ
ํ์ฌ CPU ์ฌ์ฉ๋ฅ
node_cpu_usage_percent
# โ
ํ๊ท CPU
avg(node_cpu_usage_percent)
# โ
๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ ๊ณ์ฐ
(node_memory_used_bytes / node_memory_total_bytes) * 100Histogram - ๊ฐ์ ๋ถํฌ
ํน์ง:
- ๋ฒํท์ผ๋ก ๋ถํฌ ์ธก์
- ๋ฐฑ๋ถ์์(P95, P99) ๊ณ์ฐ ๊ฐ๋ฅ
์์: http_request_duration_seconds_bucket
ํ์ ํจ์: histogram_quantile()PromQL ์์:
# P95 ์๋ต์๊ฐ (95%๊ฐ ์ด ์๊ฐ ์ด๋ด)
histogram_quantile(0.95,
rate(http_request_duration_seconds_bucket[5m])
)
# P99 ์๋ต์๊ฐ
histogram_quantile(0.99,
rate(http_request_duration_seconds_bucket[5m])
)Summary - ์ฌ์ ๊ณ์ฐ๋ ๋ฐฑ๋ถ์์
ํน์ง:
- ํด๋ผ์ด์ธํธ์์ ๋ฐฑ๋ถ์์ ๋ฏธ๋ฆฌ ๊ณ์ฐ
- Histogram๋ณด๋ค ๊ฐ๋ฒผ์
์์: http_request_duration_seconds{quantile="0.95"}
์ฌ์ฉ: ์ง์ ์ฌ์ฉ (๊ณ์ฐ ์ด๋ฏธ ์๋ฃ๋จ)๐ฏ 3. PromQL ํต์ฌ ํจํด
๊ธฐ๋ณธ ์ฟผ๋ฆฌ
# ๋ฉํธ๋ฆญ ์กฐํ
metric_name
# ๋ ์ด๋ธ ํํฐ
metric_name{label="value"}
# ์ ๊ทํํ์
metric_name{label=~"value.*"}
metric_name{label!~"value.*"}์๊ฐ ๋ฒ์
metric_name[5m] # ์ต๊ทผ 5๋ถ (๋ ์ธ์ง ๋ฒกํฐ)
metric_name[1h] # ์ต๊ทผ 1์๊ฐ
metric_name[1d] # ์ต๊ทผ 1์ผ
# ๊ณผ๊ฑฐ ์์
metric_name offset 1h # 1์๊ฐ ์
metric_name offset 1d # 1์ผ ์ ํ์ ํจ์ TOP 10
# 1. rate() - Counter ์ ์ฉ, ์ด๋น ์ฆ๊ฐ์จ
rate(http_requests_total[5m])
# 2. irate() - ์๊ฐ ์ฆ๊ฐ์จ (๋ ๋ฏผ๊ฐ)
irate(http_requests_total[5m])
# 3. increase() - ๊ธฐ๊ฐ ๋์ ์ด ์ฆ๊ฐ๋
increase(http_requests_total[5m])
# 4. sum() - ํฉ๊ณ
sum(metric_name)
# 5. avg() - ํ๊ท
avg(metric_name)
# 6. max() / min() - ์ต๋/์ต์
max(metric_name)
# 7. count() - ๊ฐ์
count(metric_name)
# 8. topk() - ์์ K๊ฐ
topk(5, metric_name)
# 9. by - ๊ทธ๋ฃนํ
sum by (label) (metric_name)
# 10. without - ํน์ ๋ ์ด๋ธ ์ ์ธ
sum without (pod) (metric_name)์ค์ ์ฟผ๋ฆฌ ํจํด
# CPU ์ฌ์ฉ๋ฅ
100 - (avg by (instance) (irate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)
# ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ
(1 - (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes)) * 100
# ์๋ฌ์จ
sum(rate(http_requests_total{status=~"5.."}[5m])) /
sum(rate(http_requests_total[5m])) * 100
# QPS (์ด๋น ์ฟผ๋ฆฌ)
sum(rate(http_requests_total[5m]))
# ํ์ฌ vs 1์๊ฐ ์ ๋น๊ต
rate(metric[5m]) / rate(metric[5m] offset 1h)๐๏ธ 4. Native vs Operator (ํต์ฌ ์ฐจ์ด)
๋น๊ตํ
โโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโ
โ ํญ๋ชฉ โ Native โ Operator โ
โโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโค
โ ์ค์ ๋ฐฉ์ โ prometheus.yml โ ServiceMonitor CRD โ
โ ์ค์ ๋ณต์ก๋ โ ๋์ (regex) โ ๋ฎ์ (์ ์ธ์ ) โ
โ ๋ณ๊ฒฝ ๋ฐ์ โ ์ฌ์์ ํ์ โ ์๋ (10-30์ด) โ
โ Pod ํ์ โ Annotation โ Label โ
โ ๋ค์์คํ์ด์คโ ์ด๋ ค์ โ ์ฌ์ (RBAC) โ
โ ํ์
โ ์ด์ํ ๋ณ๋ชฉ โ ๊ฐ๋ฐํ ์
ํ์๋น์ค โ
โ GitOps โ ๋ฎ์ โ ๋์ โ
โ ์ถ์ฒ โ ๊ฐ๋จํ ํ๊ฒฝ โ ํ๋ก๋์
, ๋ฉํฐํ โ
โโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโNative ๋ฐฉ์
# Pod Annotation ํ์
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9104"
prometheus.io/path: "/metrics"
# prometheus.yml์ ๋ณต์กํ relabel_configs ์์ฑ
relabel_configs:
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: trueOperator ๋ฐฉ์
# ServiceMonitor CRD๋ง ์์ฑ
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: mysql-exporter
spec:
selector:
matchLabels:
app: mysql-exporter
endpoints:
- port: metrics
interval: 30s๐ฏ 5. ServiceMonitor ํต์ฌ ํ๋
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-service-monitor
namespace: my-namespace
spec:
# 1. Service ์ ํ (ํ์!)
selector:
matchLabels:
app: my-app
# 2. ์์ง ์ค์
endpoints:
- port: metrics # Service์ ํฌํธ ์ด๋ฆ
path: /metrics # ๊ธฐ๋ณธ๊ฐ: /metrics
interval: 30s # ์์ง ์ฃผ๊ธฐ
scrapeTimeout: 10s # ํ์์์
scheme: http # http ๋๋ https
# 3. ๋ค์์คํ์ด์ค ์ ํ (์ ํ์ฌํญ)
namespaceSelector:
matchNames:
- my-namespace
# ๋๋ ๋ชจ๋ ๋ค์์คํ์ด์ค
# any: truePodMonitor (Service ์์ด Pod ์ง์ ์์ง)
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: my-pod-monitor
spec:
selector:
matchLabels:
app: my-app
podMetricsEndpoints:
- port: http
path: /metrics์ธ์ ๋ญ ์ธ๊น?
ServiceMonitor:
- Deployment (์ผ๋ฐ ์ฑ)
- Service ์๋ ๊ฒฝ์ฐ
- ๊ถ์ฅ! (ํ๋ก๋์
ํ์ค)
PodMonitor:
- DaemonSet (node-exporter)
- StatefulSet (๊ฐ๋ณ Pod ์ถ์ )
- Service ์๋ ๊ฒฝ์ฐ๐ 6. 4 Golden Signals (๊ผญ ๋ชจ๋ํฐ๋ง!)
1. Latency (์ง์ฐ์๊ฐ):
์ธก์ : histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
๋ชฉํ: P95 < 500ms
2. Traffic (ํธ๋ํฝ):
์ธก์ : rate(http_requests_total[5m])
๋ชฉํ: RPS ์ถ์ธ ํ์
3. Errors (์๋ฌ์จ):
์ธก์ : sum(rate(http_requests_total{status=~"5.."}[5m])) /
sum(rate(http_requests_total[5m])) * 100
๋ชฉํ: < 1%
4. Saturation (ํฌํ๋):
์ธก์ : CPU, ๋ฉ๋ชจ๋ฆฌ, ๋์คํฌ ์ฌ์ฉ๋ฅ
๋ชฉํ: < 80%Alert ์ฐ์ ์์
Critical (์ฆ์ ๋์):
- Errors > 5%
- Saturation > 90%
Warning (๊ทผ๋ฌด์๊ฐ):
- Latency P95 > 1์ด
- Saturation > 80%
Info (์ฃผ๊ฐ ๋ฆฌํฌํธ):
- Traffic ์ถ์ด๐ ๏ธ 7. ์์ฃผ ์ฐ๋ kubectl ๋ช ๋ น์ด
CRD ํ์ธ
# ServiceMonitor ๋ชฉ๋ก
kubectl get servicemonitor -n monitoring
# PodMonitor ๋ชฉ๋ก
kubectl get podmonitor -n monitoring
# PrometheusRule (Alert) ๋ชฉ๋ก
kubectl get prometheusrule -n monitoring
# ์์ธ ์ ๋ณด
kubectl describe servicemonitor mysql-exporter -n monitoringPrometheus ์ค์ ํ์ธ
# Prometheus ConfigMap ํ์ธ
kubectl get configmap prometheus-config -n monitoring -o yaml
# Prometheus Pod ๋ก๊ทธ
kubectl logs prometheus-xxx -n monitoring
# Prometheus Reload (์ค์ ์ฌ์ ์ฉ)
curl -X POST http://prometheus:9090/-/reloadTarget ํ์ธ
# Prometheus UI์์ ํ์ธ
http://prometheus:9090/targets
# ๋๋ API
curl http://prometheus:9090/api/v1/targets๐ง 8. ํธ๋ฌ๋ธ์ํ ์ฒดํฌ๋ฆฌ์คํธ
โ๋ฉํธ๋ฆญ์ด ์ ๋ณด์ฌ์!โ
1๋จ๊ณ - Exporter ํ์ธ:
โก Pod ์ ์ ์คํ ์ค?
kubectl get pods -n <namespace>
โก /metrics ์๋ํฌ์ธํธ ์๋ต?
kubectl port-forward pod/<exporter-pod> 9104:9104
curl localhost:9104/metrics
2๋จ๊ณ - Service ํ์ธ (ServiceMonitor ์ฌ์ฉ ์):
โก Service ์กด์ฌ?
kubectl get svc -n <namespace>
โก Service Label๊ณผ ServiceMonitor selector ์ผ์น?
kubectl get svc <service-name> -o yaml
kubectl get servicemonitor <sm-name> -o yaml
โก Service์ port name๊ณผ endpoints์ port ์ผ์น?
3๋จ๊ณ - ServiceMonitor ํ์ธ:
โก ServiceMonitor ์์ฑ๋จ?
kubectl get servicemonitor -n <namespace>
โก Namespace Label ์์?
kubectl get namespace <namespace> --show-labels
4๋จ๊ณ - Prometheus ํ์ธ:
โก Target์ ํ์๋จ?
http://prometheus:9090/targets
โก Prometheus Operator ๋ก๊ทธ
kubectl logs -n monitoring <prometheus-operator-pod>๐ 9. ํต์ฌ ๋ฉํธ๋ฆญ ์์
์ฟ ๋ฒ๋คํฐ์ค ๋ฆฌ์์ค
# Pod CPU ์ฌ์ฉ๋ฅ
sum(rate(container_cpu_usage_seconds_total{pod="my-pod"}[5m])) * 100
# Pod ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ
container_memory_usage_bytes{pod="my-pod"} /
container_spec_memory_limit_bytes{pod="my-pod"} * 100
# Pod ์ฌ์์ ํ์
kube_pod_container_status_restarts_total
# Deployment replicas
kube_deployment_status_replicas_availableMySQL
# ์ฐ๊ฒฐ ์
mysql_global_status_threads_connected
# ์ฌ๋ก์ฐ ์ฟผ๋ฆฌ
rate(mysql_global_status_slow_queries[5m])
# QPS
rate(mysql_global_status_queries[5m])
# ์ปค๋ฅ์
์ฌ์ฉ๋ฅ
mysql_global_status_threads_connected /
mysql_global_variables_max_connections * 100Redis
# ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋ฅ
redis_memory_used_bytes / redis_memory_max_bytes * 100
# ์ด๋น ๋ช
๋ น ์
rate(redis_commands_processed_total[1m])
# ์ฐ๊ฒฐ๋ ํด๋ผ์ด์ธํธ
redis_connected_clients
# Hit Rate
rate(redis_keyspace_hits_total[5m]) /
(rate(redis_keyspace_hits_total[5m]) + rate(redis_keyspace_misses_total[5m])) * 100โก 10. ๋น ๋ฅธ ์ฐธ์กฐ - ์๊ฐ ๋จ์
[30s] # 30์ด
[5m] # 5๋ถ (๊ฐ์ฅ ๋ง์ด ์ฌ์ฉ)
[1h] # 1์๊ฐ
[1d] # 1์ผ
[1w] # 1์ฃผ
[1y] # 1๋
offset 1h # 1์๊ฐ ์
offset 1d # 1์ผ ์
offset 1w # 1์ฃผ์ผ ์ ๐ก 11. ๊ฟํ
๋ฉ๋ชจ๋ฆฌ ํจ์จ์ ์ธ ์ฟผ๋ฆฌ
# โ ๋นํจ์จ - ๋ชจ๋ ์๊ณ์ด ๋ก๋
sum(metric_name)
# โ
ํจ์จ - ํ์ํ ๊ฒ๋ง ๋จผ์ ํํฐ
sum(metric_name{job="api"})๋ ์ด๋ธ ๋งค์นญ
# ์ ํํ ์ผ์น
{label="value"}
# ์ ๊ทํํ์ (๋๋ฆผ!)
{label=~"value.*"}
# NOT ๋งค์นญ
{label!="value"}
{label!~"value.*"}
# ์ฌ๋ฌ ์กฐ๊ฑด AND
{label1="value1", label2="value2"}Recording Rules (์์ฃผ ์ฐ๋ ์ฟผ๋ฆฌ ๋ฏธ๋ฆฌ ๊ณ์ฐ)
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: recording-rules
spec:
groups:
- name: api_metrics
interval: 30s
rules:
- record: api:request_rate:5m
expr: sum(rate(http_requests_total{job="api"}[5m]))๐ฏ ๋ง์ง๋ง ์ฒดํฌ๋ฆฌ์คํธ
โก ๋ฉํธ๋ฆญ ํ์
4๊ฐ์ง ๊ตฌ๋ถ ๊ฐ๋ฅ?
Counter, Gauge, Histogram, Summary
โก PromQL ๊ธฐ๋ณธ ํจ์ ์ฌ์ฉ ๊ฐ๋ฅ?
rate(), sum(), avg(), by
โก Native vs Operator ์ฐจ์ด ์ดํด?
Annotation vs ServiceMonitor
โก 4 Golden Signals ์๊ณ ์์?
Latency, Traffic, Errors, Saturation
โก ServiceMonitor ์์ฑ ๊ฐ๋ฅ?
selector + endpoints
โก ํธ๋ฌ๋ธ์ํ
์์ ์์ง?
Exporter โ Service โ ServiceMonitor โ Prometheus๐ ๋ ์์๋ณด๊ธฐ
์์ธ ๋ฌธ์:
- ๊ธฐ์ด ๊ฐ๋
- ๋ฉํธ๋ฆญ ํ์ ์์ธ
- PromQL ์์ธ
- Native vs Operator
- ServiceMonitor ์์ธ
- 4 Golden Signals
๐ ์ต์ข ์ ๋ฐ์ดํธ: 2025-12-12 ๐ฏ ์ฉ๋: ๋น ๋ฅธ ์ฐธ์กฐ์ฉ ์นํธ์ํธ โฑ๏ธ ์ฝ๋ ์๊ฐ: 5๋ถ
๐ก Tip: ์ด ๋ฌธ์๋ฅผ ๋ถ๋งํฌํ๊ณ ์ค๋ฌด์์ ์์ฃผ ํ์ธํ์ธ์!