4. Prometheus Operator 架构:核心组件与自动发现原理

在生产环境中,手动管理 Prometheus 配置(如 scrape_configs、rule_files)会随着微服务数量增长而迅速失控。Prometheus Operator 通过 Kubernetes 原生声明式 API 解决了这一痛点,将 Prometheus 的部署、配置、服务发现和告警管理全部抽象为自定义资源(CRD)。本章深入剖析 Operator 的组件架构、ServiceMonitor/PodMonitor 配置细节以及自动发现机制。

4.1 整体架构与核心组件

Prometheus Operator 遵循典型的 Kubernetes Operator 模式:一个控制循环(Controller)持续监听自定义资源的变化,并调和出期望的 Prometheus 实例状态。其核心组件包括:

组件 CRD 名称 职责
Operator — 核心控制器,监听所有 CRD 事件,创建/更新/删除 StatefulSet、Service、ConfigMap 等底层资源
Prometheus prometheuses.monitoring.coreos.com 定义 Prometheus 实例的规格(版本、资源、存储、副本数),Operator 据此生成 StatefulSet
ServiceMonitor servicemonitors.monitoring.coreos.com 基于 Kubernetes Service 的标签选择器,定义如何抓取 Service 背后 Pod 的指标
PodMonitor podmonitors.monitoring.coreos.com 直接基于 Pod 标签选择器,不依赖 Service,适用于 Sidecar 或无头服务场景
PrometheusRule prometheusrules.monitoring.coreos.com 定义告警规则和记录规则,Operator 自动合并并挂载到 Prometheus 实例
Alertmanager alertmanagers.monitoring.coreos.com 定义 Alertmanager 集群规格,Operator 生成对应的 StatefulSet 和配置
关键设计原则: Operator 不直接修改 Prometheus 配置文件,而是通过 CRD 声明期望状态,由 Operator 在内存中生成最终的 prometheus.yaml 并挂载到 Pod 中。这保证了配置的幂等性和可审计性。
Prometheus Operator 整体架构图 Prometheus Operator 核心架构 kubectl apply -f CRD Prometheus Operator (Controller) 监听 CRD 事件 · 调和期望状态 Kubernetes API Server — 自定义资源 (CRD) Prometheus ServiceMonitor PodMonitor Operator 自动生成的 Kubernetes 原生资源 StatefulSet ConfigMap Service Secret Prometheus 实例 (Pod) 自动挂载生成的 prometheus.yaml Operator 不修改配置文件 而是通过 CRD 声明式驱动

4.2 ServiceMonitor 配置详解

ServiceMonitor 是 Prometheus Operator 中最常用的抓取配置 CRD。它通过 标签选择器 匹配 Kubernetes Service,然后从 Service 的 spec.ports 中获取抓取端口和路径。

4.2.1 核心字段与示例

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: my-app-monitor
  namespace: monitoring
spec:
  # 选择要抓取的 Service(命名空间选择器 + 标签选择器)
  namespaceSelector:
    matchNames:
      - production
  selector:
    matchLabels:
      app: my-app
      release: stable
  # 定义抓取端点
  endpoints:
  - port: http-metrics      # 对应 Service 的端口名称
    interval: 15s
    path: /metrics
    scheme: http
    # 可选:TLS 配置、BasicAuth、Relabel 等
    relabelings:
    - sourceLabels: [__meta_kubernetes_pod_node_name]
      targetLabel: node
      action: replace
  # 目标标签(自动附加到所有抓取到的指标)
  targetLabels:
    - app
    - version
匹配逻辑: ServiceMonitor 先通过 namespaceSelector 限定命名空间范围,再通过 selector.matchLabels 匹配 Service 的标签。匹配到的 Service 下的所有 Endpoints(即 Pod IP + 端口)都会成为 Prometheus 的抓取目标。

4.2.2 ServiceMonitor 与 Service 的关联流程

  1. 用户创建 ServiceMonitor:指定 namespaceSelector 和 selector。
  2. Operator 监听事件:发现新的 ServiceMonitor 资源。
  3. 查询匹配的 Service:Operator 调用 Kubernetes API,列出指定命名空间下所有标签匹配的 Service。
  4. 解析 Endpoints:对于每个匹配的 Service,获取其 spec.ports 中名称与 endpoints.port 匹配的端口,再查询该 Service 背后的 Endpoints 对象,得到所有 Pod IP。
  5. 生成 scrape_config:Operator 将上述信息写入 Prometheus 配置的 scrape_configs 段,并触发 Prometheus 热加载。

4.3 PodMonitor 配置详解

PodMonitor 与 ServiceMonitor 类似,但 不经过 Service 层,直接通过 Pod 标签选择器抓取。适用于以下场景:

  • Sidecar 模式:主业务容器与指标导出 Sidecar 同 Pod,但未创建 Service。
  • 无头服务(Headless Service):需要直接抓取每个 Pod 实例。
  • Batch 任务:短生命周期 Pod,不需要 Service 抽象。

4.3.1 PodMonitor 示例

apiVersion: monitoring.coreos.com/v1
kind: PodMonitor
metadata:
  name: sidecar-monitor
  namespace: monitoring
