Kubernetes对象状态指标导出器
kube-state-metrics(KSM) 监听 Kubernetes API Server,把集群中的对象状态转换成 Prometheus 指标暴露出来。它不采集资源用量,只回答「集群里有哪些对象、它们处于什么状态」:有多少 Deployment 的期望副本数没被满足、有多少 Pod 处于 Pending、哪些 PVC 还没绑定、哪些节点被封锁了。
它擅长回答的问题:
CrashLoopBackOff?Pending,哪些 PV 已释放?cordon 或带着 disk-pressure 污点?部署形态(通常放在 kube-system 或独立的 monitoring 命名空间):
Deployment/kube-state-metrics 主进程,ListWatch 各类资源并生成指标
Service/kube-state-metrics 暴露 /metrics 供 Prometheus 抓取
ServiceAccount + ClusterRole 只读权限,需要 list/watch 绝大多数资源
暴露的端口:
8080 业务指标 /metrics,由 --port 控制
8081 自身运行指标 /metrics,由 --telemetry-port 控制
KSM 自身不存储任何数据,它只是把 API 对象翻译成指标;历史趋势由 Prometheus 负责。
# 方式一:Helm(推荐)
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm upgrade --install kube-state-metrics prometheus-community/kube-state-metrics \
--namespace monitoring --create-namespace
# 方式二:官方示例清单(仓库里没有发布版清单文件,需要先克隆)
git clone https://github.com/kubernetes/kube-state-metrics.git
kubectl apply -f kube-state-metrics/examples/standard
# kube-prometheus-stack 已内置 KSM,不要再单独装一份
helm list -A | grep kube-prometheus-stack
验证:
kubectl get deploy,svc -n monitoring -l app.kubernetes.io/name=kube-state-metrics
kubectl port-forward -n monitoring svc/kube-state-metrics 8080:8080
# 在新终端里拉取指标
curl -s localhost:8080/metrics | head -50
curl -s localhost:8080/metrics | grep '^kube_node_status_condition'
curl -s localhost:8081/metrics | grep kube_state_metrics
# 确认 RBAC 是否足够(权限不足时指标会静默变少)
kubectl auth can-i list pods --as=system:serviceaccount:monitoring:kube-state-metrics -A
--port=8080 业务指标端口
--telemetry-port=8081 自身指标端口
--resources=... 启用的资源类型,默认已包含绝大多数内置资源
--namespaces=... 只监听指定命名空间,减少规模
--namespaces-denylist=... 排除指定命名空间
--metric-allowlist=... 白名单,与 denylist 互斥
--metric-denylist=... 黑名单,与 allowlist 互斥
--metric-labels-allowlist=... 把指定的 Kubernetes 标签提升为指标的 label
--metric-annotations-allowlist=... 把指定的注解提升为指标的 label
--metric-opt-in-list=... 启用默认关闭的指标
--custom-resource-state-config-file 自定义资源指标配置
--custom-resource-state-only 只暴露自定义资源指标
--auth-filter 对 /metrics 启用认证鉴权
--use-apiserver-cache ListWatch 走 apiserver 缓存,降低 etcd 压力
--shard=0 --total-shards=1 分片,大集群下横向扩展
--tls-config=... TLS 配置
标签白名单的写法是把资源名和标签键成对列出:
--metric-labels-allowlist=pods=[app,version],namespaces=[team]
--metric-annotations-allowlist=pods=[owner],deployments=[team]
默认情况下 KSM 不暴露 kube_pod_labels 里的业务标签,只暴露 pod、namespace 等基础标签 —— 想按 app、team 做聚合必须显式配置白名单,这是初次接入时最常踩的坑。
节点相关:
kube_node_info 节点基本信息(kubelet 版本、运行时、内核、内网 IP)
kube_node_status_condition 节点 Condition,label 为 condition 与 status(true/false/unknown)
kube_node_spec_unschedulable 节点是否被封锁(cordon)
kube_node_spec_taint 节点污点,label 为 key、value、effect
kube_node_status_capacity 节点总容量,label 为 resource、unit
kube_node_status_allocatable 节点可分配资源,label 为 resource、unit
kube_node_role 节点角色,label 为 role
kube_node_created 节点对象创建时间
Pod 与容器相关:
kube_pod_info Pod 基本信息,含 node、pod_ip、created_by_kind
kube_pod_status_phase Pod 阶段,label 为 phase(Pending/Running/Succeeded/Failed/Unknown)
kube_pod_status_ready Pod 是否就绪,label 为 condition
kube_pod_status_scheduled Pod 是否已调度
kube_pod_status_unschedulable 是否因调度失败被标记为不可调度
kube_pod_status_reason Pod 状态原因(Evicted、NodeLost、Shutdown 等)
kube_pod_container_status_waiting_reason 容器等待原因,label 为 reason
kube_pod_container_status_last_terminated_reason 容器上次终止原因(OOMKilled、Error 等)
kube_pod_container_status_restarts_total 容器重启次数(Counter)
kube_pod_container_status_ready 容器就绪探针是否通过
kube_pod_container_resource_requests 容器的 requests,label 为 resource、unit
kube_pod_container_resource_limits 容器的 limits,label 为 resource、unit
kube_pod_owner Pod 的属主(owner_kind / owner_name)
kube_pod_created / kube_pod_start_time Pod 的创建与启动时间
工作负载与存储:
kube_deployment_status_replicas 期望副本数
kube_deployment_status_replicas_available 可用副本数
kube_deployment_status_replicas_unavailable 不可用副本数
kube_deployment_status_condition Deployment 状况
kube_deployment_spec_replicas 期望副本数(spec)
kube_daemonset_status_number_ready DaemonSet 就绪数
kube_statefulset_status_replicas_ready StatefulSet 就绪数
kube_job_status_succeeded / kube_job_status_failed Job 成功与失败数
kube_persistentvolumeclaim_status_phase PVC 阶段(Pending/Bound/Lost)
kube_persistentvolume_status_phase PV 阶段
kube_horizontalpodautoscaler_status_current_replicas HPA 当前副本数
kube_poddisruptionbudget_status_current_healthy PDB 当前健康副本数
指标状态分三档,升级 KSM 大版本前应当关注 EXPERIMENTAL 与 DEPRECATED 的部分:
| 状态 | 含义 |
|---|---|
STABLE |
除大版本外极少有破坏性变更,可以放心依赖 |
EXPERIMENTAL |
对应 alpha 字段,可能随时变化或删除 |
DEPRECATED |
已废弃,将在既定时间点移除 |
两者名字相近,定位完全不同,经常被混为一谈:
| 组件 | 数据内容 | 数据来源 | 典型用途 |
|---|---|---|---|
metrics-server |
实时资源用量(CPU、内存实际占用) | kubelet Summary API | kubectl top、HPA |
kube-state-metrics |
对象状态(副本数、状态、条件、数量) | API Server 中的对象 | 监控大盘、告警规则 |
| cAdvisor / kubelet | 容器级资源用量原始数据 | 容器运行时 | Prometheus 抓取用量指标 |
关键区别:KSM 不提供资源用量。kube_pod_container_resource_requests 是容器申请的资源,不是实际消耗。要做 CPU/内存使用率监控,需要另行抓取 kubelet 的 cAdvisor 指标(如 container_cpu_usage_seconds_total),再与 KSM 的 requests 指标做关联查询。
KSM 支持把 CRD 的状态导出为指标,通过 --custom-resource-state-config-file 指定配置文件:
kubectl create configmap ksm-crs-config --from-file=crs-config.yaml -n monitoring
kind: CustomResourceStateMetrics
spec:
resources:
- groupVersionKind:
group: cert-manager.io
version: v1
kind: Certificate
metrics:
- name: "certmanager_certificate_expiration_timestamp_seconds"
help: "证书过期时间戳"
each:
type: Gauge
gauge:
path: [status, notAfter]
valueMultiplier: 1
需要注意:custom-resource-state 已被上游标记为特性冻结,官方推荐迁移到 resource-state-metrics 项目。新接入的项目应当评估这个方向。
# 期望副本数与可用副本数不一致的 Deployment
kube_deployment_spec_replicas - kube_deployment_status_replicas_available != 0
# 处于 Pending 的 Pod
sum by (namespace, pod) (kube_pod_status_phase{phase="Pending"}) > 0
# 正在崩溃循环的容器
kube_pod_container_status_waiting_reason{reason="CrashLoopBackOff"} > 0
# 被 cordon 的节点
kube_node_spec_unschedulable > 0
# 带磁盘压力的节点
kube_node_status_condition{condition="DiskPressure", status="true"} > 0
# 未被绑定的 PVC
kube_persistentvolumeclaim_status_phase{phase="Pending"} > 0
# 容器重启次数增长最快的 Pod
topk(10, sum by (namespace, pod) (increase(kube_pod_container_status_restarts_total[1h])))
# 最近一小时内被 OOMKilled 的容器
kube_pod_container_status_last_terminated_reason{reason="OOMKilled"} > 0
# 关联 KSM 与用量指标:某个 namespace 的实际内存用量与 requests 之比
sum(container_memory_working_set_bytes{namespace="dev"})
/ sum(kube_pod_container_resource_requests{namespace="dev", resource="memory"})
kube_pod_container_resource_requests 替代 kubectl top,或者反过来想用 KSM 算使用率,都是方向性错误。kube_pod_labels、kube_deployment_labels 只带 pod、namespace 等基础标签,app、team 这类标签必须通过 --metric-labels-allowlist 显式放行,否则按业务维度聚合的告警全部失效。--metric-labels-allowlist 用通配符 =pods=[*] 会严重拖慢性能,在高基数标签(如 pod-template-hash)上尤其明显,还可能造成 Prometheus 侧的时间序列爆炸。应按需列出具体标签键。--metric-allowlist 与 --metric-denylist 互斥,同时配置会导致启动失败。list/watch 权限,对应的 kube_* 指标就整段消失,排查时应先看 KSM 日志中的 forbidden 字样。kube_node_status_condition 是「每个 status 一条序列」,true/false/unknown 各占一条。查询时必须写 status="true",否则同一条告警会同时命中 false 序列而误报。kube_pod_status_phase 无法区分 Terminating 与 Unknown,因为这两个状态不存在于 Pod.Status 字段里,需要组合 kube_pod_deletion_timestamp 与 kube_pod_status_reason 才能推导出来。--shard / --total-shards 拆分,或配合 --namespaces 限定范围。kube_pod_container_resource_requests 与调度器视角存在偏差。上游已推荐改用 kube-scheduler 在 /metrics/resources 暴露的 kube_pod_resource_request,后者计算的是包含 Pod 级资源和 init 容器取大值之后的有效资源需求,更精确。kube_* 旧指标,升级前务必对照发布说明检查告警规则与大盘表达式。kubectl — Kubernetes集群管理工具metrics-server — 集群资源指标采集组件,与 KSM 互补prometheus — 指标存储与查询系统,抓取 KSM 的 /metricshpa — 水平自动扩缩容,依赖 metrics-serverkubelet — 节点代理,资源用量的原始来源