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 的顶层字段及其层级关系:
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 定义是否合法:
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 显式列出允许的命名空间。