prometheus relabeling 配置中的防御性编程策略
文章目录
背景描述
搭建victoriametrics cluster集群后,使用VMServiceScrape方式对 kube-state-metrics进行指标采集是发现个有趣的问题。
这里先放一下的采集配置文件:
VMServiceScrape 配置文件如下:
apiVersion: operator.victoriametrics.com/v1beta1
kind: VMServiceScrape
metadata:
annotations:
labels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
app.kubernetes.io/part-of: kube-prometheus
app.kubernetes.io/version: 2.13.0
name: kube-state-metrics
namespace: kube-system
spec:
endpoints:
- interval: 30s
metricRelabelConfigs:
- action: drop
regex:
- kube_endpoint_address_not_ready|kube_endpoint_address_available
sourceLabels:
- __name__
port: http-metrics
relabelConfigs:
- action: labeldrop
regex:
- (pod|service|endpoint|namespace)
scheme: http
scrapeTimeout: 30s
jobLabel: app.kubernetes.io/name
selector:
matchLabels:
app.kubernetes.io/component: exporter
app.kubernetes.io/name: kube-state-metrics
该配置文件生成的vmagent配置如下
- job_name: serviceScrape/kube-system/kube-state-metrics/0
scrape_interval: 30s
scrape_timeout: 30s
scheme: http
relabel_configs:
- action: keep
source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_component]
regex: exporter
- action: keep
source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name]
regex: kube-state-metrics
- action: keep
source_labels: [__meta_kubernetes_endpoint_port_name]
regex: http-metrics
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: node
regex: Node;(.*)
replacement: ${1}
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: pod
regex: Pod;(.*)
replacement: ${1}
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
- source_labels: [__meta_kubernetes_pod_container_name]
target_label: container
- source_labels: [__meta_kubernetes_namespace]
target_label: namespace
- source_labels: [__meta_kubernetes_service_name]
target_label: service
- source_labels: [__meta_kubernetes_service_name]
target_label: job
replacement: ${1}
- source_labels: [__meta_kubernetes_service_label_app_kubernetes_io_name]
target_label: job
regex: (.+)
replacement: ${1}
- target_label: endpoint
replacement: http-metrics
- action: labeldrop
regex: (pod|service|endpoint|namespace)
metric_relabel_configs:
- action: drop
source_labels: [__name__]
regex:
- kube_endpoint_address_not_ready
- kube_endpoint_address_available
kubernetes_sd_configs:
- role: endpoints
namespaces:
own_namespace: false
names:
- kube-system
在通过target-relabel-debug 页面分析数据采集处理过程中发现如下配置:
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: pod
regex: Pod;(.*)
replacement: ${1}
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
这里对Pod进行了2次操作分别如下:
两次操作
第一次操作
- source_labels: [__meta_kubernetes_endpoint_address_target_kind, __meta_kubernetes_endpoint_address_target_name]
separator: ;
target_label: pod
regex: Pod;(.*)
replacement: ${1}
- 目标:从 Endpoint 对象中提取 Pod 名称,仅当目标类型是 Pod 时生效。
- 适用场景:通过 Kubernetes Endpoint 发现的 Pod(如 Service 后端的 Pod)。
第二次操作
- source_labels: [__meta_kubernetes_pod_name]
target_label: pod
- 目标:直接从 Pod 元数据中获取名称,覆盖或补充第一次操作的结果。
- 适用场景:直接发现的 Pod(如通过
role: pod的服务发现)或第一次操作未匹配的情况。
为什么需要两次操作?
1. 覆盖不同的服务发现场景
Kubernetes 服务发现有多种方式:
-
通过 Endpoint 发现(如
role: endpoints):
元数据包含__meta_kubernetes_endpoint_address_target_kind和__meta_kubernetes_endpoint_address_target_name,但不保证所有 Endpoint 都指向 Pod(可能是 Node 或 ExternalName)。 -
直接发现 Pod(如
role: pod):
元数据包含__meta_kubernetes_pod_name,但没有上述 Endpoint 相关标签。
两次操作结合,可以确保无论使用哪种服务发现方式,都能获取到 Pod 名称。
2. 处理特殊情况
-
Endpoint 指向非 Pod 目标:
若 Endpoint 指向 Node 或其他资源,第一次操作会失败(正则不匹配),此时第二次操作可从 Pod 自身的元数据中获取名称。 -
标签优先级控制:
第二次操作会覆盖第一次的结果,确保使用 Pod 自身的精确名称而非 Endpoint 关联的名称(两者通常相同,但在特殊配置下可能不同)。
示例场景
场景1:通过 Service 发现 Pod
- 服务发现返回:
__meta_kubernetes_endpoint_address_target_kind=Pod__meta_kubernetes_endpoint_address_target_name=nginx-123__meta_kubernetes_pod_name=nginx-123
- 第一次操作:提取
pod=nginx-123。 - 第二次操作:覆盖
pod=nginx-123(值相同,无实际影响)。
场景2:直接发现 Pod
- 服务发现返回:
__meta_kubernetes_endpoint_address_target_kind=Node(假设)__meta_kubernetes_endpoint_address_target_name=node-1__meta_kubernetes_pod_name=nginx-123
- 第一次操作:正则不匹配,
pod标签未设置。 - 第二次操作:设置
pod=nginx-123。
最佳实践建议
-
保持操作顺序:
先通过 Endpoint 元数据提取(第一次操作),再通过 Pod 自身元数据补充(第二次操作)。 -
添加防御性标签:
可在两次操作后添加默认值,确保标签始终存在:- target_label: pod replacement: unknown # 若前面操作都失败,设置为 unknown -
结合其他标签:
通常还会同时提取namespace、service等标签,形成完整的标识体系:- source_labels: [__meta_kubernetes_namespace] target_label: namespace - source_labels: [__meta_kubernetes_service_name] target_label: service
这种看似冗余的配置实际上是一种 健壮性设计,确保在复杂的 Kubernetes 环境中,无论 Pod 以何种方式被发现,都能正确获取和设置关键标签。
在 relabeling 配置中,连续对同一个标签(如 pod)进行操作 是一种常见的 防御性编程策略,用于确保在各种场景下都能正确获取标签值。
那么问题来了,关于node的匹配为什么只有一次呢?
更多推荐



所有评论(0)