在这里插入图片描述

👋 大家好,欢迎来到我的技术博客!
📚 在这里,我会分享学习笔记、实战经验与技术思考,力求用简单的方式讲清楚复杂的问题。
🎯 本文将围绕Prometheus这个话题展开,希望能为你带来一些启发或实用的参考。
🌱 无论你是刚入门的新手,还是正在进阶的开发者,希望你都能有所收获!


Prometheus - 服务发现深度解析:Consul/K8s 自动发现配置

在现代云原生架构中,服务的动态性已成为常态。容器频繁启停、Pod自动扩缩容、微服务实例漂移……这些都使得传统的静态监控配置方式变得不可行。Prometheus 作为 CNCF 毕业的主流监控系统,其强大的 服务发现(Service Discovery) 能力正是应对这一挑战的关键武器 🔥。

本文将深入剖析 Prometheus 的服务发现机制,重点聚焦于 ConsulKubernetes(K8s) 两大主流平台的自动发现配置,并辅以 Java 示例代码,帮助读者真正掌握从理论到实践的完整链路。


一、为什么需要服务发现?

在传统监控体系中,我们通常通过静态配置文件明确指定被监控目标的 IP 地址和端口:

scrape_configs:
  - job_name: 'static-node'
    static_configs:
      - targets: ['192.168.1.10:9100', '192.168.1.11:9100']

这种方式在固定基础设施下尚可工作,但在以下场景中会迅速失效:

  • Kubernetes 中 Pod IP 动态分配,每次重启都会变化;
  • 微服务架构中服务实例数量随负载自动伸缩;
  • 蓝绿部署或金丝雀发布时新旧版本实例共存;
  • 跨可用区/区域部署导致目标地址频繁变更。

此时,服务发现 就显得至关重要。它允许 Prometheus 动态地从外部系统获取最新的目标列表,无需人工干预即可持续监控所有活跃实例。

💡 核心思想:Prometheus 不再“记住”目标是谁,而是“询问”谁是当前的目标。


二、Prometheus 服务发现架构概览

Prometheus 的服务发现机制基于 relabeling(重标记)SD 配置(Service Discovery Configuration) 实现。其内部流程如下:

定期拉取

SD Provider
(如 Consul/K8s)

Prometheus SD Manager

Target List

Relabeling Rules

Final Target Set

Scrape Loop

Metrics Storage

关键组件说明:

  • SD Provider:提供服务注册信息的外部系统(如 Consul、Kubernetes API Server)。
  • SD Manager:Prometheus 内部模块,负责与各 Provider 对接,周期性拉取最新目标。
  • Relabeling:对原始目标进行过滤、转换、添加标签等操作,决定最终是否纳入监控。
  • Scrape Loop:实际执行指标抓取的循环。

Prometheus 原生支持多种服务发现机制,包括:

  • kubernetes
  • consul
  • dns
  • ec2
  • gce
  • file
  • azure
  • 等等

本文将重点讲解 ConsulKubernetes 两种最常用的方式。


三、基于 Consul 的服务发现

3.1 Consul 简介

Consul 是 HashiCorp 推出的服务网格解决方案,提供 服务发现、健康检查、KV 存储、多数据中心 等能力。其服务注册模型简单直观:服务实例启动时向 Consul Agent 注册自身信息(名称、IP、端口、健康检查等),Prometheus 则通过 Consul HTTP API 查询这些信息。

🌐 官方文档:https://developer.hashicorp.com/consul

3.2 Consul 服务注册示例(Java)

假设我们有一个 Spring Boot 应用,需自动注册到 Consul。首先添加依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>

然后在 application.yml 中配置:

spring:
  application:
    name: user-service  # 服务名
  cloud:
    consul:
      host: localhost
      port: 8500
      discovery:
        health-check-path: /actuator/health
        health-check-interval: 10s
        tags: prod, v1  # 可用于后续 relabel 过滤

应用启动后,会自动向 Consul 注册一个名为 user-service 的服务,包含 IP、端口及健康检查信息。

