news 2026/9/11 9:14:28

kube-state-metrics自定义标签暴露指南:allowlist与relabel配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
kube-state-metrics自定义标签暴露指南:allowlist与relabel配置

1. 问题现象:Node 上明明有 rack、dc 标签,Prometheus 指标里却查不到

1.1 一次失败的按机柜聚合

有段时间我在做告警治理,想把节点故障告警按物理机柜维度聚合,这样值班同学一眼就能看出是哪一排机柜的网络或电源出了问题。集群里的 Node 对象上很早就打了rackdc标签,Kubernetes 本身管理这些标签没有任何问题。于是在 Prometheus 里我写了一条很常规的查询:

count by (rack) (kube_node_info)

结果让我很意外:rack这个维度根本不存在,查询结果里都是空字符串或者直接没有这个标签。当时第一反应是采集配置出了问题,检查了 Prometheus 的 service monitor、抓取任务、relabel 规则,都没毛病。最后才把矛头指向 Prometheus 生态里负责暴露 Kubernetes 对象状态的组件——kube-state-metrics。它默认并不会把我们在 Kubernetes 对象上自定义的标签直接放到指标里。

这就是这篇文章要解决的典型场景:怎么让 kube-state-metrics 把额外的资源标签注入到指标中。

1.2 kube-state-metrics 默认"不带你自定义标签"的设计逻辑

先明确一个容易混淆的概念。我们常说的 Prometheus 监控体系里有两个职责完全不同的抓取目标:

  • node-exporter 负责暴露节点的机器指标,比如 CPU、内存、磁盘;
  • kube-state-metrics(下文简称 KSM)负责监听 Kubernetes API Server,把 Deployment、Pod、Node、Namespace 等对象的状态翻译成指标。

KSM 的核心工作是"对象状态 → 指标"的转换。比如kube_node_info这个指标,它表示 Node 对象的基础信息,指标上默认带的是 Node 的名称、UID、内核版本、容器运行时版本等。而你在 Node metadata 里打的rackdc这类自定义标签,属于业务自定义元数据,KSM 认为不是每个集群都需要暴露,所以默认情况下不会把它们作为指标标签输出。

这不是 KSM 偷懒,而是有意为之。Kubernetes 对象上的 label 可以非常灵活,团队可以随手打created-byownercost-centerfeature-flag等各种键值。如果 KSM 把所有 label 都直接变成指标标签,series 数量会随着 label 的取值组合迅速膨胀。Prometheus 的存储和查询对高基数非常敏感,一个取值不断变化的 label 足以把一个单机实例的查询拖垮。KSM 于是选择了一种更稳妥的策略:默认只暴露 name、namespace、uid 等跟对象身份强相关的固定标签,自定义标签必须通过白名单显式开启。

1.3 KSM 的标签来源:内置字段与白名单提取

KSM 里的指标标签主要来自三类来源:

  • 对象内置字段metadata.namemetadata.namespacemetadata.uid这类对象本身就有的信息,直接作为指标的基础标签。
  • allowlist 白名单提取:通过启动参数把metadata.labels里指定的 key 提取出来,附加到对应资源的指标上。
  • 模板生成标签:某些资源类型会额外生成与对象属性相关的标签,比如 Deployment 指标上的deployment标签、Namespace 指标上的namespace标签。

这里说的"加入额外资源标签",指的就是第二类:用启动参数把metadata.labels中我们关心的 key 加入指标。

需要特别提醒的是:KSM 只负责暴露 label,不做 Prometheus relabel 的操作。你要加的标签必须已经在 Kubernetes 对象的 labels 上存在,KSM 才有东西可提取。如果 Node 上根本没打rack标签,那不管 KSM 参数怎么配,指标里都不会凭空出现这个标签。

2. 参数选型:--metric-labels-allowlist、--labels-allowlist 到底用哪个

2.1 版本分水岭:v2.0 前后的参数变化

在 KSM 的 v2.0 版本之前,暴露自定义标签的参数叫--labels-allowlist,用法类似:

--labels-allowlist=pods=[team,env],nodes=[rack,dc]

但到了 v2.0,官方把参数改成了--metric-labels-allowlist,语义更明确:只影响指标 labels 的提取,和 annotations 的处理区分开。与此同时,--metric-annotations-allowlist也被加入,用于暴露对象的 annotations。

