尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Kube State Metrics 如何添加自定义资源标签:从配置到PromQL查询实战

Kube State Metrics 如何添加自定义资源标签:从配置到PromQL查询实战 做过 Kubernetes 监控的人应该都有印象Prometheus 加 kube-state-metrics下面直接叫 KSM这套组合能把 Deployment、Pod、Namespace 这些 API 对象“翻译”成可以查询的指标。可一旦集群规模上来或者要在多集群、多团队环境里做成本拆分、告警分组KSM 默认产出的那几个标签根本不够用。你想按团队、环境、业务域去聚合就得往指标里额外塞标签而KSM偏偏默认不带你自定义的那些 metadata.labels。这篇文章就专门拆这个需求——如何在 KSM 中加入额外的资源标签。我会从最简单的启动参数讲起把 Helm 场景、验证方法、PromQL 使用姿势、还有几个高频踩坑点全部过一遍。适合正在维护 Kubernetes 监控体系、又不想靠人工打补丁的运维和 SRE 朋友参考。1. 先搞清楚KSM 的标签到底从哪来1.1 KSM 默认会带哪些标签KSM 的本质是监听 Kubernetes API Server把各类资源对象的状态转换成类似kube_pod_info、kube_deployment_status_replicas、kube_node_status_allocatable这样的指标。每个指标都会带上这个资源的内置标识字段但对不同资源来说内置标签就那几个资源对象默认标签示例Podnamespace、podkube_pod_info{namespaceprod,podapi-abc}Deploymentnamespace、deploymentkube_deployment_status_replicas{namespaceprod,deploymentapi}Namespacenamespacekube_namespace_status_phase{namespaceprod}Nodenodekube_node_status_capacity{nodenode-01}Servicenamespace、servicekube_service_info{namespaceprod,serviceapi}这里需要特别理解一点KSM 所谓“默认标签”是你创建资源时 Kubernetes 系统自动填充的字段比如 Pod 的pod标签实际上就是 Pod 名字。但你在 Deployment 或 Pod 的 YAML 里自定义的那些labels比如app: api、team: backend、env: prod默认情况下不会出现在 KSM 指标上。我第一次用 KSM 的时候也踩过这个认知坑以为在对象上打了team标签指标里就该有teambackend结果查出来的全是namespace和pod找不到任何一个自定义标签。原因很简单KSM 为了控制基数和出参稳定性默认只输出基础信息额外的标签必须显式开启。1.2 额外资源标签能从哪里来在 KSM 的体系里能用的“额外标签”主要来自三个地方metadata.labels资源对象上的标签最常用的来源。一般放app、env、team、version这类低频变化的标识。metadata.annotations注释信息比 labels 更自由适合放owner、slack-channel、cost-center这类不适合放进查询维度的信息。资源自身的 spec/status 字段比如从kube_pod_labels这类指标里间接拿到的字段但能直接用--metric-labels-allowlist控制的通常就是 labels 和 annotations 两类。理解了来源后面所有配置就都围绕“如何把 metadata.labels 或 metadata.annotations 中的值放到指标标签上”展开。2. 加标签的两条路线别再傻傻改采集器2.1 路线一KSM 原生 allowlistKSM 自己提供了两个启动参数--metric-labels-allowlist和--metric-annotations-allowlist。前者把资源对象的 labels 附加到对应的指标上后者处理 annotations。这是官方推荐的做法也是这篇文章的重点。它的语法是按资源类型分组格式是--metric-labels-allowlistresource/[label1,label2],resource2/[labelA]比如我想让 Pod 相关的所有 KSM 指标带上app、env、team三个标签同时让 Deployment 指标也带上同样三个标签配置就是--metric-labels-allowlistpods[app,env,team],deployments[app,env,team]需要注意的是这个 flag 是按资源对象作用的。你声明了pods[team]只有 Pod 资源产生的指标会多出teamDeployment 的指标不会自动继承想加就必须单独写deployments[team]。2.2 路线二Prometheus relabel 从服务发现里加另一条路线是完全绕开 KSM在 Prometheus 的 scrape 配置里通过 relabel 规则把采集目标自身的标签写入指标。常见写法是把 Kubernetes service discovery 的元数据标签批量水平展开relabel_configs: - action: labelmap regex: __meta_kubernetes_pod_label_(.)这条路看着简单但有个大坑它拿到的是采集目标 Pod 自己的标签而不是被监控对象的标签。也就是说如果你给 KSM 这个 job 加了这条规则加出来的标签来自 KSM 自己的 Pod跟你集群里几百个业务 Deployment 的team标签一点关系都没有。所以结论很明确你要给 KSM 指标加的标签是每个被监控资源对象上的标签必须走 KSM 的 allowlist。relabel 只在少数场景下适合比如给整个集群的指标统一加一个cluster或env这样的公共标签。2.3 两条路线怎么选维度KSM allowlistPrometheus relabel标签来源资源对象的 metadata.labels/annotations采集目标自身的标签支持按标签值过滤不支持全部附加到该资源所有指标可以按 regex 选择维护位置KSM 启动参数/Helm valuesPrometheus scrape_config是否随资源动态变化是是推荐场景给 KSM 指标补充业务维度标签给所有指标加集群级公共标签我自己在实际项目中基本只用 allowlistrelabel 只用来做集群维度的公共标签或者处理云厂商自带标签。3. 实操用 --metric-labels-allowlist 加入资源标签3.1 裸部署怎么配如果你是直接用 Deployment 清单部署 KSM修改方法是给 Pod 里面的容器加启动参数。下面是一个常见的例子containers: - name: kube-state-metrics image: registry.k8s.io/kube-state-metrics/kube-state-metrics:v2.10.0 args: - --metric-labels-allowlistpods[app,env,team],deployments[app,env,team],namespaces[team]改完应用清单再滚动重启让参数生效kubectl -n kube-system rollout restart deployment/kube-state-metrics这里有个容易出错的地方如果你用的是 KSM v1.x参数名是--labels-allowlist不是--metric-labels-allowlist。KSM v2.x 才改成了metric-前缀。所以升级 KSM 版本之后旧的启动参数会直接不生效而且不一定会在日志里报错这个后面排查部分会细说。3.2 Helm 和 kube-prometheus-stack 怎么配用 Helm 部署的话绝大多数情况你是在维护kube-prometheus-stack或者独立的kube-state-metricschart。以最常见的 kube-prometheus-stack 为例values.yaml 里已经有现成的字段kube-state-metrics: metricLabelsAllowlist: - pods[app,env,team] - deployments[app,env,team] - namespaces[team] metricAnnotationsAllowlist: - pods[owner,slack-channel]如果你用的是独立的 kube-state-metrics chart结构几乎一样metricLabelsAllowlist: - pods[app,env,team] - deployments[app,env,team]改完执行升级helm upgrade --install -n kube-system kube-state-metrics prometheus-community/kube-state-metrics -f values.yaml如果你要临时验证、又不想改动 values 文件也可以直接通过命令行覆盖helm upgrade --install -n kube-system kube-state-metrics prometheus-community/kube-state-metrics \ --set metricLabelsAllowlist[0]pods[app,env,team] \ --set metricLabelsAllowlist[1]deployments[app,env,team]3.3 怎么验证真的生效了改完参数之后验证分两步。第一步确认 Pod 的启动参数确实带上了kubectl -n kube-system get deploy kube-state-metrics -o yaml | grep -A3 args:第二步直接看指标输出确认新标签出现在目标指标上。我习惯用 port-forward 加 curlkubectl -n kube-system port-forward deploy/kube-state-metrics 8081:8080 curl -s http://127.0.0.1:8081/metrics | grep ^kube_pod_info{ | head -5正常的情况下你会看到类似这样的输出kube_pod_info{namespaceprod,podapi-abc-123,label_appapi,label_envprod,label_teambackend} 1注意看那个label_前缀。这是 KSM 的规则从资源对象上附加进来的标签都会以label_key的形式出现在指标上而不是直接叫app、team。这个设计是为了避免和指标自带标签冲突。理解了这一点后面写 PromQL 时就不会一脸懵了。3.4 annotations 怎么加labels 之外annotations 的用法几乎一样只是参数名换成--metric-annotations-allowlist--metric-annotations-allowlistpods[owner,slack-channel]加了之后Pod 相关的 KSM 指标上会出现annotation_owner、annotation_slack_channel这样的标签同样带annotation_前缀。我通常把 labels 留给查询聚合维度把 annotations 留给告警路由和通知信息避免所有标签一股脑全塞进去导致指标够腻。4. 标签进来之后PromQL 和 Grafana 怎么用4.1 直接按新标签查询新标签生效后PromQL 里直接用就行。比如按团队聚合 CPU 请求量sum( kube_pod_container_resource_requests{resourcecpu, label_team!} ) by (label_team)再比如按环境看某个 Deployment 的副本数kube_deployment_status_replicas{label_envprod}这里最关键的习惯是只要是在 KSM 指标里查自定义标签就要记住label_前缀。尤其是从别人交接的 Grafana 面板里看到team、env这种查询条件却查不到数据时先别怀疑数据采集出了问题多半是忘加前缀。4.2 通过 kube_pod_labels 做跨资源 Join有人会问我只给 Deployment 加了team标签能用它去查 Pod 指标吗答案是不行除非你在配置里同样给pods[team]才行。但有一个变通方案适合那些不方便改 KSM 参数、只能在查询端解决问题的场景。KSM 有一个特殊指标叫kube_pod_labels它专门用来承载 Pod 的标签信息。只要 KSM 版本和配置允许它输出你就可以把它和 Pod 容器指标做 PromQL join。典型写法是这样kube_pod_container_resource_requests{resourcecpu} * on (namespace, pod) group_left(label_team) (kube_pod_labels{label_team!} 1)这里 1是为了拿kube_pod_labels这个值为 1 的序列去做匹配group_left(label_team)把标签维度补充到左侧指标上。缺点是查询性能会比直接查带标签的指标差一些适合临时性分析不适合高频告警和大型看板。如果你的team标签是打在 Namespace 上的想做 namespace 到 pod 的关联也可以换成kube_namespace_labels做 join。整体思路一样只是匹配键从namespace,pod缩小成namespace。4.3 在 Grafana 里做变量和分组加标签最大的收益其实是 Grafana 看板可以做动态变量。比如你要做一个“按团队过滤”的下拉框变量查询可以写成label_values(kube_pod_info, label_team)这样团队列表会自动从指标里拉取不用手工维护一堆静态变量。面板分组也可以直接用sum( rate(container_network_receive_bytes_total{jobkubelet, namespace~$namespace}[5m]) ) by (label_team)注意容器网络指标来自 kubelet 的 cAdvisor而不是 KSM。如果你在 cAdvisor 指标里也想要label_team单纯在 KSM 里加 allowlist 是不够的得靠 Prometheus relabel 从 service discovery 元数据里补或者通过 recording rule 处理。这一点很多人会在混搭查询时踩坑。5. 容易踩的坑与排查实录5.1 明明配置了指标里还是没有新标签这是我见过最多的情况排查顺序基本是固定的。第一先确认参数真的写进了进程kubectl exec进容器里执行ps aux | grep kube-state看一下实际进程参数。第二确认参数名和 KSM 版本匹配v1.x 用--labels-allowlistv2.x 用--metric-labels-allowlist。第三确认目标资源上确实存在这个 label如果整个集群没有任何 Pod 带team这个 key那指标里自然也不会出现label_team。第四确认 prometheus 的 relabel 没有把label_*开头的标签给干掉了很多团队为了瘦身会在metric_relabel_configs里写labeldrop不小心就把 KSM 的label_前缀标签全删了。5.2 带点号和斜杠的标签键变成下划线了Kubernetes 推荐标签里经常能看到类似app.kubernetes.io/name这种带点号、带斜杠的 key。但 Prometheus 的标签名只允许字母、数字和下划线所以 KSM 会自动把点号和斜杠替换成下划线。在 allowlist 里你照抄原始 key 就行--metric-labels-allowlistpods[app.kubernetes.io/name]出来的指标标签却是label_app_kubernetes_io_namemyapp坑就在这写 PromQL 或 Grafana 变量时很容易下意识写成label_app.kubernetes.io_name结果匹配不上。解决办法是先在 curl 输出里确认实际 label 名再拿去写查询。5.3 不要把高基数标签加进去这是我要重点强调的一点。allowlist 加的标签会同时出现在该资源所有指标上。如果一个标签取值特别多比如 Pod UID、Deployment 的 revision、或者每天都变的构建号、commit 号那么 KSM 产生的每个时间序列都会被直接乘以这个基数。举一个我踩过的真实例子某团队为了让指标带上version把每次发版的镜像 tag 写进了 Pod labels然后 allowlist 里加了pods[version]。版本一多KSM 指标序列数量暴涨Prometheus 内存从 8GB 一路涨到 22GB查询变慢最后只能被迫回滚配置。建议是把version、commit_sha这类高频变化的标签放进 annotations 或者日志系统而不是放 labels也不要用 allowlist 全部暴露。需要保留就限制在kube_pod_labels这种单独的指标上通过 PromQL join 按需取用能显著降低基数冲击。5.4 想改标签名怎么办KSM 给你的标签都带label_或annotation_前缀有些团队嫌丑想统一改成业务自己习惯的名字。这时候不要在 KSM 上动手脚老老实实用 Prometheus 的metric_relabel_configs做重命名metric_relabel_configs: - source_labels: [label_team] target_label: team action: replace但记住metric_relabel 是在写入前对指标标签做变换要把label_team保留还是改成team要根据用量决定。一旦改名所有 Grafana 面板和 alert 规则里的变量都要一起改建议先在测试环境验证全链路再用到生产。6. 落地之后的几点经验最后整理几条我在多个集群实践下来的个人习惯不一定适用于所有团队但方向值得参考。一是标签命名先定标准。建议只暴露三到五个核心维度比如team、app、env、business大家写查询时心智负担小。宁可少而准不要多而全。二是配置全部走 GitOps。Helm values 里的metricLabelsAllowlist属于基础设施配置别靠人肉kubectl edit。每次改动都要有 PR、有审批、有回滚方案否则一个高基数标签加进生产问题往往不是马上爆出来的而是积累几周后 Prometheus 内存才报警。三是善用kube_*_labels指标做为查询期的“字典”。KSM 2.4 之后默认不输出这类指标但如果你确实需要某些标签又担心全量暴露导致基数问题可以针对性地只允许个别 key 输出然后按需 join。虽然查询慢一点但存储压力可控。四是升级 KSM 版本前先看 release notes。v1 到 v2 的参数变更就是一个典型例子其次是 v2.4 之后对kube_*_labels默认输出方式的调整。这类变化不会在启动时报错但会静默让你丢指标排起来特别费时间。如果你现在正被“KSM 指标里少业务标签”这个问题卡住按文章里的步骤先把 Pod 和 Deployment 的 allowlist 配上再去 Grafana 里验证变量和分组基本一下就通了。后续如果发现某个标签真的是每个查询都要用再考虑要不要全量暴露如果只是个别告警要用建议留在 join 场景里就好。
返回列表