spec:
  namespaceSelector:
    any: true  # 选择所有命名空间
  selector:
    matchLabels:
      sidecar: metrics-exporter
  podMetricsEndpoints:
  - port: metrics
    interval: 30s
    path: /metrics
    relabelings:
    - sourceLabels: [__meta_kubernetes_pod_container_name]
      targetLabel: container
      action: replace
注意: PodMonitor 使用 podMetricsEndpoints 字段(而非 endpoints),且端口必须对应 Pod 内容器的 containerPort 名称。如果 Pod 有多个容器,需要确保端口名称唯一。

4.4 自动发现原理与 Relabeling 机制

Prometheus Operator 的自动发现能力建立在 Kubernetes 服务发现(SD)之上,并通过 Relabeling 对发现的目标进行过滤、修改和标记。理解 Relabeling 是排查抓取问题的关键。

4.4.1 自动发现流程

自动发现与 Relabeling 流程 Prometheus 自动发现与 Relabeling 流程 阶段 1:K8s API 发现 列出 Service / Pod / Endpoints 阶段 2:原始目标列表 __meta_kubernetes_* 标签 阶段 3:Relabeling 过滤 / 修改 / 删除标签 阶段 4:最终抓取目标 带 instance / job 标签 Relabeling 常见动作 • replace:替换标签值(默认动作) • keep/drop:保留/丢弃匹配正则的目标 • labelmap:将匹配的源标签映射为新标签

4.4.2 关键元标签与 Relabeling 实战

Prometheus 在自动发现时会为每个目标注入一组 __meta_kubernetes_* 标签。以下是最常用的元标签:

元标签 来源 示例值
__meta_kubernetes_namespace Pod/Service 命名空间 production
__meta_kubernetes_pod_name Pod 名称 my-app-7d8f9c6b4c-abcde
__meta_kubernetes_pod_node_name Pod 所在节点 node-01
__meta_kubernetes_service_name Service 名称(仅 ServiceMonitor) my-app-svc
__meta_kubernetes_pod_label_<label> Pod 标签(自动展开) __meta_kubernetes_pod_label_app
__meta_kubernetes_pod_annotation_<annotation> Pod 注解 __meta_kubernetes_pod_annotation_prometheus_io_scrape

4.4.3 典型 Relabeling 场景

场景: 只抓取 production 命名空间中 app=my-app 且 version=v2 的 Pod,并将 version 标签暴露为最终标签。
relabelings:
- sourceLabels: [__meta_kubernetes_namespace]
  regex: production
  action: keep
- sourceLabels: [__meta_kubernetes_pod_label_app]
  regex: my-app
  action: keep
- sourceLabels: [__meta_kubernetes_pod_label_version]
  targetLabel: version
  action: replace
- sourceLabels: [__meta_kubernetes_pod_name]
  targetLabel: instance
  action: replace
排查要点: 如果目标没有出现在 Prometheus 的 Target 页面,请按以下顺序排查:
1. 检查 ServiceMonitor/PodMonitor 的 namespaceSelector 是否覆盖了目标命名空间。
2. 检查 selector 的标签是否与 Service/Pod 完全匹配(包括 release 等附加标签)。
3. 检查 Relabeling 中是否有 keep 或 drop 规则误过滤了目标。
4. 查看 Prometheus 实例的日志,搜索 service monitor 或 pod monitor 相关错误。

4.5 ServiceMonitor 与 PodMonitor 对比

维度 ServiceMonitor PodMonitor
发现对象 通过 Service 标签匹配,再解析 Endpoints 直接通过 Pod 标签匹配
端口定义 引用 Service 的 spec.ports[].name 引用 Pod 内容器的 ports[].name
适用场景 标准微服务,有稳定 Service 层 Sidecar、无头服务、短生命周期 Pod
负载均衡 Service 可能做负载均衡(ClusterIP) 直接抓取每个 Pod,无负载均衡
元标签丰富度 包含 Service 级别的元标签 仅包含 Pod 级别的元标签
配置字段 endpoints podMetricsEndpoints

4.6 蓝绿发布场景下的自动发现挑战

在蓝绿发布过程中,ServiceMonitor 和 PodMonitor 的自动发现行为会直接影响流量切换的观测连续性:

  • ServiceMonitor 切换滞后:当 Service 的 selector 从蓝色 Pod 标签切换到绿色 Pod 标签时,Prometheus 需要等待下一次 relist interval(默认 30s-60s)才能发现新的 Endpoints。这会导致抓取目标短暂为空或出现旧目标。
  • PodMonitor 实时性更高:PodMonitor 直接监听 Pod 标签变化,新 Pod 创建后几乎立即被发现(取决于 Operator 的同步周期,通常 10-15s)。
  • Relabeling 冲突:如果蓝绿 Pod 带有相同的 app 标签但不同的 version 标签,Relabeling 规则需要正确处理,避免将两个版本的目标合并到同一个 job 中导致指标混乱。
最佳实践: 在蓝绿发布期间,建议同时保留蓝色和绿色 Pod 的抓取目标,通过 version 或 deployment 标签区分。待流量完全切换并稳定后,再通过更新 ServiceMonitor 的 selector 或直接删除旧 Pod 来清理目标。这样可以保证发布过程中的指标不中断。