如果你还在用 v2.0 之前的版本,写--labels-allowlist没问题;如果你已经升级到 v2.0+,建议使用新参数名。旧参数在新版本里未必会报错,但不同小版本的表现不完全一致,有的会打 warning,有的可能被忽略。最稳妥的方式是:部署前先执行kube-state-metrics --help看当前版本到底支持哪个参数。

我见过不少升级后配置"静默失效"的案例:集群从 v1.x 升到 v2.x,部署 manifest 没跟着改,结果自定义标签全没了,告警规则和 Grafana 面板一片红。这个排查过程很折腾,因为 Prometheus 抓取是正常的,指标都在,就是少了几个 label。所以升级 KSM 后,除了看 Pod 启动日志,第一件事就是确认参数名跟上了版本。

2.2 白名单语法格式和资源作用域

参数语法格式是resource=[label1,label2,...],多个资源类型之间用逗号分隔。例如:

--metric-labels-allowlist=nodes=[rack,dc],pods=[team,environment,app.kubernetes.io/name],namespaces=[team]

这段配置的含义是:

  • Node 对象上的rackdc标签会出现在 KSM 的 Node 相关指标上;
  • Pod 对象上的teamenvironmentapp.kubernetes.io/name标签会出现在 Pod 相关指标上;
  • Namespace 对象上的team标签会出现在 Namespace 相关指标上。

需要注意两点。

第一,app.kubernetes.io/name这种带斜杠的 label key 在指标里不会原样保留。Prometheus 的 label name 只允许[a-zA-Z_][a-zA-Z0-9_]*,所以 KSM 会把app.kubernetes.io/name转成app_kubernetes_io_name。后面第五章我会再展开讲。

第二,资源类型前缀是可选的。如果只想对所有资源类型统一开启某个标签,可以用空资源名加通配符的写法,但这有基数风险,建议谨慎。

KSM 支持这种白名单的资源类型比较多,我列几个实际常用的:

资源类型典型用途
nodes机柜、机房、地域、硬件规格
pods业务团队、环境、应用名
namespaces负责人、成本中心、环境
deployments发布平台、Git 仓库路径
services网关、域名、流量入口分类
persistentvolumeclaims存储类型、备份策略
statefulsets / daemonsets中间件集群、节点组件分类

2.3 用 [*] 通配前,先把基数账算清楚

--metric-labels-allowlist=[*]--metric-labels-allowlist=pods=[*]表示把所有自定义 label 都暴露出来。从功能上看这确实省事,不用一个个列 label 名字了,但在生产环境我很不建议这么干。

基数的膨胀往往不是"一次性爆炸",而是慢慢腐蚀。举个例子:假如集群里有 2000 个 Pod,其中一部分带有app.kubernetes.io/revision这种每次发布都会变化的 label,当你允许 Pod 的所有 label 暴露后,kube_pod_container_status_restarts_total这类指标就会按照每个 Pod × 每个修订版本生成多个 series。Prometheus 对这种组合爆炸的容忍度很低,一旦触发高基数告警,查询性能会明显下降,存储占用也会快速上升。

我建议的做法是:白名单只放真正在查询、告警、Grafana 面板里用得到的 label。新增 label 前先问一句:这个维度有没有对应的聚合场景?如果答不上来,就不加。

3. 实操:为 Node、Pod、Namespace 添加额外资源标签

3.1 直接修改 KSM Deployment:以 YAML 为例

如果你的 kube-state-metrics 是直接用 manifest 部署的,修改方式很简单:编辑 Deployment,在容器的 args 里加上--metric-labels-allowlist。先确认当前 deployment:

kubectl -n monitoring get deploy kube-state-metrics -o yaml

找到spec.template.spec.containers[0].args,加入参数。例如:

spec: template: spec: containers: - name: kube-state-metrics args: - --port=8080 - --metric-labels-allowlist=nodes=[rack,dc] - --metric-labels-allowlist=pods=[team,environment,app.kubernetes.io/name] - --metric-labels-allowlist=namespaces=[team]

这里我用了多个--metric-labels-allowlist参数,每个参数只针对一个资源类型,可读性更好。实际使用中也可以合并到一个参数内,用逗号分隔不同资源类型,效果一样。

改完后 apply,KSM Pod 会滚动重启。要确认参数确实生效,可以看一眼运行中的 Pod 启动命令:

kubectl -n monitoring get pod -l app.kubernetes.io/name=kube-state-metrics -o jsonpath='{.items[0].spec.containers[0].args}'

3.2 通过 kube-prometheus-stack 的 values.yaml 配置

