☰
K8s集群监控利器:kube-prometheus-stack部署实战与踩坑指南
2026/10/13 6:29:03 网站建设 项目流程

把一套 K8s 集群跑起来,通常意味着业务已经准备好在容器环境里稳定工作了。但真正接手一个集群之后,我第一件要做的事不是调高副本数,而是先把监控告警铺好——因为你不光要看到集群活没活,还要看到它是在什么状态下活着。这套“K8s可视化监控告警”系列,第一篇就是最基础也最容易被轻视的环节:Prometheus部署。本篇会带你从部署前的决策,到 Helm 完整落地,到部署后怎么验证,再把我踩过的几类高频坑完整拆一遍。适合刚入门 K8s 运维的同学,也适合集群已经跑起来但监控一直缺位的团队直接对照落地。

1. 部署前先想清楚:你的集群监控到底要装什么

很多人拿到 K8s 集群第一反应就是“装个 Prometheus”,然后 helm install 一条命令下去,看着一堆 Pod 起来就以为完事了。实际上部署动作本身只是最后一公里,真正决定监控好不好用的是部署之前那几个决策:监控哪些对象、数据存在哪、用哪种部署方式。这三件事没想清楚,后面几百个 Target 起来了也是睁眼瞎。

1.1 四个监控层次,少一个都会让你半夜被叫醒

K8s 集群的监控需求可以拆成四个层次,每个层次对应不同的数据来源和采集组件,kube-prometheus-stack 这套方案能成为事实标准,就是因为它把这四层全部盖住了。

第一层是控制面组件。API Server、Controller Manager、Scheduler 的存活状态、请求速率、延迟,直接决定了集群本身是否健康。这个层面最常见的坑是:如果你的集群由某云厂商托管,控制面你是看不见的,那就跳过;如果是自建集群,这几个组件的采集指标必须配齐。

第二层是节点层。每台 Node 的 CPU、内存、磁盘、网络、文件系统使用率,靠 node-exporter 以 DaemonSet 方式跑在每个节点上,暴露 9100 端口。很多人以为只看容器指标就够了,结果宿主机磁盘写满导致镜像拉不下来,才发现节点指标比容器指标更底层、更不能缺。

第三层是工作负载与集群对象状态。Deployment 期望副本数和实际副本数是否一致、Pod 是否 Pending、PVC 是否 Bound、Service 是否有 Endpoints,这些信息 Kubernetes 自己知道,但不会主动告诉你。kube-state-metrics 就是干这个的,它监测 Kubernetes API,把对象状态拆成指标。这一层恰恰是最多人忽略的,因为“容器都 Running 了”和“这个服务真的可用”之间,隔着太多看不见的状态。

第四层才是容器运行时的指标。每个 Pod 的容器 CPU、内存、网络、磁盘 IO,这些来自内置的 cAdvisor,通过 kubelet 暴露。它不需要额外部署组件,但需要确保 kubelet 的认证与端口配置正确。

1.2 存储方案直接决定部署方式,别用默认值硬扛

Prometheus 是典型的状态ful应用,默认配置下数据写在 Pod 的 emptyDir 里,Pod 一重启,几天的监控历史直接清空。测试环境无所谓,但生产环境这样做约等于没有监控——告警的时候查不到历史趋势,定位问题全靠猜。

所以部署前先确认集群里有没有可用的 StorageClass。如果你用的是云厂商的托管集群,通常自带一个默认 SC;自建集群的话,要么装一个本地存储方案,要么基于网络存储提供动态供给。这块要单独提醒一句:不同 StorageClass 的回收策略和性能差异很大,Prometheus 这种高频小IO写磁盘的应用,不适合用那种延迟很高的网络盘做热数据存储,宁愿把 retention 调短一点,也不要让数据写入成为瓶颈。

保留周期也要提前想。默认 retention 是 15 天,意味着在中小规模集群下,100GB 的 PVC 往往只够支撑两周到一个月。粗略估算公式是:每秒写入样本数 × 平均样本大小 × 保留秒数。中小集群一般每秒产生 1 万到 5 万样本,每个样本约 1.5KB 到 2KB,算下来一天约 1.3GB 到 8.6GB,15 天就是 20GB 到 130GB。如果你还要加一堆自定义 exporter,容量只会更紧张。

1.3 三种部署路线,我为什么选 Helm 全家桶

Prometheus 部署到 K8s 有粗线条的三种方式,先做个对比:

