ในระบบ infrastructure สมัยใหม่ที่ใช้ Kubernetes, cloud auto-scaling, หรือ container orchestration การจัดการ target ที่ต้องเก็บ metric แบบ manual เป็นเรื่องยากและไม่ scalable เพราะ instance เกิดและดับได้ตลอดเวลา Service Discovery (SD) คือเครื่องมือที่ Prometheus ใช้ค้นหา target อัตโนมัติจากแหล่งต่าง ๆ ทำให้ระบบ monitoring สามารถปรับตัวตามการเปลี่ยนแปลงของ infrastructure ได้อย่างต่อเนื่องโดยไม่ต้องแก้ไข config ทุกครั้งที่มี instance ใหม่
บทความนี้จะพาไปรู้จักประเภทต่าง ๆ ของ Service Discovery ที่รองรับ ตั้งแต่ Kubernetes SD ที่ใช้งานใน cluster, EC2 SD ที่ค้นหา instance ใน AWS, Consul SD สำหรับ service mesh, ไปจนถึง File-based SD และ HTTP SD ที่ยืดหยุ่นที่สุด พร้อมตัวอย่าง config และ best practices ที่ควรทำตามในแต่ละกรณี
Service Discovery คืออะไร และทำไมต้องใช้
Service Discovery คือระบบที่ให้ Prometheus ไปถามแหล่งข้อมูลภายนอก (เช่น Kubernetes API, AWS API, Consul) ว่าตอนนี้มี instance/service อะไรที่ต้องเก็บ metric บ้าง แล้วระบบจะ update target list อัตโนมัติตาม refresh_interval ที่กำหนด ข้อดีคือไม่ต้อง hard-code IP/hostname ทำให้ระบบรองรับ auto-scaling, rolling update, และ container lifecycle ได้อย่างไร้รอยต่อ
ตัวอย่างสถานการณ์ที่ Service Discovery เป็นประโยชน์มาก เช่น ระบบที่มี pod ใน Kubernetes เกิดและดับหลายร้อยตัวต่อวัน, ระบบ auto-scaling group ของ EC2 ที่เพิ่ม/ลด instance ตาม load, หรือระบบ microservice ที่มี service registry ผ่าน Consul/etcd ทุกกรณีเหล่านี้การทำ static config จะกลายเป็นภาระใหญ่ทันที
Kubernetes Service Discovery
Kubernetes SD เป็นประเภทที่ใช้บ่อยที่สุดในระบบ cloud-native สามารถค้นหา resource ใน cluster ได้หลายระดับ เช่น node, service, pod, endpoints, ingress โดยแต่ละ role จะได้ target ที่มี metadata (label/annotation) ติดมาด้วย ซึ่งใช้ทำ relabeling เพื่อกรองและปรับ label ต่อได้
Roles ใน Kubernetes SD
- node — ค้นหาทุก node ใน cluster เหมาะสำหรับ Node Exporter, kubelet metrics
- service — ค้นหา service ทั้งหมดใน cluster ได้ IP ของ service
- pod — ค้นหา pod ทั้งหมด ใช้กับ application ที่ expose metric endpoint
- endpoints — ค้นหา endpoint ของ service (pod IP + port) เหมาะสำหรับ scrape application ที่อยู่เบื้องหลัง service
- endpointslices — รุ่นใหม่ของ endpoints scale ได้ดีกว่าใน cluster ขนาดใหญ่
- ingress — ค้นหา ingress objects เหมาะกับการตรวจ external endpoint
ตัวอย่าง Kubernetes SD Config แบบเต็ม
scrape_configs:
# Scrape tất cả Pod ที่มี annotation ระบุให้ scrape
- job_name: 'kubernetes-pods'
kubernetes_sd_configs:
- role: 'pod'
namespaces:
names: ['default', 'production', 'monitoring']
relabel_configs:
# เก็บเฉพาะ pod ที่มี annotation prometheus.io/scrape: "true"
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: 'keep'
regex: 'true'
# ใช้ annotation prometheus.io/path เป็น metrics_path
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
action: 'replace'
target_label: '__metrics_path__'
regex: '(.+)'
# ใช้ annotation prometheus.io/port เป็น port ใน address
- source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
action: 'replace'
regex: '([^:]+)(?::\d+)?;(\d+)'
replacement: '$1:$2'
target_label: '__address__'
# Copy pod labels ทั้งหมดเข้ามา
- action: 'labelmap'
regex: '__meta_kubernetes_pod_label_(.+)'
# เพิ่ม namespace, pod, node
- source_labels: [__meta_kubernetes_namespace]
target_label: 'namespace'
- source_labels: [__meta_kubernetes_pod_name]
target_label: 'pod'
- source_labels: [__meta_kubernetes_pod_node_name]
target_label: 'node'
Pod Annotation Pattern
รูปแบบที่นิยมใช้คือให้แต่ละ pod ระบุว่าต้องการให้ scrape หรือไม่ผ่าน annotation ทำให้ developer ควบคุมได้เองว่า application ของตนเองจะถูก monitor หรือไม่
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-app
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
labels:
app: my-app
tier: backend
spec:
containers:
- name: my-app
image: my-app:latest
ports:
- containerPort: 8080
name: metrics
EC2 Service Discovery
EC2 SD ค้นหา instance ใน AWS อัตโนมัติตาม tag และ region ทำให้ไม่ต้อง maintain list ของ IP เองในระบบ auto-scaling ที่ instance เปลี่ยนแปลงบ่อย
scrape_configs:
- job_name: 'ec2-nodes'
ec2_sd_configs:
- region: 'ap-southeast-1'
access_key: '${AWS_ACCESS_KEY}' # หรือใช้ IAM role
secret_key: '${AWS_SECRET_KEY}'
port: 9100
filters:
- name: 'tag:Environment'
values: ['production']
- name: 'tag:MonitoringEnabled'
values: ['true']
relabel_configs:
# ใช้ Name tag เป็น instance label
- source_labels: [__meta_ec2_tag_Name]
target_label: 'instance'
# ใช้ Role tag เป็น job label ต่าง ๆ
- source_labels: [__meta_ec2_tag_Role]
target_label: 'role'
# เพิ่ม availability zone
- source_labels: [__meta_ec2_availability_zone]
target_label: 'az'
# Copy all tags เข้ามาเป็น labels
- action: 'labelmap'
regex: '__meta_ec2_tag_(.+)'
Meta Labels ที่ EC2 SD ให้มา
- __meta_ec2_instance_id — instance ID ของ EC2
- __meta_ec2_availability_zone — AZ ที่ instance อยู่
- __meta_ec2_instance_type — ประเภท instance (t3.medium, c5.xlarge)
- __meta_ec2_private_ip — Private IP ของ instance
- __meta_ec2_public_ip — Public IP (ถ้ามี)
- __meta_ec2_tag_<tagname> — ทุก tag ของ instance
- __meta_ec2_vpc_id — VPC ที่ instance อยู่
Consul Service Discovery
Consul เป็น service registry ที่นิยมใช้ใน microservice architecture การใช้ Consul SD ทำให้สามารถค้นหา service ทั้งหมดที่ลงทะเบียนไว้ใน Consul ได้อัตโนมัติ
scrape_configs:
- job_name: 'consul-services'
consul_sd_configs:
- server: 'consul.service.consul:8500'
datacenter: 'dc1'
services: [] # [] = ดึงทุก service; ระบุ list เพื่อกรอง
tags: ['metrics'] # กรองเฉพาะ service ที่มี tag นี้
relabel_configs:
# ใช้ service name เป็น job label
- source_labels: [__meta_consul_service]
target_label: 'service'
# ใช้ datacenter เป็น label
- source_labels: [__meta_consul_dc]
target_label: 'datacenter'
# Copy tags เข้ามา
- source_labels: [__meta_consul_tags]
regex: ',(prod|staging|dev),'
target_label: 'environment'
DNS Service Discovery
DNS SD ใช้ DNS record (โดยเฉพาะ SRV record) เพื่อค้นหา target เหมาะกับระบบที่มี DNS-based service mesh หรือใช้ CoreDNS/Kubernetes DNS อยู่แล้ว
scrape_configs:
- job_name: 'dns-srv-discovery'
dns_sd_configs:
- names:
- '_metrics._tcp.services.consul'
- '_prometheus._tcp.example.com'
type: 'SRV' # SRV, A, AAAA, MX
refresh_interval: 30s
- job_name: 'dns-a-record'
dns_sd_configs:
- names:
- 'node-exporter.monitoring.svc.cluster.local'
type: 'A'
port: 9100
File-based Service Discovery
File SD อ่านรายชื่อ target จากไฟล์ JSON หรือ YAML ที่สามารถ update โดย external script/tool นี่คือทางที่ยืดหยุ่นที่สุดและเหมาะกับสถานการณ์ที่ไม่มี service registry แบบดั้งเดิม ระบบจะตรวจ file changes และ reload อัตโนมัติ
# prometheus.yml
scrape_configs:
- job_name: 'file-based'
file_sd_configs:
- files:
- '/etc/prometheus/targets/*.json'
- '/etc/prometheus/targets/*.yml'
refresh_interval: 30s
# ไฟล์ /etc/prometheus/targets/web.json
[
{
"targets": ["web-01:9100", "web-02:9100"],
"labels": {
"env": "production",
"role": "web",
"region": "bangkok"
}
},
{
"targets": ["staging-web-01:9100"],
"labels": {
"env": "staging",
"role": "web"
}
}
]
File SD เหมาะกับการสร้าง pipeline ที่ดึงข้อมูลจากแหล่งภายนอก (เช่น CMDB, Ansible inventory, Terraform state) แล้ว generate ไฟล์ target ออกมาเป็น cron job ทุก 5-15 นาที ให้ระบบอ่านไป scrape
HTTP Service Discovery
HTTP SD เป็นการ discover target ผ่าน HTTP endpoint ภายนอกที่ return JSON รูปแบบเดียวกับ file SD เหมาะกับการเชื่อมต่อกับ service registry custom หรือ API ภายในขององค์กร
scrape_configs:
- job_name: 'http-sd'
http_sd_configs:
- url: 'https://cmdb.internal.example.com/api/prometheus/targets'
refresh_interval: 60s
authorization:
type: 'Bearer'
credentials_file: '/etc/prometheus/api_token'
# Response format จาก endpoint (JSON)
[
{
"targets": ["10.0.1.10:9100", "10.0.1.11:9100"],
"labels": {
"env": "production",
"team": "backend"
}
}
]
Service Discovery Providers อื่น ๆ
นอกจากที่กล่าวมาแล้ว ระบบยังรองรับ SD provider อีกหลายแบบ เหมาะกับสภาพแวดล้อมเฉพาะที่หลากหลาย
- azure_sd_configs — ค้นหา Azure VM ตาม subscription/resource group
- gce_sd_configs — ค้นหา Google Compute Engine instance
- digitalocean_sd_configs — ค้นหา Droplet ใน DigitalOcean
- hetzner_sd_configs — ค้นหา instance ใน Hetzner Cloud
- linode_sd_configs — ค้นหา Linode instance
- scaleway_sd_configs — ค้นหา instance ใน Scaleway
- docker_sd_configs — ค้นหา container ผ่าน Docker Engine API
- dockerswarm_sd_configs — ค้นหา service/task ใน Docker Swarm
- nomad_sd_configs — ค้นหา job allocation ใน HashiCorp Nomad
Best Practices ในการใช้ Service Discovery
- ใช้ refresh_interval ที่เหมาะสม — ถ้า SD ดึงจาก API ที่ rate limit อยู่ อย่าตั้งสั้นเกินไป ปกติ 30-60 วินาทีเพียงพอสำหรับระบบส่วนใหญ่
- ใช้ relabel_configs เพื่อกรอง target — ไม่ควร scrape ทุก target ที่ SD ให้มา กรองด้วย action
keep/dropตาม label ที่กำหนด - ใช้ IAM role แทน access key — สำหรับ EC2 SD ควรใช้ IAM role ของ instance ที่รัน Prometheus แทนการใส่ access_key/secret_key ใน config
- ระมัดระวัง cardinality — บาง label จาก SD เช่น pod IP, instance ID สามารถสร้าง cardinality สูงได้ ให้ drop ด้วย labeldrop
- ใช้ namespaces filter ใน K8s SD — ถ้าต้องการ monitor แค่บาง namespace การใช้
namespaces.namesใน config จะลดภาระกว่าการ drop ใน relabel - ทดสอบ SD ก่อน production — ดูที่
/service-discoveryendpoint ว่าได้ target ถูกต้อง และดู/targetsว่า scrape สำเร็จ - จัดการ authentication อย่างปลอดภัย — ใช้
credentials_fileแทนการใส่ token ตรงใน config
การ Debug Service Discovery
เมื่อ SD ไม่ทำงานตามคาดหวัง มีหลายจุดที่ต้องตรวจสอบ เริ่มจาก web UI ของระบบ เปิดหน้า /targets เพื่อดูว่ามี target ถูก discover หรือไม่ และหน้า /service-discovery เพื่อดูรายละเอียด label ของ target ก่อนและหลัง relabeling
# ตรวจดู target ที่ discover ได้
curl http://localhost:9090/api/v1/targets | jq '.data.activeTargets[].labels'
# ตรวจดู target ที่ถูก drop ในขั้น relabel
curl http://localhost:9090/api/v1/targets?state=dropped | jq
# ตรวจดู SD configuration ที่ load
curl http://localhost:9090/api/v1/status/config | jq
# ดู log ของ SD (ตั้ง --log.level=debug)
journalctl -u prometheus -f | grep 'level=debug'
สรุป
Service Discovery เป็นหัวใจที่ทำให้ระบบ monitoring ทำงานได้ในสภาพแวดล้อม cloud-native ที่เปลี่ยนแปลงตลอดเวลา ช่วยให้ระบบ adapt ตาม infrastructure ได้อัตโนมัติโดยไม่ต้อง maintain target list เอง การเลือกใช้ SD provider ที่เหมาะกับแต่ละสภาพแวดล้อม พร้อมใช้ relabel_configs ในการกรองและปรับ label อย่างมีประสิทธิภาพ จะช่วยให้ระบบ scale ได้ตามการเติบโตของ infrastructure
ในกรณีที่ระบบมี infrastructure หลายชั้น (cloud + on-premise + container) สามารถใช้ SD หลายประเภทพร้อมกันได้โดยแยกเป็น scrape_configs ต่าง ๆ หรือใช้ File SD + HTTP SD เป็น unified layer ที่อ่าน target จากแหล่งต่าง ๆ มารวมกัน ซึ่งช่วยให้การจัดการเป็นระเบียบและ maintenance ง่ายขึ้น

