ปัญหา
prometheus.yml แบบ hardcode:
scrape_configs:
- job_name: 'app1'
static_configs:
- targets: ['app1:9090']
- job_name: 'app2'
static_configs:
- targets: ['app2:9090']
- job_name: 'app3'
static_configs:
- targets: ['app3:9090']
มี service ใหม่ — ต้องแก้ไฟล์ → reload Prometheus → ทุกครั้ง
ถ้ามี 50 service → จัดการไม่ไหว
Service Discovery
Prometheus รองรับ SD จากหลายแหล่ง:
docker_sd_configs— auto discover container ใน Dockerkubernetes_sd_configs— discover pod / service ใน K8sconsul_sd_configs— Consul registryfile_sd_configs— ไฟล์ JSON ที่ tool อื่น generatedns_sd_configs— DNS SRV recordec2_sd_configs— AWS EC2 instance
หลักการ: Prometheus query API ของแหล่งข้อมูล → ได้รายการ target → scrape ตาม label/annotation ที่กำหนด
ใช้ Docker SD
prometheus.yml:
scrape_configs:
- job_name: 'docker'
docker_sd_configs:
- host: unix:///var/run/docker.sock
refresh_interval: 30s
relabel_configs:
# filter — scrape เฉพาะ container ที่มี label "prometheus.scrape=true"
- source_labels: [__meta_docker_container_label_prometheus_scrape]
regex: 'true'
action: keep
# ใช้ port จาก label "prometheus.port"
- source_labels: [__meta_docker_container_label_prometheus_port]
target_label: __address__
replacement: ${1}:${2}
regex: '(.+)'
# job name = container name
- source_labels: [__meta_docker_container_name]
regex: '/(.*)'
target_label: job
Docker compose ที่ container "opt-in" ให้ scrape:
services:
api:
image: myapi
labels:
prometheus.scrape: "true"
prometheus.port: "9090"
ports:
- "9090"
worker:
image: myworker
labels:
prometheus.scrape: "true"
prometheus.port: "9091"
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
- /var/run/docker.sock:/var/run/docker.sock:ro
ports:
- "9090:9090"
ทุก container ที่มี label prometheus.scrape: "true" → Prometheus scrape ให้อัตโนมัติ
container ใหม่ — ใส่ label = appear ใน Prometheus ภายใน 30 วินาที
ใช้ Kubernetes SD
วิธีมาตรฐานในการ scrape pod ใน K8s:
scrape_configs:
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: pod
relabel_configs:
# scrape เฉพาะ pod ที่มี annotation prometheus.io/scrape=true
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
# ใช้ path จาก annotation
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: replace
target_label: __metrics_path__
regex: (.+)
# ใช้ port จาก annotation
- source_labels:
[__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: replace
regex: ([^:]+)(?::\d+)?;(\d+)
replacement: $1:$2
target_label: __address__
# ดึง namespace + pod name มาเป็น label
- action: labelmap
regex: __meta_kubernetes_pod_label_(.+)
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
deployment ที่ opt-in:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "9090"
prometheus.io/path: "/metrics"
spec:
containers:
- name: app
image: myapp:1.0
ports:
- name: metrics
containerPort: 9090
Prometheus Operator + ServiceMonitor
ถ้าใช้ kube-prometheus-stack (Helm chart) — มี ServiceMonitor CRD ที่ดีกว่า:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: myapp
labels:
release: kube-prometheus-stack # ต้อง match label ของ Prometheus instance
spec:
selector:
matchLabels:
app: myapp
endpoints:
- port: metrics
interval: 30s
path: /metrics
แค่นี้ Prometheus Operator จะ generate scrape config ให้อัตโนมัติ
ดี: declarative, manage ผ่าน manifest ปกติ, version control ได้
File-based Service Discovery
สำหรับ infrastructure ที่ไม่มี API native — สร้างไฟล์ JSON ให้ Prometheus อ่าน:
scrape_configs:
- job_name: 'custom'
file_sd_configs:
- files:
- /etc/prometheus/targets/*.json
refresh_interval: 30s
/etc/prometheus/targets/databases.json:
[
{
"targets": ["db1.internal:9187", "db2.internal:9187"],
"labels": {
"service": "postgres",
"env": "production"
}
},
{
"targets": ["redis1.internal:9121", "redis2.internal:9121"],
"labels": {
"service": "redis",
"env": "production"
}
}
]
ใช้กับ tool อื่น generate ไฟล์นี้ — เช่น script ที่ดึงรายการจาก Terraform state
Consul Service Discovery
ถ้ามี Consul registry อยู่:
scrape_configs:
- job_name: 'consul'
consul_sd_configs:
- server: 'consul.internal:8500'
relabel_configs:
- source_labels: [__meta_consul_tags]
regex: '.*,prometheus,.*'
action: keep
- source_labels: [__meta_consul_service]
target_label: job
service ที่ register ใน Consul ด้วย tag prometheus → Prometheus ดึงมา scrape
Multi-cluster / Multi-region
ใช้ Prometheus federation หรือ Thanos เพื่อ aggregate:
scrape_configs:
- job_name: 'federate'
scrape_interval: 30s
honor_labels: true
metrics_path: '/federate'
params:
'match[]':
- '{job=~".+"}'
static_configs:
- targets:
- prometheus-region-1:9090
- prometheus-region-2:9090
หรือใช้ VictoriaMetrics ที่ scale ดีกว่า + เก็บ data นานกว่า
Reload config ไม่ต้อง restart
# ผ่าน HTTP API (ต้องเปิด --web.enable-lifecycle)
curl -X POST http://prometheus:9090/-/reload
# หรือส่ง SIGHUP
docker exec prometheus kill -HUP 1
ตั้ง config ใน Prometheus image:
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--web.enable-lifecycle'
- '--storage.tsdb.retention.time=30d'
Verify ว่า target ถูก discover
UI Prometheus: http://prometheus:9090/targets
หรือ API:
curl http://prometheus:9090/api/v1/targets | jq '.data.activeTargets[] | {job: .labels.job, health: .health, url: .scrapeUrl}'
ปัญหาที่เจอบ่อย
Target down (UNREACHABLE) → Prometheus เข้า service URL ไม่ได้
- เช็ค network:
curl <target>จาก pod ของ Prometheus - เช็ค port ตรงมั้ย
- เช็ค NetworkPolicy ใน K8s
Target ไม่โผล่ → SD ไม่ match label/annotation
- ดู
Service Discoverypage ใน Prometheus UI ดู target ที่ถูก drop กับเหตุผล
Cardinality ระเบิด → label ที่มี value ไม่ซ้ำเยอะ (เช่น user_id, request_id) — Prometheus เก็บเป็น series คนละตัว
- หลีกเลี่ยง label ที่ unbounded
- ใช้ histogram bucket แทน raw value
Best Practice
- Convention over configuration — ใช้ annotation/label มาตรฐานเดียว ทุก service follow
- Filter ที่ relabel ก่อน — อย่า scrape ทุก pod ใน cluster ใหญ่ (กิน resource)
- Consistent labeling —
service,env,regionใส่ทุก target - Recording rules สำหรับ query ที่ซับซ้อน — query ตอน dashboard เร็วขึ้น
- Alert rules แยกไฟล์ —
rules/*.ymlmodular
สรุป
Service discovery เปลี่ยน Prometheus จาก "config ที่ต้องแก้ทุกครั้ง" → "ระบบที่ตั้งครั้งเดียวขยายเอง"
หลักของทุก SD เหมือนกัน: Prometheus ถาม source → ได้ list → relabel → scrape
เริ่มจาก Docker SD หรือ K8s SD ตามที่ infra ใช้อยู่ — แล้วขยายไป Consul / file SD ตามต้องการ