简介:面向Kubernetes集群运维与开发者,这套部署方案基于Prometheus和Grafana构建监控体系,用来采集集群与应用指标、完成可视化展示,并支持告警通知。压缩包仅3个YAML文件,总大小5KB,分别对应Prometheus服务端、Grafana面板和Node Exporter节点指标收集器,配置简洁、便于修改。目前已有836人学习,可直接按顺序应用到集群中。借助Prometheus的服务发现机制,系统能自动发现新Pod,抓取CPU、内存、网络I/O等关键数据;Grafana将数据渲染为直观图表,运维人员可快速掌握集群状态;Node Exporter负责采集各节点的负载、磁盘与网络信息,配合Prometheus的告警规则和Alertmanager,能在故障发生时及时推送消息。整个方案麻雀虽小但五脏俱全,省去了自行编写配置的麻烦,特别适合刚开始尝试在Kubernetes中搭建监控体系的读者。
1. Kubernetes 监控选型:为什么是 Prometheus 和 Grafana
集群刚上线那几天,一切都很顺利。等业务一扩容,Pod 在节点间来回调度,旧的监控方案立刻翻车——IP 是死的,目标列表是手写的,节点一换,图就断。后来我把监控栈整体迁到 Prometheus 和 Grafana 上,才把“监控谁、从哪抓、怎么画”这件事真正交给集群自己回答。这个标题讲的就是在 Kubernetes 里部署一套以 Prometheus 为采集存储、Grafana 为可视化界面的监控系统,让指标跟着服务发现走,而不是跟着 IP 走。适合正在维护生产集群、被“扩容后监控失联”折磨的运维和平台工程师;读完你能独立装出一套可用、可调、不埋雷的监控栈。
2. 把监控链路拆开:Prometheus 的拉模型与 Grafana 的展示层
2.1 为什么 Prometheus 是 Kubernetes 监控的事实标准
Kubernetes 里的 workload 是动态的:Deployment 滚动更新、HPA 扩容、节点故障驱逐,Pod 的 IP 和名字随时变。传统 Push 模式的 agent 采集方案需要提前知道目标在哪里,这在容器环境里非常别扭。Prometheus 走的是 Pull 模型——由 Prometheus Server 主动发 HTTP 请求去抓取指标,配合 Kubernetes 的服务发现机制,它每隔一段时间向 API Server 询问“当前有哪些 Service、哪些 Pod 带着我要的标签”,然后自动生成抓取目标列表。这一步解决的不只是 IP 漂移,还包括新 Pod 上线后自动接入监控。
这套设计的核心价值在于:你不需要在业务容器里塞 Agent,只需要暴露一个/metrics端口,Prometheus 就能完成发现、拉取、存储、查询。这也是为什么云原生生态里几乎所有组件都自带 metrics 接口,比如 kubelet、etcd、API Server,都是天然被抓取的对象。
2.2 拆开看这套系统由哪几块组成
一套完整的 K8s 监控栈,不是只有 Prometheus Server 和 Grafana 两个进程。按职责拆,至少是四层:
| 组件 | 角色 | 部署形态 |
|---|---|---|
| Prometheus Server | 指标采集、TSDB 存储、PromQL 查询 | Deployment/StatefulSet |
| Exporters | 暴露指标,如 node-exporter、kube-state-metrics | DaemonSet / Deployment |
| Alertmanager | 接收告警规则,做去重、分组、路由 | Deployment |
| Grafana | 数据可视化、告警展示、Dashboard 管理 | Deployment |
四个组件里,Prometheus 是整个链路的数据中枢,负责定时抓取各目标的/metrics,把时序数据写入本地 TSDB;Grafana 本身不存监控数据,它通过数据源接口连接 Prometheus,用 PromQL 查询出数据再画成图。需要强调的是,很多新手以为“装上 Grafana 就等于监控完成”,其实数据采集没通,Grafana 只是一块漂亮的空屏幕。
2.3 先看一套最小 Prometheus 配置长什么样
在没有 Operator 介入之前,Prometheus 核心就是一个 YAML 文件加一个启动命令。拿最原始的部署方式来理解它的工作逻辑:
global: scrape_interval: 30s # 全局抓取间隔,默认 1 分钟 evaluation_interval: 30s # 告警规则评估间隔 scrape_configs: - job_name: 'kubernetes-nodes' kubernetes_sd_configs: # 基于 Kubernetes 服务发现 - role: node # 发现所有节点 relabel_configs: - source_labels: [__metrics_path__] regex: /metrics action: replace target_label: __metrics_path__ replacement: /metrics这段配置看的不是命令,而是两个关键设计:scrape_interval决定数据粒度,越短越占存储和内存;kubernetes_sd_configs让 Prometheus 自己问 API Server “现在有哪些节点”,而不是你在配置文件里写死三个 IP。实际生产里我们很少裸写scrape_configs,而是用 Prometheus Operator 的 ServiceMonitor 抽象,但底层原理仍然是这套拉取模型。
2.4 Prometheus Operator:把配置变成 Kubernetes 资源
在生产环境里,直接管理 Prometheus 的 YAML 配置是有风险的:改一个抓取配置要进容器、改文件、重载,多人协作时很容易互相覆盖。所以社区的主流做法是用 Prometheus Operator 这一层控制器,把“抓取配置”抽象成 ServiceMonitor 这种 CRD 资源。你创建了一个 ServiceMonitor,Operator 就自动帮你把对应的scrape_config渲染进 Prometheus 配置里。
这套抽象带来一个好处:开发自服务的团队可以自己提交 ServiceMonitor,不用再去碰 Prometheus 实例的配置。后面我们部署的kube-prometheus-stack就是把 Operator、Prometheus、Grafana、各类 Exporter 打包在一起的完整方案。
3. 在 Kubernetes 上部署 Prometheus:用 Helm 一次性拉起整套监控栈
3.1 部署前要确认的两件事:RBAC 权限与存储规划
Prometheus 要发现 Kubernetes 资源,必须有权限访问 API Server。它的 ServiceAccount 需要能 list/watch nodes、services、endpoints、pods 这些资源。用裸 YAML 部署时最容易漏掉这块,结果就是日志里刷kubelet 401 Unauthorized,Targets 页面一片红。用 Helm 部署kube-prometheus-stack时,RBAC 相关资源会自动创建,但你要知道这个前提存在,后面排查权限问题才不抓瞎。
存储方面,Prometheus 默认把数据写在容器的临时目录里,Pod 一重建历史数据就全没了。生产环境要给 Prometheus 配上 PVC,容量按“指标数量 × 采集频率 × 保留天数”粗估。一般来说,100 个 Pod 规模的集群,保留 15 天,30Gi 起步;如果采集间隔压到 15s,这个数字要翻倍。
3.2 用 Helm 安装 kube-prometheus-stack 的完整过程
这是目前最快、最不容易出错的路径:一个 Chart 包含 Prometheus、Grafana、Alertmanager、node-exporter、kube-state-metrics,以及它们之间的联动配置。操作步骤分三步执行。
# 1. 添加官方 Helm 仓库并更新索引 helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update # 2. 创建独立的命名空间并安装 kubectl create namespace monitoring helm install kube-prometheus-stack prometheus-community/kube-prometheus-stack \ --namespace monitoring \ --version <当前稳定版本>参数说明:prometheus-community是社区维护的官方 Chart 仓库,kube-prometheus-stack是包名;--namespace monitoring让所有监控组件集中在一个命名空间,方便统一管理权限和网络策略。安装完成后,用下面的命令看启动状态:
kubectl get pods -n monitoring # 期望看到 prometheus、grafana、alertmanager 等 Pod 处于 Running 状态刚装完时 Pod 可能会因为拉镜像慢而卡在ContainerCreating,等一两分钟再看是正常的。如果状态一直变CrashLoopBackOff,多半是镜像拉不下来或资源限制太小,这个我们后面单独讲排查。
3.3 安装前把这三个参数写进 values.yaml
默认安装能跑通,但直接上生产会难受。我一般会在安装前准备一个values.yaml,把下面三组参数先改掉:
grafana: adminPassword: "your-strong-password" # 默认 admin 密码太简单,先改掉 service: type: NodePort # 测试环境用 NodePort 快速访问 nodePort: 30080 prometheus: prometheusSpec: retention: 15d # 指标保留时长,默认也是 15d,显式写出来便于审计 resources: requests: memory: 2Gi # 请求内存,调度时参考 limits: memory: 4Gi # 限制内存,防止 OOM 拖垮节点 storageSpec: volumeClaimTemplate: spec: accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi # 给 Prometheus 数据盘参数说明:retention是时序数据的保留时间,超过这个时间的数据会被后台任务删除;storageSpec.volumeClaimTemplate让 Prometheus 的每个副本都绑定一个 PVC,Pod 调度到其他节点时数据跟着走。资源限制不能省,Prometheus 的内存占用会随 target 数量线性增长,不设 limits 的后果是 OOM 后 Kubernetes 不断重启它,数据写入跟不上。
3.4 验证部署结果:从 Pod 状态到 Targets 页面
部署完不是看一眼 Pod 就完事,要验证“能抓能查能画”。先做两步检查:
# 检查 Prometheus 服务是否在集群内可访问 kubectl get svc -n monitoring # 找到 prometheus 的 ClusterIP 服务,一般叫 kube-prometheus-stack-prometheus # 把 Prometheus 的 Web UI 转发到本地 kubectl port-forward -n monitoring svc/kube-prometheus-stack-prometheus 9090:9090浏览器打开http://localhost:9090,进入Status → Targets,这里会列出 Prometheus 当前抓取的所有目标。正常的节点和 ServiceMonitor 目标应该是绿色的UP状态。如果目标是DOWN,点进去能看到具体的拉取错误信息,这是后面调监控最重要的入口。
4. Grafana 接入与数据源配置:让监控面板先亮起来
4.1 Grafana 的登录与暴露方式
用kube-prometheus-stack安装时 Grafana 已经带好数据源,默认配置里已经自动添加了 Prometheus,登录后就能看到预置的 Kubernetes 集群监控 Dashboard,密码就是刚才values.yaml里设置的adminPassword。但如果你是手工分开部署的 Grafana,或者想理解数据源是怎么连上的,要按下面的步骤走一遍。
访问 Grafana 有两种方式:测试环境用 NodePort 或 port-forward,生产环境建议走 Ingress 并开启 HTTPS。下面命令把 Grafana 转发到本地 3000 端口:
kubectl port-forward -n monitoring svc/kube-prometheus-stack-grafana 3000:80浏览器打开http://localhost:3000,用admin和你设置的密码登录。登录后第一件事不是建 Dashboard,而是确认Configuration → Data Sources → Prometheus里的 URL 是否正确。
4.2 数据源的 URL 到底该填什么
这是最常见的翻车点。很多人装了 Grafana 后,在数据源 URL 里填localhost:9090,结果图全是 No Data。原因很简单:Grafana 和 Prometheus 在不同的 Pod 里,localhost指向的是 Grafana 自己。
正确写法是使用 Prometheus 的集群内服务地址,格式为http://<service-name>.<namespace>.svc.cluster.local:<port>。用我们 Chart 默认的 release 名,实际填的就是:
# Grafana Data Source 配置示例 apiVersion: v1 kind: ConfigMap metadata: name: grafana-datasources namespace: monitoring data: datasources.yaml: | apiVersion: 1 datasources: - name: Prometheus type: prometheus url: http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090 access: proxy isDefault: true填完后点Save & Test,出现绿色提示 "Data source is working" 就说明通了。如果报HTTP status 400或连接超时,优先检查 Prometheus Service 的名字——release 名变了,服务名也会跟着变,不要照抄网上的路径。
4.3 免手工配置:用 Provisioning 管理数据源和 Dashboard
面板多了以后,手工在界面上一个个配置数据源和导入 JSON 是很痛苦的事,而且换环境就要重来一遍。生产做法是走 Provisioning:把数据源配置和 Dashboard 文件挂载到 Grafana 容器里,启动时自动加载。
# 把 Dashboard JSON 放到 Grafana 的 provisioning 目录 kubectl create configmap grafana-dashboards \ --from-file=dashboards.json \ -n monitoring # 在 values.yaml 中开启挂载 grafana: additionalDataSources: - name: Prometheus type: prometheus url: http://kube-prometheus-stack-prometheus.monitoring.svc.cluster.local:9090 access: proxy isDefault: true dashboards: default: k8s-cluster: json: | # 这里放你自己的 Dashboard JSON 内容参数说明:additionalDataSources是 Chart 提供的扩展字段,它会把数据源自动写进 Grafana 配置;dashboards下面的配置会把 JSON 内容挂载进容器,Grafana 启动时扫描并导入。这样做的好处是,数据源和面板都变成代码,环境迁移时只需要重新应用同一份 YAML。
4.4 导入社区 Dashboard:一个 ID 省三天工作量
自己从零画监控面板效率太低,社区已经有非常成熟的现成 Dashboard。Grafana 官方社区里有大量针对 Kubernetes 和节点监控的面板,导入方式很简单:Dashboards → Import → 输入 Dashboard ID → Load。推荐几个经过大量生产环境验证的面板 ID:
| 面板 ID | 监控对象 | 适用场景 |
|---|---|---|
| 315 | Node Exporter 节点指标 | 看 CPU、内存、磁盘、网络的基础面板 |
| 8919 | Kubernetes 集群监控 | 集群视角的 Pod、容器、节点总览 |
| 1860 | Node Exporter 全量指标 | 需要深度排查节点问题时用 |
导入后如果某些图显示 No Data,大概率是面板里的 PromQL 查询用了固定 job 名,和你环境里的标签不一致。这时候要回到 Prometheus 的 Targets 页面看实际的job和instance标签,手动改面板查询里的job="..."部分即可。
5. 避坑:K8s 上跑 Prometheus 与 Grafana 的五个高频问题
5.1 现象:Prometheus Pod 反复重启,状态停在 CrashLoopBackOff
明明 Helm 安装没有报错,Pod 却一直重启。看日志发现是存储目录权限问题,或者是内存超限被杀。前者常见于自定义了storageSpec但没有给 PVC 正确的 fsGroup;后者常见于只设置了 limits 却没给 requests,导致调度时内存评估失真。
解决分两步走:第一,给 Prometheus 的 StatefulSet 加securityContext.fsGroup,让运行用户对 PVC 有写权限;第二,检查resources配置,把 requests 和 limits 都显式设上,避免 OOM 后无限重启。
5.2 现象:Grafana 面板全是 No Data,但数据源测试是通的
数据源能连通,说明网络没问题;图没数据,问题出在查询层面。最常见的原因是面板里的 PromQL 用了旧版的标签名,比如把node_cpu_seconds_total写成node_cpu,或者 job 名不匹配。另一个隐蔽原因是 Grafana 的时区设置不对,看起来“没有数据”其实是时间范围选到了没有数据的未来时段。
排查路径:先到 Prometheus 的 Graph 页面里手工执行同样的 PromQL,确认有数据;再回到 Grafana 的 Explore 页面查询,看返回的时间序列标签;最后检查面板变量里的job下拉值是否匹配你的集群标签。
5.3 现象:监控系统比业务系统还吃资源
这是最容易被忽视的“隐形成本”:node-exporter 是 DaemonSet,每个节点都有一份;kube-state-metrics 要监听集群全部资源;Prometheus 本身还要把抓到的数据做索引和压缩。小规模集群导出的资源可能占掉 10% 的总内存。
我一般建议三个收敛动作:第一,把全局scrape_interval从默认改到 30s 甚至 60s,很多指标不需要 15s 粒度;第二,用relabel_configs过滤不需要抓取的 Pod,比如只保留带prometheus.io/scrape=true注解的目标;第三,给 Prometheus 设置合理的内存 limits,宁可牺牲一点缓存命中率,也不能让它把节点内存吃满。
5.4 现象:重启后历史监控图变成空白
Prometheus 的时序数据写在本地磁盘,如果用的是emptyDir存储,Pod 被重新调度后数据就没了。这不是“坏”了,而是存储没配 PVC。在测试环境里图方便没关系,一旦你对着空白的图排查历史问题,就知道什么叫后悔药没处买。
解决:给 Prometheus 配上volumeClaimTemplate,同时确认 PVC 的回收策略是Retain。另外,如果有 HA 需求,单副本的 Prometheus 本身就有单点风险,数据持久化只是第一步。
5.5 现象:ServiceMonitor 建了,但 Targets 里没有对应目标
ServiceMonitor 是让 Prometheus 自动发现抓取目标的关键,但很多人创建后等半天 Targets 里还是空的。原因基本是标签选择器对不上:ServiceMonitor 的selector匹配的是 Service 的标签,而不是 Pod 的标签;或者namespaceSelector没有选中目标 Service 所在的命名空间。
# 一段可复制的 ServiceMonitor 示例 apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: example-app namespace: monitoring spec: selector: matchLabels: app: example-app # 匹配 Service 的 labels namespaceSelector: matchNames: - default # Service 所在命名空间 endpoints: - port: metrics # Service 端口名,必须和 Service 定义一致 interval: 30s这段配置的核心是port字段:它对应 Service 里定义的端口名,不是数字端口。写错这个字段,Targets 里会一直显示Http discovery error。遇到这类问题,先用kubectl get svc -n default --show-labels确认标签和端口名,再反查 ServiceMonitor 的 selector。
6. 验证监控系统真的可用:从 Targets 清单到告警联调
安装完成不等于监控完成,我习惯用三件事验证这套系统“真的能用”。第一件事,回到 Prometheus 的Status → Targets页面,清点目标数量。一个正常的集群至少应该看到三类目标:kubernetes-nodes(节点指标)、kubernetes-pods(带采集注解的 Pod)、kubernetes-service-endpoints(ServiceMonitor 生成的目标)。任意一类为空,都说明服务发现链路有断点。
第二件事,在 Grafana 的 Explore 页面手动执行一条 PromQL,验证数据闭环。比如查节点 CPU 使用率:
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100)如果这条查询能输出曲线,说明采集、存储、查询、展示全部打通。第三件事,配置一条最简单的告警规则验证 Alertmanager 链路。在 Prometheus 的规则里加一条“节点内存使用率超过 90% 持续 5 分钟”的告警,然后故意压一个测试节点,看告警能不能到达你的通知渠道。
最后一个习惯:每次改动监控配置前,用helm template渲染出完整 YAML 检查一遍,再helm upgrade应用。监控系统是运维的眼睛,但它自己出问题时排障成本最高。这套方案我用下来的感受是:Prometheus 和 Grafana 的组合在 Kubernetes 里不是“能跑”的问题,而是“能不能稳定地跑、出问题时能不能快速定位”。提前把存储、权限、资源边界设好,后面能省掉大量半夜救火的精力。希望帮到你。
提示:文中涉及的面板 ID 和 Chart 名称来自社区公开资料,实际部署时以你所用版本的官方文档为准。资源大小和保留时长的数值均需结合集群规模调整,先小后大,观察内存曲线再扩容。
本文还有配套的精品资源,点击获取