3. ServiceMonitor 基础定义:apiVersion、kind、metadata、spec 结构详解

ServiceMonitor 是 Prometheus Operator 引入的自定义资源(CRD),用于声明式地定义 Prometheus 应监控哪些 Service 端点。理解其基础定义结构是标签治理的前提——因为标签选择逻辑、端点匹配规则、重命名行为都直接由 spec 中的字段控制。本章将逐层拆解 ServiceMonitor 的四个核心组成部分:apiVersion、kind、metadata 和 spec,并明确区分必填字段与可选字段。

3.1 顶层结构概览

一个完整的 ServiceMonitor YAML 遵循标准的 Kubernetes 资源格式。以下是一个最小可用的示例,展示了四个顶层字段的排列关系:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: example-monitor
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: my-service
  endpoints:
  - port: http-metrics
    interval: 30s

下面通过一张结构图直观展示 ServiceMonitor 的顶层字段及其层级关系:

ServiceMonitor 顶层字段结构 apiVersion monitoring.coreos.com/v1 kind ServiceMonitor metadata name, namespace, labels spec(核心配置区) selector endpoints namespaceSelector jobLabel targetLabels podTargetLabels 必填字段:apiVersion、kind、metadata.name、spec.selector、spec.endpoints

3.2 apiVersion 与 kind:资源标识

字段 值 说明 必填
apiVersion monitoring.coreos.com/v1 Prometheus Operator 的 API 组和版本。当前稳定版为 v1,早期版本 v1alpha1 已废弃。 是
kind ServiceMonitor 固定值,标识资源类型为 ServiceMonitor。大小写敏感。 是
版本兼容提示: 如果集群中安装的 Prometheus Operator 版本较旧(低于 v0.30),请确认是否支持 monitoring.coreos.com/v1。建议始终使用 v1 版本,因为 v1alpha1 已在 Operator v0.56+ 中移除。

3.3 metadata:元数据定义

metadata 字段遵循 Kubernetes 通用元数据规范,用于标识和分类 ServiceMonitor 资源。

字段 类型 必填 说明
name string 是 资源名称,在命名空间内唯一。遵循 DNS-1123 子域名规范(小写字母、数字、连字符)。
namespace string 否* ServiceMonitor 所在的命名空间。如果未指定,则使用当前上下文命名空间。Prometheus 只能发现同一命名空间或通过 namespaceSelector 允许的 ServiceMonitor。
labels map[string]string 否 标签键值对。用于选择器匹配、组织分类。在标签治理中,此处定义的标签不会自动传递到监控指标,但可用于 Prometheus 的 serviceMonitorSelector 匹配。
annotations map[string]string 否 注解,用于非标识性元数据,如描述信息、工具集成等。

* namespace 在 YAML 中通常建议显式声明,避免因 kubectl 上下文不同导致资源创建位置错误。

3.4 spec:核心配置结构

spec 是 ServiceMonitor 的功能主体,定义了 Prometheus 如何发现目标、采集指标以及处理标签。以下按字段重要性分组说明。

3.4.1 必填字段

字段 类型 说明
selector LabelSelector 定义如何选择 Service。支持 matchLabels(精确匹配)和 matchExpressions(表达式匹配)。被选中的 Service 的端点将成为 Prometheus 的抓取目标。
endpoints []Endpoint 端点列表,定义从选中的 Service 的哪些端口抓取指标。每个端点至少需要指定 port 或 targetPort。

3.4.2 常用可选字段

字段 类型 默认值 说明
namespaceSelector NamespaceSelector 仅当前命名空间 控制 ServiceMonitor 可以跨命名空间选择 Service。设置 any: true 允许所有命名空间,或通过 matchNames 指定允许的命名空间列表。
jobLabel string 无 指定 ServiceMonitor 的 metadata 中哪个标签的值作为 Prometheus 的 job 标签值。例如 jobLabel: "app" 会将 ServiceMonitor 的 app 标签值赋给抓取指标的 job 标签。
targetLabels []string 无 指定从 Service 对象上复制哪些标签到抓取目标。常用于将业务标签传递到指标中。
podTargetLabels []string 无 指定从 Pod 对象上复制哪些标签到抓取目标。比 targetLabels 更细粒度,直接作用于 Pod 级别。
sampleLimit uint64 无限制 限制每个端点采集的样本数量上限,防止高基数标签导致 Prometheus 内存溢出。
endpoints[].interval duration 全局配置 抓取间隔,如 30s、1m。覆盖 Prometheus 全局 scrape_interval。
endpoints[].scrapeTimeout duration 全局配置 抓取超时时间,必须小于 interval。
endpoints[].path string /metrics 指标 HTTP 路径。如果应用暴露在非标准路径,需要显式设置。
endpoints[].scheme string http 协议,支持 http 和 https。
endpoints[].params map[string][]string 无 附加的 HTTP URL 参数,如 params: { "format": ["prometheus"] }。
endpoints[].relabelings []RelabelConfig 无 重标签规则,在抓取前对标签进行增删改。这是标签治理的核心战场,将在后续章节深入讲解。
endpoints[].metricRelabelings []RelabelConfig 无 指标重标签规则,在抓取后对指标标签进行处理。用于丢弃高基数标签、重命名指标等。