⚠️ 注意:确保应用暴露了 /actuator/prometheus 端点(通过 micrometer-registry-prometheus)。

3.3 Prometheus 配置 Consul SD

prometheus.yml 中添加如下配置:

scrape_configs:
  - job_name: 'consul-services'
    consul_sd_configs:
      - server: 'localhost:8500'  # Consul Agent 地址
        services: ['user-service', 'order-service']  # 只发现指定服务
        # 或留空表示发现所有服务
    relabel_configs:
      - source_labels: [__meta_consul_service]
        target_label: job
      - source_labels: [__meta_consul_tags]
        target_label: tags
      - source_labels: [__address__]
        target_label: instance
关键元标签(Meta Labels)

Prometheus 从 Consul 获取目标时会附加一系列 __meta_consul_* 标签,常用包括:

元标签 说明
__meta_consul_address 实例 IP
__meta_consul_service_port 服务端口
__meta_consul_service 服务名称
__meta_consul_tags 服务标签(逗号分隔)
__meta_consul_dc 数据中心

📌 默认情况下,Prometheus 使用 __address__ = __meta_consul_address:__meta_consul_service_port 作为抓取地址。

3.4 高级 Relabeling:按标签过滤

假设我们只想监控 prod 环境的服务:

relabel_configs:
  # 保留包含 "prod" 标签的服务
  - source_labels: [__meta_consul_tags]
    regex: .*prod.*
    action: keep
  # 设置 job 名为服务名
  - source_labels: [__meta_consul_service]
    target_label: job
  # 提取版本号(假设标签格式为 "v1", "v2")
  - source_labels: [__meta_consul_tags]
    regex: .*v(\d+).*
    target_label: version
    replacement: $1

这样,只有带 prod 标签的实例才会被纳入监控,且自动打上 version 标签。

3.5 健康检查集成

Consul 的强大之处在于其内置健康检查。Prometheus 只会发现状态为 passing 的实例。这意味着:

  • 若某实例宕机,Consul 将其标记为 critical;
  • Prometheus 下次拉取时自动剔除该目标;
  • 无需额外配置,实现“故障自动隔离”。

✅ 这是静态配置无法比拟的优势!


四、基于 Kubernetes 的服务发现

Kubernetes 是当前最主流的容器编排平台,其服务发现机制更为复杂但也更强大。Prometheus 可直接对接 K8s API Server,发现各类资源(Pod、Service、Endpoint 等)。

🌐 官方文档:https://kubernetes.io/docs/concepts/services-networking/service/

4.1 K8s 中的监控目标类型

Prometheus 支持从以下 K8s 资源发现目标:

资源类型 用途
pod 直接监控 Pod(需暴露 metrics 端口)
service 通过 Service 抓取后端 Pod
endpoints 最常用!对应 Service 的实际 Endpoint
node 监控节点(kubelet)
ingress 监控 Ingress 控制器

💡 推荐使用 endpoints:它直接对应 Service 的后端 Pod 列表,且自动处理 Pod 变化。

4.2 Java 应用在 K8s 中的暴露方式

假设我们有一个 Spring Boot 应用,需在 K8s 中暴露指标:

Dockerfile

FROM openjdk:17-jdk-slim
COPY target/app.jar app.jar
EXPOSE 8080 8081  # 8080 业务端口,8081 管理端口(含 metrics)
ENTRYPOINT ["java", "-jar", "/app.jar"]

application.yml

management:
  endpoints:
    web:
      exposure:
        include: health,info,prometheus
  server:
    port: 8081  # 独立管理端口,避免与业务混用

K8s Deployment + Service

apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
        metrics: enabled  # 关键!用于 Prometheus 发现
    spec:
      containers:
      - name: app
        image: user-service:latest
        ports:
        - containerPort: 8080
        - containerPort: 8081  # metrics 端口
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
  annotations:
    prometheus.io/scrape: "true"   # 启用自动发现
    prometheus.io/port: "8081"     # 指定 metrics 端口
    prometheus.io/path: "/actuator/prometheus"  # 指定路径
