Prometheus và Grafana
Prometheus và Grafana là bộ đôi không thể tách rời trong hệ sinh thái Kubernetes. Prometheus chịu trách nhiệm thu thập, lưu trữ và query metrics, trong khi Grafana cung cấp lớp visualization mạnh mẽ. Với sự ra đời của Prometheus Operator, việc quản lý Prometheus trên Kubernetes trở nên declarative và tự động hóa hoàn toàn.
Prometheus Data Model
Trước khi đi vào Prometheus Operator, cần hiểu rõ data model của Prometheus để viết queries hiệu quả.
Time Series và Labels
Mọi dữ liệu trong Prometheus đều là time series — một chuỗi các giá trị (float64) theo thời gian, được định danh duy nhất bởi tên metric và một tập hợp key-value labels. Ví dụ:
http_requests_total{method="GET", status="200", job="api-server", instance="10.0.0.1:8080"}
http_requests_total{method="POST", status="500", job="api-server", instance="10.0.0.1:8080"}
Labels là công cụ chính để filter, aggregate và join data trong PromQL. Thiết kế labels tốt là quan trọng — không nên dùng high-cardinality labels (như user ID hay request ID) vì sẽ tạo ra hàng triệu time series và làm Prometheus chậm.
Metric Types
Prometheus định nghĩa bốn loại metric cơ bản:
- Counter: giá trị chỉ tăng, không bao giờ giảm (reset về 0 khi restart). Dùng cho: total requests, total errors, bytes sent. Query thường dùng với
rate()hoặcincrease(). - Gauge: giá trị có thể tăng hoặc giảm tự do. Dùng cho: current memory usage, current number of pods, queue size.
- Histogram: đo phân phối của các observations (thường là request duration, response size). Tạo ra các time series với suffix
_bucket,_sum,_count. Dùng để tính percentiles vớihistogram_quantile(). - Summary: tương tự Histogram nhưng tính percentiles phía client-side. Ít linh hoạt hơn Histogram, không nên dùng cho metrics mới.
Prometheus Operator
Prometheus Operator giúp quản lý Prometheus và AlertManager trên Kubernetes theo cách declarative. Thay vì viết config files và reload Prometheus thủ công, bạn tạo Kubernetes resources và Operator sẽ tự động cập nhật cấu hình.
CRDs của Prometheus Operator
Prometheus Operator cung cấp các CRDs sau:
- Prometheus: định nghĩa một Prometheus instance
- AlertManager: định nghĩa AlertManager cluster
- ServiceMonitor: định nghĩa cách scrape metrics từ Services
- PodMonitor: định nghĩa cách scrape metrics từ Pods
- PrometheusRule: định nghĩa alerting và recording rules
- Probe: định nghĩa blackbox monitoring targets
Prometheus CRD
apiVersion: monitoring.coreos.com/v1
kind: Prometheus
metadata:
name: prometheus
namespace: monitoring
spec:
replicas: 2
retention: 15d
serviceAccountName: prometheus
serviceMonitorSelector:
matchLabels:
team: frontend
serviceMonitorNamespaceSelector:
matchLabels:
monitoring: enabled
ruleSelector:
matchLabels:
prometheus: kube-prometheus
storage:
volumeClaimTemplate:
spec:
storageClassName: fast-ssd
resources:
requests:
storage: 100Gi
resources:
requests:
memory: 2Gi
cpu: 500m
limits:
memory: 4Gi
cpu: 2000m
Prometheus Operator tự động discover ServiceMonitors và PodMonitors dựa trên label selectors — không cần restart hay reload Prometheus khi thêm target mới.
ServiceMonitor — Scrape Metrics Từ Services
ServiceMonitor là cách phổ biến nhất để thêm scrape targets vào Prometheus. Nó định nghĩa cách Prometheus tìm và scrape metrics từ một nhóm Services.
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: api-server
namespace: production
labels:
team: frontend
app: api-server
spec:
selector:
matchLabels:
app: api-server
namespaceSelector:
matchNames:
- production
endpoints:
- port: metrics
path: /metrics
interval: 30s
scrapeTimeout: 10s
relabelings:
- sourceLabels: [__meta_kubernetes_pod_name]
targetLabel: pod
- sourceLabels: [__meta_kubernetes_namespace]
targetLabel: namespace
Service cần expose metrics port với tên đúng:
apiVersion: v1
kind: Service
metadata:
name: api-server
namespace: production
labels:
app: api-server
spec:
ports:
- name: http
port: 8080
- name: metrics # tên port phải match với ServiceMonitor
port: 9090
selector:
app: api-server
PodMonitor — Scrape Metrics Trực Tiếp Từ Pods
PodMonitor dùng khi bạn muốn scrape trực tiếp từ Pods mà không qua Service, hoặc khi mỗi Pod cần được scrape độc lập (ví dụ: mỗi Pod expose metrics khác nhau).
apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
name: worker-pods
namespace: production
spec:
selector:
matchLabels:
app: worker
podMetricsEndpoints:
- port: metrics
path: /metrics
interval: 60s
namespaceSelector:
matchNames:
- production
- staging
PromQL — Query Language Của Prometheus
PromQL (Prometheus Query Language) là công cụ mạnh mẽ để query time series data. Dưới đây là các patterns phổ biến nhất.
Rate và Increase
Với Counter metrics, bạn luôn cần dùng rate() hoặc increase() để có giá trị có nghĩa:
# Requests per second (5 minute rate)
rate(http_requests_total[5m])
# Total requests trong 1 giờ qua
increase(http_requests_total[1h])
# Error rate percentage
rate(http_requests_total{status=~"5.."}[5m]) / rate(http_requests_total[5m]) * 100
Histogram Percentiles
# P95 request latency
histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m]))
# P99 latency theo service
histogram_quantile(0.99,
sum by (le, service) (
rate(http_request_duration_seconds_bucket[5m])
)
)
Kubernetes-Specific Queries
# Pods với unavailable replicas
kube_deployment_status_replicas_unavailable > 0
# Pods đang trong CrashLoopBackOff
kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} == 1
# CPU throttling percentage
rate(container_cpu_cfs_throttled_seconds_total[5m]) /
rate(container_cpu_cfs_periods_total[5m]) * 100 > 25
# Memory usage percentage
container_memory_working_set_bytes /
container_spec_memory_limit_bytes * 100
# Node disk pressure
kube_node_status_condition{condition="DiskPressure", status="true"} == 1
Grafana Dashboards
Grafana là visualization layer, kết nối với Prometheus (và Loki, Tempo) để tạo dashboards phong phú.
Import Dashboard Từ Grafana.com
Grafana.com có hàng nghìn community dashboards. Một số dashboard quan trọng cho Kubernetes:
- ID 315: Kubernetes cluster monitoring (basic)
- ID 12740: Kubernetes monitoring (advanced, requires kube-state-metrics)
- ID 15661: Kubernetes Node Overview
- ID 15760: Kubernetes Views — Global
- ID 14205: Kubernetes — Pod Overview
Để import: vào Grafana UI → Dashboards → Import → nhập ID → chọn Prometheus data source.
Dashboard Variables
Variables biến dashboard thành interactive tool. Các variables phổ biến cho Kubernetes:
# Variable: cluster
Type: Query
Query: label_values(kube_node_info, cluster)
# Variable: namespace
Type: Query
Query: label_values(kube_namespace_labels{cluster="$cluster"}, namespace)
# Variable: pod
Type: Query
Query: label_values(kube_pod_info{cluster="$cluster", namespace="$namespace"}, pod)
Với variables này, user có thể chọn cluster → namespace → pod và mọi panel trong dashboard sẽ tự động filter theo lựa chọn đó.
Các Panels Quan Trọng
Dashboard Kubernetes hoàn chỉnh nên có:
- Node Overview: CPU usage, memory usage, disk I/O, network I/O per node
- Pod Metrics: CPU/memory request vs limit vs actual usage
- Deployment Status: desired vs available replicas
- Container Restarts: restart count trong 1h, 24h
- Error Rate: HTTP 5xx rate per service
- Latency P50/P95/P99: request duration percentiles
AlertManager
AlertManager nhận alerts từ Prometheus và xử lý chúng: routing đến đúng receiver, grouping để giảm noise, inhibition để tránh alert storm, và silencing khi maintenance.
Routing Tree
AlertManager routing được cấu hình theo cây phân cấp. Mỗi route match labels của alert và gửi đến receiver tương ứng:
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: main-routing
namespace: monitoring
spec:
route:
groupBy: ['alertname', 'cluster', 'service']
groupWait: 30s
groupInterval: 5m
repeatInterval: 12h
receiver: 'default-slack'
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
continue: false
- match:
severity: warning
team: frontend
receiver: 'slack-frontend'
- match:
severity: warning
receiver: 'slack-platform'
receivers:
- name: 'default-slack'
slackConfigs:
- apiURL:
name: slack-secret
key: webhook-url
channel: '#alerts'
title: '{{ .CommonAnnotations.summary }}'
text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'
- name: 'pagerduty-critical'
pagerdutyConfigs:
- routingKey:
name: pagerduty-secret
key: routing-key
severity: '{{ .CommonLabels.severity }}'
Inhibition Rules
Inhibition rules ngăn alert bị gửi đi khi một alert khác đang active. Ví dụ: khi toàn bộ cluster down, không cần gửi alerts cho từng service:
inhibitRules:
- sourceMatch:
alertname: ClusterDown
targetMatch:
severity: warning
equal: ['cluster']
- sourceMatch:
alertname: NodeNotReady
targetMatch:
alertname: KubePodNotRunning
equal: ['node']
PrometheusRule — Alert Rules
PrometheusRule định nghĩa alerting rules và recording rules. Prometheus Operator tự động load rules này vào Prometheus.
apiVersion: monitoring.coreos.com/v1
kind: PrometheusRule
metadata:
name: kubernetes-alerts
namespace: monitoring
labels:
prometheus: kube-prometheus
role: alert-rules
spec:
groups:
- name: kubernetes.deployment
rules:
- alert: KubeDeploymentReplicasMismatch
expr: |
(
kube_deployment_spec_replicas
!=
kube_deployment_status_replicas_available
) and (
changes(kube_deployment_status_replicas_updated[10m]) == 0
)
for: 15m
labels:
severity: warning
annotations:
summary: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} replica mismatch"
description: "Deployment {{ $labels.namespace }}/{{ $labels.deployment }} has not matched the expected number of replicas for over 15 minutes."
- alert: KubePodCrashLooping
expr: |
increase(kube_pod_container_status_restarts_total[1h]) > 5
for: 2m
labels:
severity: warning
annotations:
summary: "Pod {{ $labels.namespace }}/{{ $labels.pod }} is crash looping"
description: "Pod {{ $labels.namespace }}/{{ $labels.pod }} container {{ $labels.container }} has restarted {{ $value }} times in the last hour."
- name: kubernetes.node
rules:
- alert: NodeMemoryPressure
expr: kube_node_status_condition{condition="MemoryPressure", status="true"} == 1
for: 5m
labels:
severity: critical
annotations:
summary: "Node {{ $labels.node }} is under memory pressure"
- alert: NodeHighCPUUsage
expr: |
100 - (avg by (node) (
rate(node_cpu_seconds_total{mode="idle"}[5m])
) * 100) > 85
for: 10m
labels:
severity: warning
annotations:
summary: "High CPU usage on node {{ $labels.node }}: {{ $value | printf \"%.1f\" }}%"
Recording Rules — Pre-Compute Expensive Queries
Recording rules tính toán trước các queries phức tạp và lưu kết quả thành time series mới. Điều này cải thiện đáng kể performance của dashboards và alerts sử dụng các queries nặng.
groups:
- name: kubernetes.recording_rules
interval: 1m
rules:
# Pre-compute request rate per service
- record: job:http_requests_total:rate5m
expr: |
sum by (job, namespace, status) (
rate(http_requests_total[5m])
)
# Pre-compute P99 latency per service
- record: job:http_request_duration_seconds:p99
expr: |
histogram_quantile(0.99,
sum by (le, job, namespace) (
rate(http_request_duration_seconds_bucket[5m])
)
)
# Pre-compute CPU usage ratio
- record: namespace:container_cpu_usage_seconds_total:sum_rate
expr: |
sum by (namespace) (
rate(container_cpu_usage_seconds_total{
container!="",
image!=""
}[5m])
)
Best practices cho recording rules:
- Tên theo format
level:metric:operations(ví dụ:job:http_requests:rate5m) - Chỉ tạo recording rules cho queries dùng trong nhiều places
- Evaluation interval của recording rules phải nhỏ hơn scrape interval
- Không tạo recording rules cho queries chỉ dùng một lần
Best Practices Cho Production
Prometheus Sizing
Prometheus memory usage tỉ lệ thuận với số lượng active time series. Ước tính: 1-2 bytes per sample, với 15-second scrape interval, 10,000 time series sẽ dùng khoảng 1GB RAM. Với cluster 100 nodes và hàng trăm services, dự kiến 500K-1M time series.
High Availability
Chạy 2 Prometheus instances với cùng cấu hình. Grafana sẽ deduplicate khi query. Với AlertManager, chạy 3 instances theo cluster mode để đảm bảo không mất alerts.
Long-Term Storage
Prometheus chỉ nên giữ data 2-4 tuần. Để long-term storage (months/years), dùng Thanos hoặc Grafana Mimir — cả hai đều hỗ trợ object storage backend (S3, GCS) với chi phí thấp hơn nhiều so với Prometheus local storage.
Tổng Kết
Prometheus Operator đã cách mạng hóa cách quản lý monitoring trên Kubernetes. Với ServiceMonitor và PodMonitor, việc thêm targets mới là hoàn toàn declarative và không cần can thiệp thủ công. PrometheusRule giúp alert rules được quản lý như code (GitOps-friendly), và AlertManager với routing tree linh hoạt đảm bảo đúng người nhận đúng alert.
Bài học tiếp theo sẽ bổ sung phần còn lại của observability stack: Loki cho logs và Tempo cho distributed tracing.