3.5 必填字段与可选字段的完整清单

以下流程图帮助快速判断一个 ServiceMonitor 定义是否合法:

ServiceMonitor 字段合法性检查流程 开始检查 apiVersion 正确? kind = ServiceMonitor? metadata.name 非空? spec.selector 已定义? spec.endpoints 非空? ✅ 合法定义 ❌ 检查版本号 ❌ 必须为 ServiceMonitor ❌ 必须提供名称 ❌ 必须定义 selector ❌ 至少一个 endpoint

3.6 实战示例:完整定义与字段说明

以下是一个生产级 ServiceMonitor 示例,包含必填字段和常用可选字段:

apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
  name: payment-service-monitor
  namespace: monitoring
  labels:
    release: prometheus-stack      # 用于 Prometheus 的 serviceMonitorSelector 匹配
    team: payment                   # 团队标签,便于资源分类
    environment: production         # 环境标签
spec:
  # --- 必填字段 ---
  selector:
    matchLabels:
      app: payment-service          # 选择 app=payment-service 的 Service
    matchExpressions:               # 可选:表达式匹配
      - key: tier
        operator: In
        values: ["backend", "critical"]
  endpoints:
    - port: metrics                 # 引用 Service 中定义的端口名称
      interval: 30s
      scrapeTimeout: 10s
      path: /metrics
      scheme: http
      # 重标签规则(标签治理核心)
      relabelings:
        - sourceLabels: [__meta_kubernetes_pod_node_name]
          targetLabel: node
          action: replace
      metricRelabelings:
        - sourceLabels: [__name__]
          regex: "go_.*"
          action: drop               # 丢弃所有 go_ 开头的指标

  # --- 可选字段 ---
  namespaceSelector:
    matchNames:
      - production                   # 只允许选择 production 命名空间的 Service
  jobLabel: "app"                    # 将 ServiceMonitor 的 app 标签值作为 job 标签
  targetLabels:
    - app
    - version                        # 从 Service 复制 app 和 version 标签到目标
  podTargetLabels:
    - pod-template-hash              # 从 Pod 复制 pod-template-hash 标签
  sampleLimit: 50000                 # 每个端点最多采集 50000 个样本
标签治理关键点: 上述示例中,relabelings 和 metricRelabelings 是标签治理的主要操作位置。targetLabels 和 podTargetLabels 控制哪些 Kubernetes 标签流入 Prometheus 标签空间。合理配置这些字段可以避免标签爆炸,同时保留必要的业务上下文。

3.7 常见错误与避坑指南

  • selector 为空或缺失: 如果 spec.selector 为空,Prometheus Operator 不会选择任何 Service,导致抓取目标为空。必须至少提供 matchLabels 或 matchExpressions。
  • endpoints 中 port 与 targetPort 混淆: port 引用 Service 中定义的端口名称(string),targetPort 引用 Pod 中的端口号(int)或名称。两者只需指定其一,同时指定可能导致歧义。
  • namespaceSelector 未配置导致跨命名空间失败: 默认情况下,ServiceMonitor 只能选择同一命名空间的 Service。如果需要跨命名空间选择,必须显式配置 namespaceSelector。
  • jobLabel 指向不存在的标签: 如果 jobLabel 指定的标签在 ServiceMonitor 的 metadata 中不存在,Prometheus 会使用默认的 job 名称(ServiceMonitor 名称)。建议始终确保标签存在。
  • sampleLimit 设置过小: 如果应用暴露大量指标,过小的 sampleLimit 会导致部分指标被静默丢弃。建议先观察正常采集量,再设置合理的上限。
生产环境警告: 不要在生产环境中使用 namespaceSelector.any: true,这会允许 ServiceMonitor 选择集群中所有命名空间的 Service,可能导致意外的抓取目标泄露或性能问题。始终使用 matchNames 显式列出允许的命名空间。

3.8 本章小结