4. Prometheus 服务发现:从静态配置到动态感知
监控系统要解决的核心问题是什么?说白了就是——我怎么知道该监控谁。
在云原生环境下,容器随时启停,Pod 随时漂移,IP 随时变化。你要是还用手工写死目标地址,那运维效率基本等于零。我刚开始用 Prometheus 时,就吃过这个亏。当时线上几十个微服务,每次扩缩容都要手动改配置文件,然后 reload。有一次凌晨扩容,我忘了更新监控配置,结果业务涨了三倍,告警却静悄悄——因为 Prometheus 压根不知道新节点存在。
所以,服务发现不是「锦上添花」,而是 Prometheus 在云原生环境下的生存基础。
这一章,我们按从简单到复杂的顺序,把四种服务发现方式挨个捋一遍。
4.1 静态配置:最原始,但最可靠
静态配置就是直接在 prometheus.yml 里写死 target 地址。格式很简单:
scrape_configs:
- job_name: 'static-demo'
static_configs:
- targets: ['192.168.1.10:9090', '192.168.1.11:9090']
labels:
env: 'production'
team: 'backend'
优点很明显:简单、直观、没有外部依赖。你想想看,如果 Consul 挂了,Kubernetes API 连不上了,至少静态配置还能兜底。
缺点也扎心:不灵活。每次增删节点都要改配置、重启或 reload。我建议只在以下场景用静态配置:
- 基础设施组件(如 Prometheus 自身、Alertmanager、Grafana)
- 物理机或固定 IP 的传统服务
- 作为其他服务发现方式的「备用方案」
4.2 基于文件的服务发现:动态与静态的折中
文件服务发现,说白了就是让 Prometheus 去读一个 JSON 或 YAML 文件,文件里写 target 列表。你只要更新这个文件,Prometheus 会自动感知变化,不需要 reload。
配置方式:
scrape_configs:
- job_name: 'file-sd-demo'
file_sd_configs:
- files:
- '/etc/prometheus/targets/*.json'
refresh_interval: 30s
对应的 targets 文件内容:
[
{
"targets": ["10.0.1.1:9100", "10.0.1.2:9100"],
"labels": {
"service": "node_exporter",
"env": "staging"
}
}
]
我在项目中遇到过一种典型用法:配合配置中心(比如 Consul Template 或 Ansible)动态生成 targets 文件。CMDB 里登记了所有机器,Ansible 定期拉取并生成 JSON 文件,Prometheus 自动加载。这样既不用改主配置,又能实现半自动化。
4.3 基于 Consul 的服务发现:微服务架构的标配
Consul 是目前最成熟的服务注册中心之一。Prometheus 原生支持从 Consul 拉取服务列表,而且能自动获取服务的元数据(标签、健康状态等)。
配置示例:
scrape_configs:
- job_name: 'consul-demo'
consul_sd_configs:
- server: 'localhost:8500'
datacenter: 'dc1'
services: ['web', 'api', 'worker']
relabel_configs:
- source_labels: ['__meta_consul_service']
target_label: 'service'
- source_labels: ['__meta_consul_tags']
target_label: 'tags'
Consul 服务发现的核心优势在于:
- 自动感知服务注册与注销——服务上线即被监控,下线自动移除
- 丰富的元数据——Consul 的 tags、dc、node 等信息都可以通过 relabel 映射到 Prometheus 标签
- 健康检查联动——Consul 标记为不健康的服务,Prometheus 默认不会抓取
我曾经踩过一个坑:Consul 里注册了上百个服务,但 Prometheus 只关心其中几个。如果不加 services 过滤,Prometheus 会尝试发现所有服务,导致 target 数量爆炸,内存飙升。所以,一定要用 services 参数或 relabel 做过滤。
4.4 基于 Kubernetes 的服务发现:云原生的终极方案
如果你在用 Kubernetes,那 Prometheus 的 k8s 服务发现就是你的首选。它可以直接从 Kubernetes API 获取 Pod、Service、Node、Endpoint 等信息。
配置示例(发现所有 Pod):
scrape_configs:
- 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__
这段配置什么意思?说白了就是:只抓取那些打了 prometheus.io/scrape=true 注解的 Pod,并且从注解里读取端口和路径。
Kubernetes 服务发现支持 5 种 role:
| Role | 发现对象 | 典型用途 |
|---|---|---|
| node | Kubernetes 节点 | 监控节点指标(kubelet、node_exporter) |
| service | Service 对象 | 监控 Service 的 ClusterIP 或 LoadBalancer |
| pod | Pod 实例 | 直接抓取 Pod 的 metrics 端点 |
| endpoints | Endpoints 对象 | 监控 Service 背后的 Pod 列表 |
| ingress | Ingress 对象 | 监控 Ingress 控制器 |
我建议你优先用 endpoints 或 pod 角色。为什么?因为 service 角色只能抓到 Service 的 ClusterIP,但 Service 本身不暴露 metrics,真正暴露指标的是背后的 Pod。endpoints 角色直接给你 Pod 列表,更精准。
4.5 四种方式怎么选?我的建议
没有银弹。不同场景用不同方式:
- 静态配置:基础设施组件、测试环境、兜底方案
- 文件服务发现:配合 CMDB 或配置中心,半自动化场景
- Consul 服务发现:微服务架构(非 K8s 环境),服务注册中心已存在
- Kubernetes 服务发现:K8s 环境,云原生应用,首选方案
你想想看,如果你的业务跑在 K8s 上,却还在用静态配置写 Pod IP,那每次 Pod 重启你都得改配置——这不叫运维,这叫自虐。
嗯,这一章就到这里。下一章我们聊聊 relabel 机制——这是 Prometheus 服务发现里最灵活、也最容易踩坑的部分。到时候我会分享几个我亲手填过的坑。