
1. 集群监控这套组合拳到底解决什么问题搞过 K8s 的人都有体会容器一多Pod 一漂移服务的状态就像断了线的风筝kubectl get pods看到的只是活着但活着不等于健康。CPU 是不是被某个漏内存的服务悄悄吃满、某个接口的 P99 延迟是不是已经飙到两秒、节点磁盘是不是还有三天就写爆这些问题光靠命令行根本盯不过来。Prometheus Grafana 这套组合本质上就是给 K8s 集群装上体检仪 仪表盘让运维和开发能在一个页面上同时看到指标、告警和趋势。这篇文章我会把prometheus 监控 K8S的完整落地过程捋一遍从集群部署前置、Prometheus 的采集原理、Grafana 安装和配置一直讲到告警接入和踩坑排查。适合两类人看一类是刚开始接触prometheus grafana 安装部署、想照抄一套生产可用方案的同学另一类是已经装上了但数据对不上、大盘乱七八糟、告警死活不触发的老哥。我不打算只给你一堆 YAML更重要的是把每个选择背后的取舍讲透——为什么用 Operator 而不是手搓 manifest、为什么指标要打标签、为什么你的 Grafana 数据源总连不上。先说清楚这套东西的能力边界。Prometheus 负责拉取pull和存储时序数据它不做展示Grafana 负责把 Prometheus 里的数据画成图它不负责采集Alertmanager 负责接收 Prometheus 推过来的告警并做去重、分组、路由。三者是流水线上的三道工序任何一个环节配置错位最终你看到的要么是空图要么是误报。很多人第一次装完打开 Grafana 发现面板全是大红叉八成不是 Grafana 的问题而是数据源对接或者指标标签对不上。这个后面会专门开一节说。我个人的建议是如果你手上是单节点或者刚起步的小集群别一上来就上全套 Helm 大礼包先把 Prometheus、Grafana 各跑起来一个最小实例把数据流通路走通再往上加 StatefulSet、持久化、告警规则。通路没通就堆配置出了问题你连从哪一层查都不知道。2. 整体架构设计与部署方案选型2.1 为什么监控 K8s 首选 PrometheusK8s 生态里的监控方案不少Datadog、Zabbix、InfluxDB 系都能干但 Prometheus 能成为事实标准靠的是几个很实在的特性。第一是基于标签的多维数据模型每条指标都带一堆 key-value 标签你可以用pod、namespace、node这些维度随便切分聚合不用提前建表设计 schema这对容器这种动态环境太重要了。第二是pull 模型Prometheus 主动去各个 target 拉数据谁挂了它自己知道不像 push 模型那样需要服务端一直等着被推、还得处理推失败的重试。第三点也是很多人忽略的就是服务发现。K8s 里的 Pod IP 天天变传统监控要你手填 IP 列表根本没法维护。Prometheus 通过对接 K8s API能自动发现 Service、Pod、Endpoints配合注解annotation决定采不采、怎么采这才是它能扛住弹性伸缩集群的根本原因。至于时序库本身的性能单机 Prometheus 在指标量级合理的场景下每秒处理几十万样本、保留 15 天数据是没什么压力的。真到了需要长期存储、跨集群聚合的规模再引入 Thanos 或 VictoriaMetrics 做远端存储这是后续演进的事初始阶段不用背这个包袱。2.2 核心组件与数据流向先把这套系统里的角色理清楚不然后面看 YAML 会绕晕。整个链路大致是这样组件职责是否必须Prometheus Server服务发现、抓取指标、本地存储、按规则评估告警必须node-exporter采集节点级别指标CPU、内存、磁盘、网络建议kube-state-metrics把 K8s 对象状态转成指标Deployment 副本数、Pod 状态等建议Alertmanager告警去重、分组、静默、路由到邮件/钉钉/Webhook按需Grafana可视化展示、大盘管理必须数据流是单向的Prometheus 从各类 exporter 和应用的/metrics端点拉数据存进本地 TSDBGrafana 通过 PromQL 查询 Prometheus 的 HTTP API 拿数据绘图触发告警规则时 Prometheus 把告警推给 AlertmanagerAlertmanager 再按配置发给接收方。这里有个容易搞混的点Grafana 只读不写它不会往 Prometheus 里塞数据所以你在 Grafana 里永远改不了原始指标只能改展示方式。2.3 Operator、Helm、原生 YAML 三种路子怎么选部署 Prometheus 到 K8s主流有三种做法我按实际使用体验排一下。第一种是 Prometheus Operator现在多封装成 kube-prometheus-stack 这个 Helm Chart。它引入了一批 CRD比如ServiceMonitor、PodMonitor、PrometheusRule你想让 Prometheus 采集谁不用改 Prometheus 主配置只要写一个 ServiceMonitor 资源就行Operator 会自动帮你热加载。这套方案最大的好处是配置声明化、可版本管理、扩缩容跟着集群走新手用默认 values 也能一把装起来一整套包括 Grafana 和 Alertmanager。坏处是抽象层多出问题要顺着 CRD → Operator → StatefulSet 一路查。第二种是纯 Helm Chart 手配。灵活但服务发现和采集配置得自己写 relabel 规则改一次重载一次维护成本高适合对配置极度挑剔又要控资源的场景。第三种是原生 YAML 一把梭。所有配置硬编码在 ConfigMap 里适合学习原理生产环境 Pod 一多就是灾难改配置还得重启。我的选择很明确生产环境直接用 kube-prometheus-stack它是社区维护最活跃、默认大盘最全的方案省下来的时间拿去调告警规则比什么都值。下面实操也基于这个来。3. 集群侧前置准备与存储规划3.1 集群版本与资源基线动手前先确认几件事不然装到一半报错会让你怀疑人生。集群版本建议 1.20 以上太低的话部分 CRD 的 apiextensions 版本对不上。用kubectl version --short看一眼 Server 版本稳定版更省心。资源给多少这是新手最没谱的地方。我按单节点和中小集群给个参考值Prometheus 本身内存2Gi 起步指标多的话往 4Gi 走它内存跟活跃时间序列数成正比series 越多吃越多CPU 1 核够用抓取和告警评估是突发的。Grafana 很轻256Mi 内存足矣。node-exporter 和 kube-state-metrics 各自 100-200Mi 就够。如果你的集群有几十个节点、几千个 Pod那 Prometheus 直接往 8Gi、2 核上给别抠。提示先把kubectl top node的基线跑一遍心里有个数装完监控后对比一下才知道这套监控本身给集群增加了多少负担。3.2 持久化存储怎么配Prometheus 的本地 TSDB 默认写在容器里Pod 一重建数据全没监控数据丢了就等于没有历史可查所以必须挂持久化卷。K8s 里最省事的做法是提前备一个 StorageClass让 Prometheus 的 PVC 自动动态供给。如果你用的是公有云托管集群通常自带默认 StorageClass直接声明 PVC 即可。如果是自建集群得先装好类似 NFS provisioner 或者本地卷 provisioner然后kubectl get sc确认能看到一个带(default)标记的存储类。没有的话PVC 会一直卡在 PendingPrometheus 的 StatefulSet 就起不来这是最常见的卡点之一。存储大小按保留期算。默认保留 15 天大致公式是每天活跃样本量 × 样本字节数 × 15 天粗略经验是每 5000 个活跃 series、15 天大约占 5-8GB。中小集群给50Gi比较保险别省这个钱存储写满之后 Prometheus 会开始丢数据甚至崩。3.3 命名空间与权限准备我会单独建一个monitoring命名空间跟业务隔离方便统一管权限和清理kubectl create namespace monitoring权限这块Helm 装的 kube-prometheus-stack 会自带一套 ClusterRole能读全局的 Pod、Service、Endpoints、Node 等资源——这是服务发现必需的最小权限集合不要图省事给它 cluster-admin该最小化就最小化。真要更严格可以拆成多个角色按需绑定起步阶段用默认自带的即可等安全审计要求上来了再收紧。4. Prometheus 在 K8s 中的部署实操4.1 用 kube-prometheus-stack 一键拉起先把 Helm 仓库加进来并更新索引helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update然后准备一个values.yaml把持久化和资源这类关键项改成适合你的值。下面这份是我常用来起步的最小可调版本prometheus: prometheusSpec: retention: 15d resources: requests: memory: 2Gi cpu: 500m limits: memory: 4Gi storageSpec: volumeClaimTemplate: spec: storageClassName: standard accessModes: [ReadWriteOnce] resources: requests: storage: 50Gi grafana: persistence: enabled: true size: 10Gi resources: requests: memory: 256Mi这里几个参数我解释一下为什么这么填。retention: 15d是保留期够覆盖大部分排障需求太长则存储压力大storageSpec里的storageClassName一定要换成你集群里实际存在的那个名字写错了 PVC 就挂不上。grafana 开持久化是为了让 Dashboards 和用户配置不随 Pod 重启丢失虽然大盘可以代码化管理但手动导入的临时面板还是存下来方便。装helm install kube-prom prometheus-community/kube-prometheus-stack \ -n monitoring -f values.yaml装完等几分钟kubectl get pods -n monitoring应该能看到一堆 Running。这里注意第一次拉镜像会比较慢国内环境如果拉取困难提前准备好可用的镜像加速配置或私有仓库。4.2 采集配置与 ServiceMonitor 实战这套方案里Prometheus 采集谁不再是写死在配置文件里而是靠ServiceMonitor这种 CRD 声明。默认装完K8s 自身的 apiserver、kubelet、coredns、node-exporter、kube-state-metrics 这些已经被一堆内置的 ServiceMonitor 覆盖了你不用管。但业务应用的指标怎么接进来假设你有个 Spring Boot 服务暴露了/actuator/prometheus对应的 Service 上要打一个带端口的标签然后写一个 ServiceMonitorapiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: my-app-monitor namespace: monitoring labels: release: kube-prom spec: namespaceSelector: matchNames: [default] selector: matchLabels: app: my-app endpoints: - port: metrics path: /actuator/prometheus interval: 30s这里有几个坑必须点出来。第一labels里的release: kube-prom是必须的它得跟 Prometheus 实例的选择器对上否则 Operator 根本不会把这个 ServiceMonitor 关联进去你以为配了其实没生效。第二endpoints.port写的是 Service 里那个端口的名字不是数字很多人写成8080直接采不到。第三namespaceSelector决定去哪些命名空间找目标业务在别的 namespace 就得显式列出来。配置完kubectl apply然后去 Prometheus 的 Web UI默认通过 9090 端口 service 暴露里的Status - Targets看出现了对应 target 且 State 是 UP才算真正接入成功。4.3 指标标签与 PromQL 初体验指标能采到只是第一步能不能用好靠的是 PromQL。举个最常用的例子查某个接口的 QPS按 5 分钟速率rate(http_server_requests_seconds_count{uri/api/order}[5m])rate()是算每秒增量方括号里是时间窗口标签过滤用花括号。这里[5m]的窗口不能乱设太短会抖动太长会把瞬时尖峰抹平30s 采一次的指标用 5 分钟窗口比较平衡。再比如查所有 Pod 里内存使用最高的前 10 个topk(10, sum(container_memory_working_set_bytes{namespace!kube-system}) by (pod))topk、sum ... by、rate这几个函数基本能覆盖日常八成的查询需求。我建议新手别急着看花哨的 Dashboard先在 Prometheus 的 Graph 页面把这几条练熟理解标签过滤和聚合的逻辑再看 Grafana 大盘就知道每块图背后的查询长什么样。4.4 资源限制与保留策略调优跑一段时间后要回头调优。如果发现 Prometheus 频繁 OOM 被重启kubectl get pods里 RESTARTS 一直在涨大概率是 series 数量暴涨。先去Status - TSDB Status看 series 总数和 cardinality 最高的指标往往是某个应用把用户 ID、请求 ID 这种高基数标签打进了指标里这种标签是 Prometheus 的毒药得让开发去掉或者用 relabel 规则丢弃。保留策略有两种按时间retention和按大小retentionSize。我一般用时间设 15d如果磁盘紧张就加上retentionSize: 40GB让它先到的先删。注意这两个是或的关系任一条件满足都会触发清理。5. Grafana 安装接入与大盘配置5.1 Grafana 面板与数据源打通kube-prometheus-stack 默认已经把 Grafana 装了你可以通过端口转发先本地访问kubectl port-forward -n monitoring svc/kube-prom-grafana 3000:80浏览器开localhost:3000默认用户名admin密码从 Secret 里取kubectl get secret -n monitoring kube-prom-grafana \ -o jsonpath{.data.admin-password} | base64 -d进去第一件事是确认数据源。默认它会自动创建一个指向集群内 Prometheus Service 的 Prometheus 数据源。点进Connections - Data Sources选择 Prometheus往下拉点Save Test如果显示绿色的 Data source is working说明通路 OK。如果报错比如常见的datasource was not found或连接超时八成是这几处问题URL 写的是http://localhost:9090在 Grafana 容器里 localhost 不是 Prometheus或者 Prometheus Service 名跟数据源里配的对不上。正确做法是填集群内 Service 的 FQDN形如http://kube-prom-kube-prometheus-prometheus.monitoring.svc:9090。这个完整域名千万别手敲直接用下面命令抄省得打错kubectl get svc -n monitoring | grep prometheus注意Grafana 和 Prometheus 在同一集群时一定走 Service 域名别用 IPPod 重建 IP 就变数据源会连不上。5.2 导入官方与社区大盘数据源通了接着就是找大盘。Grafana 内置了导入功能Dashboards - New - Import输入大盘 ID 即可。社区里几个必装的大盘用途常用 IDNode Exporter Full节点 CPU/内存/磁盘/网络1860Kubernetes Cluster集群总览7249K8s Pod 概览按 Pod 看资源6417kube-state-metrics v2K8s 对象状态13332导入时它会让你选数据源选刚才那个 Prometheus 就行。这里有个新手必踩的坑ID 对应的大盘是给特定指标命名规范做的比如要求指标名是node_cpu_seconds_total如果你的采集配置改了指标名或者标签导入后图会空白或者报 no data。所以导入后先随便点开一块面板看 Edit 里的查询语句引用了哪些标签跟你实际采集到的对一对。kube-prometheus-stack 其实已经预置了一批大盘在 ConfigMap 里以grafana_dashboard标签管理装完就能直接看比手动导入省事。手动导入主要用在需要额外社区大盘的时候。5.3 告警接入 Alertmanager光看大盘不够人不会一直盯着屏幕得让系统主动喊你。Prometheus 的告警流程是Prometheus 按规则评估表达式的真假为真就发告警到 AlertmanagerAlertmanager 再做分组去重后发给接收方。先写一条规则用 PrometheusRule 这个 CRDapiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: node-alert-rules namespace: monitoring labels: release: kube-prom spec: groups: - name: node.rules rules: - alert: NodeHighMemory expr: (1 - node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) 0.9 for: 5m labels: severity: warning annotations: summary: 节点 {{ $labels.instance }} 内存使用率超过 90%这里for: 5m很关键它表示条件需要连续满足 5 分钟才真正触发避免瞬时抖动造成误报。没有这个稍微抖一下你的手机就被打爆了。annotations里可以用{{ $labels.xxx }}引用标签值让告警内容带上具体是哪个节点、哪个 Pod。规则生效后在 Prometheus UI 的Alerts页面能看到它处于 Inactive/Pending/Firing 状态。接着配 Alertmanager 的接收路由编辑它的 Secret 里的alertmanager.yaml把邮件、企业微信机器人或通用 Webhook 的配置填进去。改完记得让 Alertmanager 重载新版 Operator 会自动感知 Secret 变化。我个人建议告警分级severity: critical的走电话或强提醒warning的走群消息。别什么告警都往一个渠道丢不然消息疲劳之后真出大事反而没人看。6. 常见问题与排查技巧实录6.1 高频问题速查表把我在实际部署里反复遇到、也帮别人解决过的问题整理成表对照着查能省很多时间。现象大概率原因处理方向Prometheus Pod 起不来卡 PendingPVC 没有可用的 StorageClass检查kubectl get sc确认默认存储类存在Grafana 数据源测试报 not foundURL 填了 localhost 或 Service 名写错换成集群内 Service FQDNTargets 里业务目标始终不上报ServiceMonitor 的 release 标签不匹配补上release: kube-prom面板全空 / no data大盘要求的指标名或标签跟实际不符对着面板查询语句核对指标名Prometheus 频繁 OOM 重启高基数标签导致 series 暴涨查 TSDB Status用 relabel 丢弃高基数标签告警一直不触发for时间过长或表达式恒为假先在 Graph 里单独跑表达式验证数据查不到历史没挂持久化Pod 重建数据没了配 volumeClaimTemplate6.2 排查思路从数据流源头逐层往下遇到问题别乱点按链路顺序查最快。第一步确认 Prometheus 自身健康看它的Status - Targets如果内置目标都是 DOWN那是 Prometheus 的问题跟业务指标无关。第二步确认业务 target 是否出现出现了但 DOWN通常是网络策略、端口名写错或 endpoint 路径不对。第三步确认 Grafana 能不能查到数据在 Explore 里直接敲一条简单 PromQL比如up有结果说明数据源通路没问题。第四步才去看大盘前面三层都通了大盘问题就只是面板配置的事。我特别想强调第一层。很多人一上来就怀疑 Grafana其实绝大多数没有数据是 Prometheus 压根没采到Grafana 只是如实展示了一个空数据集。把 Prometheus 的采集链路查干净问题基本就解了。6.3 几个能少走弯路的实操心得关于时间同步Prometheus 和被抓取目标的系统时间偏差太大会导致样本被拒out of order 或 too old尤其是在自建集群上一定确保所有节点开了 NTP 同步这是很隐蔽的一类问题。关于标签命名让开发团队统一约定指标标签只放低基数的维度像service、env、instance这种绝对不要把 traceID、requestID 塞进标签一个请求一个标签值series 数量会指数爆炸几天就能把 Prometheus 拖垮。这个规矩最好写进团队的接入规范里比事后救火强一百倍。关于采集频率默认 30s 一次对大多数场景够了改成 15s 会翻倍存储和计算压力除非你确实需要更高分辨率否则别动。频率和保留期是两个独立的旋钮调之前想清楚自己的排障需求到底是看得更细还是看得更久。关于改配置工资之所以要花在调试上是因为很多人改完 values 不重新 apply。记住所有 ServiceMonitor、PrometheusRule 这类 CRD 资源kubectl apply之后还要给它几十秒让 Operator 热加载急不得。关于备份Grafana 的大盘、Prometheus 的告警规则、Alertmanager 的路由配置建议全部用 Git 管理把它们当成代码而不是一堆点出来的界面配置。这样换集群、重建环境时一套helm install加kubectl apply就能恢复比截图存文档靠谱得多。走到这一步一套能采、能看、能报警的监控链路就算完整跑起来了。后面真正花时间的其实是持续打磨告警规则——把那些天天响但没人管的告警删掉或者降级把真正的风险信号留下来这个过程没有终点得跟着业务一起迭代。我自己是从一条规则都不写到根据事故回补规则这么过来的每次线上出问题第一件事就是问这个故障如果当时有监控该长什么样把它补成规则比什么都实在。