如果 KSM 是通过 Helm 安装的,我优先推荐在 values.yaml 里配置,而不是直接改 Deployment。因为直接改 Deployment 在下次helm upgrade时会被覆盖,配置就丢了。

在 kube-prometheus-stack 里,配置通常长这样:

kube-state-metrics: metricLabelsAllowlist: - nodes=[rack,dc] - pods=[team,environment,app.kubernetes.io/name] - namespaces=[team]

这里有个小坑:不同版本的 kube-prometheus-stack / prometheus-community chart,字段名不完全一样。有的版本用metricLabelsAllowlist,旧一点的可能用labelsAllowlist,还有一些版本倾向于直接传extraArgs。最靠谱的方法是先看当前 chart 的默认 values:

helm show values prometheus-community/kube-prometheus-stack | grep -B2 -A5 -i allowlist

确认字段名后再写,避免 chart 渲染时把你的配置悄悄忽略掉。

如果你用的是独立的 kube-state-metrics chart,values 里的写法可能更接近:

kube-state-metrics: extraArgs: - --metric-labels-allowlist=nodes=[rack,dc] - --metric-labels-allowlist=pods=[team,environment]

3.3 验证标签是否生效:Prometheus UI 与命令行双管齐下

参数加完后别急着去 Grafana 看面板,先在 Prometheus UI 的 Graph 页面验证一下。以 Node 为例,执行这条查询:

kube_node_info

结果里应该能直接看到rackdc两个标签。如果看到rack=""或者干脆没有这个标签,可能的原因有三个:

  • Node 对象上本身没有打这个 label;
  • KSM 参数里的资源类型写错了,比如给 nodes 写的白名单是rack,但参数被写到了--metric-labels-allowlist=namespaces=[rack]
  • KSM 版本参数名不兼容,参数没被解析成功。

还有一种验证方式,直接看 KSM 暴露的 metrics 端点,搜索某个具体指标:

curl -s http://<ksm-service-address>:8080/metrics | grep '^kube_node_info' | head -5

这能看到最新样本的完整 label set,非常直观。

3.4 在 Grafana 里按新标签聚合的效果

配置生效后,我们再把文章开头那条查询拉出来:

count by (rack) (kube_node_info)

现在结果就正常了:每个机柜标识对应一个节点数量。后续做故障聚合、成本分摊、容量规划都方便了。把这套标签和告警规则结合的例子也很常见:

count by (rack) (kube_node_status_condition{condition="Ready",status="true"} == 0)

这条规则可以统计每个机柜里不健康的节点数量,配合告警路由,就能把问题定位精确到机柜,而不是让值班同学在一堆 IP 里猜。

4. 不重启 KSM 的备选方案:用 metric_relabel_configs 从 kube_pod_labels 提取标签

4.1 为什么很多老集群选 relabel 而不是 allowlist

除了 KSM 白名单,还有一个老办法:在 Prometheus 的抓取配置里用metric_relabel_configs对 KSM 暴露的label_系列标签做提取。

KSM 默认会生成几个专门的指标来展示对象的 label,比如kube_pod_labelskube_node_labelskube_namespace_labels。这些指标本身带着label_<key>格式的标签,例如:

kube_node_labels{node="node-01", label_rack="rack-a1", label_dc="dc-sh"}

很多老集群不愿意动 KSM 部署,或者 KSM 版本太旧不支持 allowlist,就会在 Prometheus 抓取时把label_前缀的标签改写成普通标签。这样做的好处是不用重启 KSM,纯 Prometheus 配置层面就能解决。

4.2 labelmap + 正则提取label_前缀标签

在 Prometheus 的scrape_configs里,针对 kube-state-metrics 这个 job 加一段metric_relabel_configs

scrape_configs: - job_name: kube-state-metrics honor_timestamps: true static_configs: - targets: ["kube-state-metrics.monitoring:8080"] metric_relabel_configs: - action: labelmap regex: label_(.+) replacement: $1

labelmap动作的含义是:凡是标签名匹配正则的,都用 replacement 重新生成一个标签。label_rack会变成racklabel_dc会变成dc。全部在采集阶段完成,KSM 不需要做任何改动。

这个方案在生产上确实是可行的,我见过不少大集群就是这么干的。但要注意副作用:该 job 下所有以label_开头的标签都会被重命名,如果有些 label 本身就以label_开头,可能出现覆盖或重复。而且 relabel 后的标签和原始label_xxx同时存在,可能让指标体积变大。

