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 的传统服务
  • 作为其他服务发现方式的「备用方案」
小技巧: 静态配置里可以加 labels,这些 labels 会附加到所有抓取到的指标上。我习惯用 labels 标记环境、机房、团队,方便后续做告警路由和指标聚合。

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 自动加载。这样既不用改主配置,又能实现半自动化。

注意: 文件服务发现的刷新间隔默认是 5 分钟。如果你需要秒级响应,记得调小 refresh_interval。但别设太短,否则磁盘 I/O 会上去。我个人习惯设 30 秒到 1 分钟。

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 做过滤

核心思路: Consul 服务发现适合「服务粒度」的监控。每个微服务注册到 Consul,Prometheus 自动发现并抓取。配合 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 列表,更精准。

避坑指南: 我曾经遇到过一个问题——Prometheus 在 Kubernetes 里运行,但 RBAC 权限没配好,导致服务发现一直报 403。记住,Prometheus 需要以下权限:get、list、watch 对应资源(pods、services、endpoints、nodes)。用 ClusterRole 和 ClusterRoleBinding 绑定到 Prometheus 的 ServiceAccount。

4.5 四种方式怎么选?我的建议

没有银弹。不同场景用不同方式:

  • 静态配置:基础设施组件、测试环境、兜底方案
  • 文件服务发现:配合 CMDB 或配置中心,半自动化场景
  • Consul 服务发现:微服务架构(非 K8s 环境),服务注册中心已存在
  • Kubernetes 服务发现:K8s 环境,云原生应用,首选方案

你想想看,如果你的业务跑在 K8s 上,却还在用静态配置写 Pod IP,那每次 Pod 重启你都得改配置——这不叫运维,这叫自虐。

嗯,这一章就到这里。下一章我们聊聊 relabel 机制——这是 Prometheus 服务发现里最灵活、也最容易踩坑的部分。到时候我会分享几个我亲手填过的坑。