部署方式基本思路适合场景主要缺点
二进制/镜像单机直接跑一个 Prometheus,静态配置抓取目标本地试验、临时验证没有服务发现,K8s Pod 一重建配置就失效
只装 Prometheus Operator用自定义资源管理监控,但告警、图表自己再搭已有 Grafana/Alertmanager,只想引入 Prometheus集成成本高,默认规则缺失
kube-prometheus-stackOperator + Prometheus + Alertmanager + Grafana + exporter 全家桶大多数生产与测试集群chart 较大,第一印象有点“重”

我个人的建议很明确:别犹豫,直接用 kube-prometheus-stack。它不是一个简单的 Prometheus Helm Chart,而是一整套由开源社区长期打磨的组合包。你得到的不只是 Prometheus 本身,还包括 Prometheus Operator、Alertmanager、Grafana、node-exporter、kube-state-metrics,以及一整套默认的采集配置和告警规则。这套默认规则尤其值钱,很多刚上手的人以为告警要自己一条条写,其实 kube-prometheus-stack 装好就自带了几十条基础规则,比如 Pod 反复重启、节点磁盘将满、API Server 延迟过高,都覆盖了。

用到后面你会发现,自定义监控“新服务”这件事的门槛也被这套方案拉低了——你只需要写一个 ServiceMonitor 对象,告诉 Operator“这个 Service 的某个端口要被抓取”,剩下的都由 Operator 自动完成。

2. Helm 落地部署:values 配置逐项拆解

确定走 kube-prometheus-stack 之后,真正的实操才开始。这节我会按我自己平时落地的顺序一步步来,并重点解释每个配置项的用途,而不是甩一个现成的 values 文件让你照抄。

2.1 前置检查:Helm、kubectl、StorageClass 三件套

部署前先确认环境里三个东西是否就绪。

  • Helm:建议 3.8 以上,低版本对 chart 的兼容性差,容易在安装时报奇怪的模板语法错误。
  • kubectl:能正常访问集群,并且当前 context 指向目标集群。命令行里执行kubectl cluster-info确认一下,少踩“装错环境”的低级失误。
  • StorageClass:执行kubectl get storageclass,记录下你想用的 SC 名称。如果没有可用的 SC,那你得先去解决存储问题,否则 Prometheus 和 Grafana 的 PVC 都会卡在 Pending。

确认完毕后,添加官方社区仓库并更新索引:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm search repo prometheus-community/kube-prometheus-stack

这里有个经验:第一次用某个 chart 时,先执行helm show values prometheus-community/kube-prometheus-stack > values-default.yaml,把默认值导出来留着参考。后面你想改什么配置,照着这个文件找路径,比翻在线文档高效得多。

2.2 核心 values 配置:存数据、限资源、控周期

不要裸装 chart。至少改三个地方:持久化、资源限制、保留周期。下面是一份我常用的精简配置,可以直接存成values.yaml:

global: scrapeInterval: 30s evaluationInterval: 30s prometheus: prometheusSpec: retention: 15d resources: requests: cpu: 500m memory: 2Gi limits: cpu: "1" memory: 4Gi storageSpec: volumeClaimTemplate: spec: storageClassName: standard accessModes: ["ReadWriteOnce"] resources: requests: storage: 100Gi alertmanager: enabled: true grafana: adminPassword: "your-strong-password" persistence: enabled: true storageClassName: standard size: 10Gi

逐项拆解:

  • scrapeInterval与evaluationInterval:前者是 Prometheus 多久去拉一次指标,后者是多久评估一次告警规则。默认是 1m,我习惯压到 30s。注意这不是越小越好,采集频率提高一倍,存储量也跟着翻倍,小集群没必要追求 10s。
  • retention:保留周期,如前所述,结合你的磁盘容量设置。没有绝对正确的值,只有“磁盘够不够”这一个判断维度。
  • resources:给 Prometheus 主容器设定资源上限非常重要。它不像普通无状态服务那样可以随便 restart,OOM 导致的后果是监控数据断档。4Gi 内存上限可以覆盖绝大多数中小集群。
  • storageSpec:这是持久化的关键。PVC 模板会动态创建一块 100Gi 的盘,写满后不会自动扩容,所以可以按需调小或调大。
  • grafana.adminPassword:部署时直接指定 Grafana 管理员密码,省的第一次登录时还得去查随机生成的密码。生产环境更推荐用existingSecret挂 Secret。

2.3 执行安装与组件角色一览

配置写好后,执行安装:

kubectl create namespace monitoring helm install kube-prometheus prometheus-community/kube-prometheus-stack \ -n monitoring \ -f values.yaml