4.3 两种方案的边界:什么时候该用哪种

allowlist 和 relabel 不是互斥的,选择哪种要看具体场景。

对比维度KSM allowlistmetric_relabel_configs
配置位置KSM Deployment 或 Helm valuesPrometheus 抓取配置
生效方式KSM Pod 重启Prometheus 热加载
影响范围只影响 allowlist 指定的资源指标整个 job 下所有指标
灵活性高,可精确指定资源类型和 label较低,按标签名前缀批量处理
维护成本需要升级/重启 KSM只改配置,但不直观

我的建议是:如果你的 KSM 版本支持--metric-labels-allowlist,优先用它,因为它能精确控制"哪些资源类型暴露哪些 label",语义清晰,出问题的概率低。只有当你没法轻易重启 KSM、或者集群有特殊的全局标签提取需求时,再考虑metric_relabel_configs

5. 几个容易翻车的联动问题:HPA、跨集群采集与 label 名改写

5.1 HPA 配合 KSM 指标时,自定义标签要注意什么

很多团队会用 Prometheus Adapter 把 KSM 的指标暴露给 HorizontalPodAutoscaler 使用,比如根据kube_pod_container_status_restarts_totalkube_deployment_status_replicas做扩缩容。这时候你可能会担心:新加的自定义标签会不会影响 HPA?

直接回答:如果指标标签集里加入了新 label,HPA 本身不会被"撑爆",但 Prometheus Adapter 的metricsQueryseriesQuery配置里,可能会因为查询条件变了导致匹配不到指标。举个例子,Adapter 默认按namespacepod做资源关联,这不会受自定义标签影响;但如果你的 Adapter 配置里用labelSelector过滤了某些对象,而过滤条件依赖的 label 又被 allowlist 改变了命名(比如斜杠变下划线),就会匹配不上。

另外,如果你在 HPA 里使用的是"针对某个 Deployment 副本数"的 custom metric,指标中新增的自定义标签不会破坏现有的匹配关系,因为 HPA 关联的是被评估对象的 name,而不是某个业务标签。真正的风险点在于:你想按新标签拆分告警或扩容策略,但 Prometheus Adapter 的metricsQuery没有把新标签保留在返回结果里。这个不是 KSM 的问题,是 Adapter 层的聚合逻辑问题,需要检查metricsQuery中是否有group by或聚合操作把自定义 label 丢掉了。

5.2 跨集群采集时的标签冲突与区分

如果你的公司有多个 Kubernetes 集群,监控数据统一汇总到一套 Prometheus 或 Thanos / VictoriaMetrics 里,那么 Node 名称、Pod 名称、甚至 Namespace 名称都可能是重复的。此时如果只依赖 KSM 的自定义标签做区分,远远不够,因为跨集群的指标合流时,不同集群的同类对象会互相覆盖。

我比较推荐的做法是:在采集阶段用relabel_configs给每个集群打一个全局静态标签,比如cluster

scrape_configs: - job_name: kube-state-metrics static_configs: - targets: ["<cluster-a-ksm>:8080"] labels: cluster: cluster-a

这个cluster标签和 KSM allowlist 提取的标签是不同来源的:一个来自抓取任务配置,一个来自对象元数据。两者配合使用,才能回答"哪个集群的哪个节点、在哪个机柜"这样的问题。

5.3 特殊字符去哪了:allowlist 对 label key 的规范化规则

Kubernetes label key 允许出现的字符比 Prometheus label name 宽松得多。app.kubernetes.io/nameexample.com/teammy-label这些在 Kubernetes 里都是合法的,但 Prometheus 的 label name 只允许[a-zA-Z_][a-zA-Z0-9_]*,斜杠和短横线都不能出现。

KSM 在做 label 提取时,会对非法的字符做替换:斜杠、点、短横线一律替换成下划线。所以你写在 allowlist 里的 key 是app.kubernetes.io/name,最后在指标上看到的标签名大概率是app_kubernetes_io_name

这个改写在kube_pod_labels指标的label_系列里同样存在,比如:

kube_pod_labels{label_app_kubernetes_io_name="order-service"}

所以配置告警规则或 Grafana 时,不要想当然地写成原始的 label key,先去 Prometheus UI 里搜一下实际标签名再写表达式。这个坑很多人踩过,包括我自己,一次告警规则里写错标签名,结果静默了半个月才发现。

6. 生产环境落地建议:五条让我躲过坑的经验