spec:
  selector:
    app: user-service
  ports:
  - name: http
    port: 8080
    targetPort: 8080
  - name: metrics
    port: 8081
    targetPort: 8081

📌 注意:通过 Pod LabelService Annotation 配合,实现灵活控制。

4.3 Prometheus 配置 K8s SD

prometheus.yml 中配置:

scrape_configs:
  - job_name: 'kubernetes-pods'
    kubernetes_sd_configs:
      - role: pod  # 发现 Pod
        api_server: https://kubernetes.default.svc
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
    relabel_configs:
      # 仅保留带有 "metrics: enabled" 标签的 Pod
      - source_labels: [__meta_kubernetes_pod_label_metrics]
        action: keep
        regex: enabled
      # 从 annotation 获取端口和路径
      - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        target_label: __metrics_path__
        regex: (.+)
        replacement: :${1}
      - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
        action: replace
        target_label: __address__
        regex: (.+?)(?::\d+)?;(\d+)
        replacement: ${1}:${2}
      # 设置 job 名为 Pod 名称
      - source_labels: [__meta_kubernetes_pod_name]
        target_label: job
关键元标签(K8s Pod)
元标签 说明
__meta_kubernetes_pod_name Pod 名称
__meta_kubernetes_pod_ip Pod IP
__meta_kubernetes_pod_label_<labelname> Pod 标签值
__meta_kubernetes_pod_annotation_<annotationname> Pod 注解值
__meta_kubernetes_namespace 命名空间

🔍 注意:Label 和 Annotation 的 key 中 - 会被替换为 _

4.4 使用 Endpoints 角色(推荐)

更稳健的方式是发现 endpoints

- job_name: 'kubernetes-endpoints'
  kubernetes_sd_configs:
    - role: endpoints
  relabel_configs:
    # 仅保留带有 prometheus.io/scrape=true 的 Service
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
      action: keep
      regex: true
    # 设置 metrics 路径
    - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
      action: replace
      target_label: __metrics_path__
      regex: (.+)
      replacement: ${1}
    # 设置端口
    - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
      action: replace
      target_label: __address__
      regex: (.+?)(?::\d+)?;(\d+)
      replacement: ${1}:${2}
    # 添加命名空间和服务名标签
    - source_labels: [__meta_kubernetes_namespace]
      target_label: namespace
    - source_labels: [__meta_kubernetes_service_name]
      target_label: service

这种方式的优势:

  • 自动处理 Service 后端 Pod 的增删;
  • 天然支持 headless Service;
  • 与 K8s 网络模型一致。

4.5 RBAC 权限配置

Prometheus Pod 需要有权限访问 K8s API。创建 ServiceAccount 和 RoleBinding:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: prometheus
  namespace: monitoring
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: prometheus
rules:
- apiGroups: [""]
  resources:
  - nodes
  - nodes/proxy
  - services
  - endpoints
  - pods
  verbs: ["get", "list", "watch"]
- apiGroups: ["networking.k8s.io"]
  resources:
  - ingresses
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: ClusterRole
  name: prometheus
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: monitoring

在 Prometheus Deployment 中指定该 ServiceAccount。


五、Relabeling 深度解析

无论 Consul 还是 K8s,relabeling 是服务发现的灵魂。它决定了哪些目标被保留、如何打标签、抓取路径是什么。

5.1 Relabeling 基本语法

relabel_configs:
  - source_labels: [label1, label2]  # 源标签列表
    separator: ;                     # 分隔符(默认 ;)
    regex: (.*)                      # 正则表达式
    modulus: 1                       # 取模(用于 hashmod)
    target_label: new_label          # 目标标签
    replacement: $1                  # 替换值(支持 $1, $2...)
    action: replace                  # 动作(keep, drop, replace, hashmod...)

5.2 常用 Action

Action 说明
keep 仅当 regex 匹配 source_labels 时保留目标
drop 仅当 regex 匹配时丢弃目标
replace 将匹配内容替换到 target_label
hashmod 对 source_labels 哈希后取模,用于分片