安装过程会创建一批 CRD(CustomResourceDefinition),包括 ServiceMonitor、PodMonitor、PrometheusRule、AlertmanagerConfig 等。CRD 是这套体系能够自动化工作的基石:你不需要手写 Prometheus 的抓取配置文件,而是通过声明式对象告诉 Operator“哪些目标需要纳入采集”。这也是为什么后面自定义监控时,核心动作是写 ServiceMonitor 而不是去改 Prometheus 的 yaml。

装完以后,等一两分钟镜像拉取,然后看 Pod 状态:

kubectl get pods -n monitoring

正常情况下你会看到类似这样的结果:

NAME READY STATUS RESTARTS AGE alertmanager-kube-prometheus-stack-alertmanager-0 2/2 Running 0 6h kube-prometheus-stack-grafana-7f78b8467b-xxxxx 3/3 Running 0 6h kube-prometheus-stack-kube-state-metrics-d8d8f-xxxx 1/1 Running 0 6h kube-prometheus-stack-operator-5f6f5f8f8-xxxxx 1/1 Running 0 6h prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 6h kube-prometheus-stack-node-exporter-xxxxx 1/1 Running 0 6h kube-prometheus-stack-node-exporter-yyyyy 1/1 Running 0 6h

各组件角色简单说就是:operator 负责“看菜下饭”,把你声明的监控需求翻译成 Prometheus 的实际配置;Prometheus 负责拉指标和算告警;Alertmanager 负责把触发的告警发到钉钉、邮件、Webhook 等地;Grafana 负责把指标画成图;node-exporter 与 kube-state-metrics 分别负责节点和对象状态的指标供应。

3. 部署后的第一轮验证:从 Pod 健康看到指标可信

部署这一步是给“运行”用的,但只有运行状态合格还不够。我见过太多集群里 Prometheus 是 Running,点开 Targets 页面却一屏 DOWN。所以部署完成后别急着开心,按下面顺序做三轮验证。

3.1 Pod 层面的健康检查

先看 Pod 列表里有没有 CrashLoopBackOff 或 ImagePullBackOff,再检查 READY 列是否如示例所示全都 1/1 或 2/2。注意 READY 列的数字不总是 1,比如 Prometheus 主容器旁边还有 config-reloader 边车容器,所以 2/2 代表两个容器都正常,不能只看 STATUS 是 Running。

如果某个 Pod 反复重启,立刻看日志和事件:

kubectl -n monitoring logs <pod-name> --previous kubectl -n monitoring describe pod <pod-name>

--previous参数非常关键,因为 CrashLoop 状态下当前容器日志经常是空的,只有上一次退出的日志才有内容可看。

3.2 Targets 页面与 UP/DOWN 状态

Pod 全 Running 后,把 Prometheus 的 Web UI 转发到本地:

kubectl get svc -n monitoring | grep prometheus kubectl port-forward -n monitoring svc/prometheus-operated 9090:9090

转发成功后在浏览器打开http://127.0.0.1:9090,进入 Status -> Targets 页面。你会看到一长串采集目标,每个目标前面都有一个 UP/DOWN 标志。

这里要建立一个最重要的概念:一个 Target 显示 UP,只代表这个抓取端点的 HTTP 请求返回了正常指标,不代表你的监控已经覆盖到位。UP 只是“连接畅通”,指标语义是否正确是另一回事。比如 node-exporter 正常返回数据,但 kubelet 的/metrics/cadvisor端口因为认证问题抓不到,Target 列表里会直接显示 DOWN——这种问题越早发现越好,等业务跑起来再排错压力就大了。

3.3 用三条 PromQL 验证监控数据真的可用

只看 Target 全 UP 还是不够,得用几条查询确认数据确实被采集并且能用于判断集群状态。我把每一次部署后必查的三条 PromQL 列在这里:

节点 CPU 使用率,用来验证 node-exporter 的数据链路:

100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)

容器内存使用量,用来验证 Kubelet/cAdvisor 的数据链路:

sum by (namespace, pod) (container_memory_working_set_bytes{container!=""})

工作负载期望副本数是否被满足,用来验证 kube-state-metrics 的数据链路:

kube_deployment_spec_replicas - kube_deployment_status_replicas

三条查询有结果且数值合理,说明四层监控链路已经打通了。这一步做完,Prometheus 部署这件事才算真正验收合格。

3.4 告警链路“通了”与“可用”之间的差距

打开 Alert 标签页,你会看到 kube-prometheus-stack 默认加载的几百条告警规则。它们大多处于 inactive 状态,只有指标确实触发阈值后才会变成 firing。