6.1 白名单字段必须走评审流程

给 KSM 加一个 label 看起来只是改一行参数,但它影响的是整条 Prometheus 数据链路的基数。我建议在团队内部定一个简单规矩:所有新增到 allowlist 的标签,必须说明使用场景和预期基数。没有聚合场景的标签,不允许加。这样可以从源头控制 series 数增长。

6.2 把标签命名规范写进团队约定

Kubernetes 对象的 label key 最好尽量使用不带斜杠的后缀部分作为 Prometheus 里的最终标签名,或者反过来,提前约定所有要暴露到监控系统的 label key 都使用[a-zA-Z0-9_]以内的字符。比如用rack,不用example.com/rack。这样可以减少 KSM 转换带来的标签名歧义,也方便告警模板和面板变量复用。

6.3 用告警和 recording rule 监控 series 增长

我对每个 Prometheus 实例都会配置一条针对 series 数量的观察型查询:

sum(scrape_series_added) by (job)

同时关注kube_state_metrics自身的tsdb_head_seriesprometheus_tsdb_head_series。一旦发现新增 label 后 series 数异常上升,能第一时间感知,而不是等到查询变慢才去排查。

6.4 需要剔除指标时保留一副"切除工具"

allowlist 只负责"加",如果某个 label 或指标不需要了,你得会"减"。KSM 暴露的指标本身全量很大,有些公司会用--metric-denylist一类参数排除不需要的高基数指标。保留这些参数配置,在出现基数问题时能快速止血。不要只盯着增加标签这一个维度,删掉无用的内置标签同样是控制资源消耗的手段。

6.5 文档化你的 allowlist 配置

最后一条看起来像废话,但实际能救很多人。把每个集群的 KSM 参数记录下来,包括资源类型、暴露的 label、用途、负责人。下次谁要改配置,先看文档,再改代码,然后验证。我的经验是,监控系统的绝大多数线上事故都来自"无人知道这条配置为什么存在"的隐性维护债。

如果你正在经历"Kubernetes 对象标签在 Prometheus 里不可见"的问题,照着前面的配置加一下 allowlist,再验证一遍标签是否出现在目标指标上,基本就能解决。配置通常只要几分钟,但省下来的排查时间,可能是好几天。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/11 9:13:10

中小企业做网站怕花冤枉钱?过来人整理的高性价比开发方清单

很多中小企业、初创团队在搭建官网时&#xff0c;都会陷入同一个困境&#xff1a;传统定制建站报价动辄数千元甚至上万元&#xff0c;开发周期长、后期维护成本高&#xff0c;而低价建站工具又容易出现功能残缺、收录差、售后无保障等问题。多数企业每年花在网站搭建、改版、运…

作者头像 李华
网站建设 2026/9/11 9:08:43

DeepSeek Harness本地评测实战:从零安装到跑通代码生成任务

"赶个晚集"这四个字&#xff0c;说的就是我。DeepSeek Harness 在圈子里其实已经讨论过一阵了&#xff0c;Codex Harness 那边带起来的评测框架热度还没退&#xff0c;DeepSeek 也顺势有了自己的 harness 方向。我一直拖着没动&#xff0c;手里的项目一个接一个&…

作者头像 李华
网站建设 2026/9/11 9:08:37

GitHub热门开源项目盘点:AI模型优化与低代码工具

1. 近期GitHub热门开源项目盘点最近在开发者社区中&#xff0c;有四个GitHub开源项目引发了广泛讨论。这些项目覆盖了从开发工具到AI模型的不同领域&#xff0c;每个都解决了特定场景下的痛点需求。作为长期关注开源生态的技术从业者&#xff0c;我整理了这些项目的核心价值、技…

作者头像 李华
网站建设 2026/9/11 9:07:54

配电网N-1扩展规划Matlab实现:从校验到优化决策

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/11 9:07:22

【滚雪球学数学建模】第19.1节·排队论与随机服务系统!

🎓 本文收录于《滚雪球学数学建模》系列专栏 数学建模真正的难点,往往不在于掌握某一个公式或算法,而在于面对实际问题时,能否完成从 问题分析 → 模型构建 → 算法求解 → 结果验证 → 论文表达 的完整闭环。 本专栏正是围绕这一目标打造:从零基础出发,通过“滚雪球式”…

作者头像 李华
网站建设 2026/9/11 9:07:00

Fluent与EDEM耦合模拟颗粒-流体传热过程

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华