5.3 实战:多环境隔离

假设 K8s 中有 devstagingprod 命名空间,我们只想监控 prod

- source_labels: [__meta_kubernetes_namespace]
  regex: prod
  action: keep

5.4 实战:自动设置 job 名

根据 Service 名称设置 job:

- source_labels: [__meta_kubernetes_service_name]
  target_label: job

5.5 实战:提取版本号

从 Pod 标签 app.kubernetes.io/version: v1.2.3 提取主版本:

- source_labels: [__meta_kubernetes_pod_label_app_kubernetes_io_version]
  regex: v(\d+)\.\d+\.\d+
  target_label: version
  replacement: $1

六、性能与最佳实践

6.1 发现频率

Prometheus 默认每 60 秒 从 SD Provider 拉取一次。可通过 refresh_interval 调整:

consul_sd_configs:
  - server: 'localhost:8500'
    refresh_interval: 30s  # 更频繁,但增加 Consul 负载

⚠️ 不建议低于 15s,避免对 Provider 造成压力。

6.2 目标数量控制

避免发现过多无用目标:

  • Consul:通过 services 白名单限制;
  • K8s:通过 Label Selector 或 Annotation 过滤。

6.3 使用中间件:Prometheus Operator

在 K8s 中,Prometheus Operator 是更高级的管理方式。它通过 CRD(Custom Resource Definition)简化配置:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: user-service-monitor
spec:
  selector:
    matchLabels:
      app: user-service
  endpoints:
  - port: metrics
    path: /actuator/prometheus
    interval: 30s

Operator 自动将其转换为 Prometheus 的 SD 配置。

🌐 官方文档:https://prometheus-operator.dev/

6.4 调试技巧

  • 访问 Prometheus Web UI → Status → Targets 查看当前目标;
  • 查看 Service Discovery 页面,观察原始目标和 relabel 结果;
  • 使用 count(up) by (job) 验证目标数量是否合理。

七、常见问题排查

7.1 目标未出现

  • 检查 SD Provider 是否可达(网络、认证);
  • 检查 relabel_rules 是否误 drop
  • 检查 Consul 服务健康状态或 K8s Pod 是否 Running。

7.2 抓取失败(down)

  • 检查 __address__ 是否正确(端口、路径);
  • 在 Prometheus Pod 内 curl 目标地址测试连通性;
  • 检查目标应用是否真的暴露了 /metrics

7.3 标签未生效

  • 确认元标签名称是否正确(注意 _ 替换);
  • 检查 regex 是否匹配(可使用在线正则测试工具);
  • 注意 relabel 顺序:前面的规则会影响后面的输入。

八、总结

Prometheus 的服务发现机制是其适应云原生环境的核心能力。通过与 ConsulKubernetes 的深度集成,我们实现了:

  • 动态目标管理:自动感知实例变化;
  • 零配置扩展:新服务上线即被监控;
  • 环境隔离:通过标签灵活划分监控范围;
  • 健康联动:结合健康检查自动剔除故障实例。

无论是基于 VM 的微服务架构,还是全容器化的 K8s 集群,合理配置服务发现都能极大提升监控系统的 自动化水平和可靠性

🚀 最后建议:从小规模开始,逐步完善 relabel 规则,善用 Prometheus UI 调试,你将构建出一个“活”的监控系统!


希望本文能帮助你彻底掌握 Prometheus 服务发现的精髓。如有疑问,欢迎在评论区交流!


🙌 感谢你读到这里!
🔍 技术之路没有捷径,但每一次阅读、思考和实践,都在悄悄拉近你与目标的距离。
💡 如果本文对你有帮助,不妨 👍 点赞、📌 收藏、📤 分享 给更多需要的朋友!
💬 欢迎在评论区留下你的想法、疑问或建议,我会一一回复,我们一起交流、共同成长 🌿
🔔 关注我,不错过下一篇干货!我们下期再见!✨

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