部署阶段我建议不要主动去搞破坏来验证告警,先观察规则是否能正常加载。规则的加载本身已经验证了 Prometheus 到 Alertmanager 的连接是通的。至于告警消息能不能发到钉钉或邮件、路由树怎么配、抑制与分组怎么做,那是这个系列后续文章的主角,这阶段只要保证链路是活的就行。

4. 踩坑实录:四类高频问题的完整排查链路

kube-prometheus-stack 虽然安装简单,但真正维护起来有几个坑是几乎每个人都会踩的。我把最常见的问题按“现象—排查—解决”写下来,这比直接告诉你答案更有用,因为下次换个姿势出现,你还能按这个思路自己查。

4.1 Prometheus 反复重启:先查 PVC 再查资源,别急着删 Pod

现象:prometheus-0 这个 StatefulSet 的 Pod 起不来,一直在 CrashLoopBackOff,或者 PVC 一直 Pending。

排查链路:

  1. kubectl get pvc -n monitoring,看 PVC 状态。
  2. 如果 PVC 是 Pending,kubectl describe pvc <pvc-name>,看 Events 里的报错。
  3. 如果报错是 storageclass 不存在或者 WaitForFirstConsumer,说明 SC 名写错了或者调度时机不对。
  4. 如果 PVC 已 Bound,再看 Pod 的kubectl describe,检查是否有 FailedMount 事件。

这里有个真正坑过我的场景:用了 WaitForFirstConsumer 模式的 SC,Prometheus 调度到节点之后 PVC 才开始创建,但因为节点没有可用的磁盘资源,PVC 一直拿不到卷,然后 Pod 卡在 ContainerCreating。如果只看 Pod 状态,第一反应是“删掉重建”,但其实重建多少次都没用,根因在存储资源上。

解决思路:确认 SC 的配置和节点容量。测试环境不想折腾时,可以干脆先不配 storageSpec,用 emptyDir 跑通功能,生产环境再补持久化。

4.2 Targets 大面积 DOWN:ServiceMonitor 的服务发现逻辑

现象:Prometheus 起来了,Targets 页面上某个类别全是 DOWN,或者干脆整个列表里少了一类目标。

排查链路:

  1. 切换到该 Target,看 Endpoint 地址显示的是什么。
  2. 如果地址是 Pod IP + 端口,先去确认那个 IP 能不能通,kubectl get pod -o wide看看对应 Pod 是否存在。
  3. 如果地址是 Service 名,检查 Service 是否有 Endpoints:kubectl get endpoints -n <namespace>。
  4. 然后回头看 ServiceMonitor:kubectl get servicemonitor -n <namespace>,确认它的 selector 是否匹配到了目标 Service。

大多数人踩的坑都出在第 4 步。ServiceMonitor 通过 label selector 找到目标 Service,如果你的 Service 少了对应的 label,或者 ServiceMonitor 的 namespaceSelector 没有把目标命名空间包含进来,Prometheus 就发现不了它。Operator 不会主动报错,它只会把“找不到”当成正常结果,Target 列表里静默缺失。

解决思路:排查时不要只盯 Prometheus 本身,先看 ServiceMonitor 与 Service 之间的 label 匹配。开两个终端,一边看 ServiceMonitor 的 yaml,一边看目标 Service 的 labels,一眼就看出问题。

4.3 硬盘被监控数据塞满:基数与保留期的取舍

现象:跑了两周,PVC 所在的磁盘使用率直线飙升,Prometheus 日志里出现大量head storage has expired,或者查询某些指标速度明显变慢。

根因分析:Prometheus 的数据量不取决于集群节点数,而取决于时间序列数量。一个指标加一组标签就是一个序列,如果某个指标带了 Pod 名称、请求路径这种高基数标签,序列数会爆炸式增长。K8s 集群里最容易踩的是直接把container_network_receive_bytes_total按 Pod 维度长期聚合,Pod 频繁重建会产生大量一次性序列,再叠加默认的 15 天保留期,磁盘很快就满。

解决思路:一是合理缩短 retention,二是对高基数标签做聚合降维,三是只抓取真正需要的指标,别一股脑把 node-exporter 和 kubelet 的所有指标都长期保留。可以设置 remote write 把长周期数据转存到远端,Prometheus 本地只留短周期的热数据,这样磁盘压力会小很多。

4.4 指标偏差真实存在:时间同步与 exporter 版本差异

现象:Grafana 上看到的 CPU 使用率曲线总比其他平台高一点或低一点,不是完全对不上,但趋势总有点歪。

根因分析:有两种常见来源。第一种是节点时间不同步。Prometheus 计算rate()时依赖时间窗口,如果采集端和被采集端时间差超过几十毫秒,rate 算出来就是歪的。K8s 集群所有节点必须配好 NTP,这属于基本功,但经常被人忽略。第二种是 exporter 版本差异。不同版本的 node-exporter 对某些内核指标的解释不同,比如node_cpu_seconds_total在不同版本分别代表 CPU 时间还是 CPU 使用率,单位都可能不一样。如果 Grafana 用的是自带的默认面板,那通常没问题;一旦自定义面板,就得先确认指标单位再画图,否则数字对不上是常事。

5. 部署只是起点:为告警链路预留的扩展点

Prometheus 部署完成只是“监控告警”的开始。就算你已经能看到 Targets 全绿、Grafana 面板能画出漂亮的曲线,离“告警闭环”还有一段路。这节我不会直接把告警讲完,但会在部署篇把该预埋的扩展点都准备好。

5.1 运维闭环里现在就该做的三件小事

第一件,给监控命名空间加上资源配额。监控组件会随着集群长大而变胖,不设限额的话,node-exporter 在几百台节点上跑起来,光它一个 DaemonSet 可能吃掉几个核。我在一个 50 节点集群里遇到过 node-exporter 内存涨到 1GB 的情况,最后是靠给 DaemonSet 加 resources.limits 压住的。

第二件,把 Grafana 的 dashboard JSON 备份进代码仓库。很多人只备份 Prometheus 规则,dashboard 丢了就靠记忆重画。其实 Grafana 的 dashboard JSON 就是一份文本文件,完全可以入库管理,每次改完面板顺手导出覆盖,比事后后悔省事太多。

第三件,记录下你的 ServiceMonitor 命名约定。随着自定义监控越来越多,ServiceMonitor 的 name、namespace、labels 如果不统一,后面找人维护时全靠猜。建议定一条简单规则:ServiceMonitor 与目标 Service 放同一个 namespace,命名用<应用名>-monitor,selector 统一用app.kubernetes.io/name: <应用名>。

5.2 Alertmanager 与 Grafana 的入口确认,给系列留好“接口”

部署篇收尾前,至少把两个入口确认掉:

Alertmanager 的 UI:

kubectl get svc -n monitoring | grep alertmanager kubectl port-forward -n monitoring svc/alertmanager-operated 9093:9093

打开后能看到当前已加载的告警。正常情况下没有任何 alert,但能看到一条条 receiver 配置。后续文章要讲的路由树、分组、抑制,入口都在这里。

Grafana 的 UI:

kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:3000

用前面设置的 admin 密码登录后,确认数据源里已经有一个指向 Prometheus 的数据源。这里最容易被忽视的是:如果后续你自己部署了第二个 Prometheus,或者接入了 Thanos,需要手动加数据源,别搞混。

5.3 一个实测好用的监控自检脚本

最后分享一个我常用的自检脚本逻辑。部署完成后不想一次次手动点页面,可以用这个一键检查核心链路:

#!/bin/bash NAMESPACE=monitoring echo "=== 1. Pod 状态 ===" kubectl -n $NAMESPACE get pods | grep -v Running || echo "存在非 Running 状态的 Pod" echo "=== 2. ServiceMonitor 列表 ===" kubectl -n $NAMESPACE get servicemonitor echo "=== 3. Prometheus 核心指标 up ===" kubectl port-forward -n $NAMESPACE svc/prometheus-operated 9090:9090 >/dev/null 2>&1 & PF_PID=$! sleep 3 curl -s "http://127.0.0.1:9090/api/v1/query" --data-urlencode 'query=up' \ | python3 -c "import sys,json; data=json.load(sys.stdin); results=data.get('data',{}).get('result',[]); print(f\"UP 目标数量: {sum(1 for r in results if r['value'][1]=='1')} / {len(results)}\")" kill $PF_PID

脚本的作用很直接:第一步看 Pod 有没有非 Running,第二步看我们声明了多少个采集对象,第三步通过 Prometheus 自身的 API 统计 UP 目标数量。在这里我故意保留了原始的 UP 目标总数和正常数量,如果两者差距越来越大,多半是某个节点或组件挂了,可以继续深挖。

这套东西用下来,比我以前手写静态配置去跑 Prometheus 的体验好了几个量级。尤其是后面要接自定义监控时,你只需要写好 ServiceMonitor,剩下的服务发现、配置热加载都由 Operator 托管,这才是把部署这一步做到位的真正意义。等下一篇再聊告警规则和 Alertmanager 配置时,你会发现现在打好的地基会非常扎实。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询