新接手一个 K8s 集群,老板甩过来一句"把监控搭起来,明天我要看数据",你打开终端开始敲命令,结果发现配了一上午,Grafana 面板上还是空的------这种场景我太熟悉了。更扎心的是,好不容易装好了,过两天数据又没了,查半天发现是 retention 配置在 3.x 里改了位置。今天我把 Prometheus 监控 K8s 的完整流程和踩过的坑一次性说清楚,照着做就行。
一、速查急救包
以下命令假设你已经通过 Prometheus Operator 部署了监控栈。遇到问题先跑这几条:
# 1. 查看 Prometheus 所有采集目标的状态(最重要!)
kubectl -n monitoring get prometheus -o yaml
# 或者在 Prometheus UI 里点 Status → Targets
# 2. 检查 ServiceMonitor 是否生效
kubectl -n monitoring get servicemonitor
# 3. 查看 Prometheus Pod 日志(采集失败时必看)
kubectl -n monitoring logs -l app=prometheus --tail=100
# 4. 验证 kube-state-metrics 是否正常
kubectl -n monitoring get pods -l app=kube-state-metrics
# 5. 检查 PVC 状态(数据丢了先看这个)
kubectl -n monitoring get pvc
二、为什么 K8s 监控必须用 Pull 模型?
先聊个概念。很多从 Zabbix 转过来的朋友,刚接触 Prometheus 时最不习惯的就是 Pull 模型------Prometheus Server 主动去拉取数据,而不是被监控端主动推送。
在 Kubernetes 里,Pod 频繁重建、IP 随时变化。如果用 Push 模式,你得维护一个不断变化的 targets 列表,谁受得了?Pull 模式天然适配这种动态环境------Prometheus 通过 Kubernetes API 自动发现新 Pod、新 Service,目标列表实时更新。
Kubernetes 自身组件(kubelet、kube-apiserver、etcd)本身就暴露了 /metrics 端点,格式就是 Prometheus 能直接吃的。所以用 Prometheus 监控 K8s,不是"选它",是"只能选它"。
三、核心原理:Prometheus 在 K8s 里到底怎么工作的?
3.1 服务发现(Service Discovery)------最关键的机制
Prometheus 在 K8s 里干活的核心是 服务发现。它通过调用 Kubernetes API Server,实时 watch 集群资源的变化。
支持 6 种服务发现 role:
|-----------------|-----------------------|----------------------------------|
| Role | 发现什么 | 什么时候用 |
| node | 集群节点 | 采集 kubelet 和节点指标 |
| service | K8s Service | Service 级别的探测 |
| pod | 单个 Pod | 采集应用自定义指标 |
| endpoints | Service 背后的 Endpoints | 传统方式,新集群不推荐 |
| endpointslice | EndpointSlice 对象 | 新集群推荐,比 endpoints 更 scalable |
| ingress | Ingress 资源 | 对 URL 做黑盒探测 |
endpoints和 pod的区别 :endpoints role 能给你更多标签数据(比如 Pod 属于哪个 Service),而 pod role 会 targeting 任意 Pod------包括那些没有对应 Service 的。endpointslice 则是 endpoints 的升级版,在较大规模集群中性能更好,新集群应该优先用 endpointslice 。endpointslice role 从 Prometheus v2.21.0 开始支持。
关于 EndpointSlice 的一个重要背景 :从 Kubernetes v1.33 开始,Endpoints API 已被正式弃用 ,社区推荐迁移到 EndpointSlice API。如果你使用的是 Kubernetes v1.33+ 集群,务必关注这个迁移。Prometheus Operator 从 v0.55.0 开始宣称支持 endpointslice,但早期版本(v0.55.x)存在 bug 导致支持不工作。建议使用 Operator v0.82.0+ 并配置 spec.serviceDiscoveryRole: EndpointSlice来启用------这是官方推荐的迁移方式。
工作流程是这样的:Prometheus 的 discovery manager 通过 kubernetes_sd_configs 配置的角色,从 API Server 拉取资源元数据,然后经过 relabel 规则过滤和转换,最终生成采集目标列表。
我踩过的坑 :endpoints role 在 K8s v1.33+ 中已经被弃用。如果你还在用旧配置,会发现控制台不断刷出 v1 Endpoints is deprecated in v1.33+ 的警告日志。Helm 社区从 prometheus-29.0.0 开始已经将 endpoint role 迁移到 endpointslice 了。
3.2 数据模型与标签设计
Prometheus 的数据模型由 指标名 + 一组标签 构成。比如:
http_requests_total{method="GET", status="200", endpoint="/api/users"}
标签设计直接影响性能。高基数标签是性能杀手 ------千万别把 user_id、request_id 这种高基数值当作标签。我见过一个团队把 trace_id 塞进标签,Prometheus 内存直接飙到 20GB,集群差点崩了。正确的做法是用 status_code、method 这种有限枚举值。
3.3 Prometheus 3.x 的重要变化
如果你之前用的是 Prometheus 2.x,升级到 3.x 有几个需要注意的点:
- Prometheus 3.14.0 是最新稳定版(2026-08-17 发布)
- 3.14.0 是短期支持版本 ,EOL 日期为 2026-09-30 。如果你追求长期稳定,推荐使用 3.13.2 LTS (2026-07-29 发布),官方支持到 2027 年 7 月 31 日
--storage.tsdb.retentionCLI flag 在 3.0 中已被移除。Prometheus 3.x 推荐通过配置文件来设置 retention 参数- Prometheus Operator 0.92.0 (2026-06-18 发布)开始支持将 retention 选项写入配置文件,但该行为仅对 Prometheus >= v3.11.0 生效;对于更低版本的 Prometheus,Operator 仍然通过 CLI flags 传递 retention 配置
- Prometheus Operator 0.93.0(2026-07-28 发布)是最新版本
kube-prometheus-stack Helm Chart 88.3.0 对应的 appVersion 为 v0.93.0 。kube-state-metrics v2.19.1 对应 Helm Chart 版本为 8.0.0。
四、配置详解:ServiceMonitor 和 PodMonitor
在动手部署之前,先搞懂这两个最重要的 CRD 概念。
4.1 这俩到底啥区别?
ServiceMonitor 和 PodMonitor 是 Prometheus Operator 引入的 CRD,用来声明式地定义"要采集谁"。
- ServiceMonitor:通过 K8s Service 发现背后的 Pod。适合需要经过 Service 访问的场景
- PodMonitor:直接通过 Pod 标签发现目标。适合不需要 Service 的应用,或者需要更细粒度控制单个 Pod 监控的场景
ServiceMonitor 比 PodMonitor 更常用 ,对大多数场景都推荐用 ServiceMonitor。只在 ServiceMonitor 满足不了需求时才用 PodMonitor。
4.2 一个能跑通的 ServiceMonitor 示例
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app-monitor
namespace: my-app
spec:
selector:
matchLabels:
app: my-app # 选择带有这个标签的 Service
endpoints:
- port: metrics # Service 里定义的端口名
path: /metrics
interval: 30s
namespaceSelector:
matchNames:
- my-app
创建后,Prometheus Operator 会自动把它转换成 Prometheus 的 scrape 配置。
4.3 应用 Pod 需要加什么?
要让 Prometheus 发现你的应用 Pod,需要在 Pod 的 annotation 里声明:
apiVersion: v1
kind: Pod
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "8080"
prometheus.io/path: "/metrics"
⚠️ 注意:这个 annotation 机制是社区约定,不是 K8s 原生功能。Prometheus 的 relabel 规则会读取这些 annotation 来决定是否采集。
五、部署实操:两种方式,我推荐第二种
理解了 ServiceMonitor 和 PodMonitor 这两个核心 CRD 之后,我们正式开始部署。
方式一:手动部署(不推荐,仅用于理解原理)
手动创建 Deployment、Service、ConfigMap,配置 prometheus.yml 里的 kubernetes_sd_configs。优点是能深刻理解每个配置项的含义,缺点是维护成本太高------每次加一个监控目标都要改 ConfigMap 重启 Prometheus。
方式二:Helm + kube-prometheus-stack(生产推荐)
这是社区的标准做法。kube-prometheus-stack 集成了 Prometheus Operator、Prometheus、Alertmanager、Grafana、node-exporter、kube-state-metrics 等一堆组件。
前置条件 :Kubernetes 1.25+(kube-prometheus-stack 88.x 要求 kubeVersion: '>=1.25.0-0'),Helm 3+
# 添加 Helm 仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 安装(默认配置,快速验证)
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring --create-namespace
就这么简单?对。但生产环境不能这么搞,下面说配置。
生产环境必须改的配置
创建一个 production-values.yaml:
# production-values.yaml
prometheus:
prometheusSpec:
# 持久化存储------默认是 emptyDir,Pod 重启数据就没了
storageSpec:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi # 根据集群规模调整
# 资源限制------不设的话可能把节点内存吃光
resources:
requests:
memory: 4Gi
cpu: 2
limits:
memory: 8Gi
cpu: 4
# ⚠️ Prometheus 3.x 的 retention 配置方式变了!
# 不要用 retention: 15d(旧方式),要用下面的 tsdb 块
# 注意:此配置仅对 Prometheus >= v3.11.0 + Operator >= 0.92.0 生效
tsdb:
retention:
time: 15d # 按时间保留
# size: 100GB # 按大小保留,二选一或同时使用
# percentage: 80 # 按 PVC 容量百分比保留(0-100),三选一或组合使用
grafana:
persistence:
enabled: true
size: 10Gi
然后执行:
helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \
-f production-values.yaml -n monitoring
💡 我踩过的坑 :第一次部署时没配 storageSpec,第二天节点重启,所有历史数据全没了。幸好是测试环境。生产环境 务必配置持久化存储。
六、标签重标记(Relabeling):最容易被忽视的杀手锏
Relabeling 是 Prometheus 里最强大也最容易被忽视的功能。分两种:
- relabel_configs :在 采集之前 生效,用于过滤目标、修改目标地址
- metric_relabel_configs :在 采集之后 生效,用于修改或删除指标标签
典型场景:从 Pod annotation 里提取信息作为标签:
relabel_configs:
# 只采集带 prometheus.io/scrape=true 注解的 Pod
- source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
action: keep
regex: true
# 把 namespace 加到标签里
- source_labels: [__meta_kubernetes_namespace]
action: replace
target_label: namespace
💡 极少人知道的隐藏技巧 :__meta_kubernetes_pod_annotation_* 这组标签可以读取 Pod 的任何 annotation。你可以用自定义 annotation 来给 Pod 打上"监控分组""告警级别"等元信息,然后通过 relabel 注入到指标里。这招在微服务场景下特别好用------不同业务线的 Pod 打上不同的 team annotation,告警路由就能按团队分发。
七、常见问题排查
7.1 "Grafana 面板没数据"
排查路径:
- 打开 Prometheus UI → Status → Targets,看目标状态是 UP 还是 DOWN
- 如果是 DOWN,检查对应 Pod 的
/metrics端点是否能从 Prometheus Pod 访问到 - 检查 ServiceMonitor 的 selector 是否匹配了正确的标签
- 检查 relabel 配置是否意外丢弃了标签
7.2 "Prometheus Pod OOMKilled"
大概率是标签基数太高,或者 retention 时间太长导致 TSDB 膨胀。解决方案:
- 检查是否有高基数标签(
prometheus_tsdb_head_series指标可以看时间序列总数) - 缩短 retention 时间
- 增加内存 limit
- 考虑使用 recording rule 做预聚合
- 用
metric_relabel_configs丢弃不需要的高基数指标
7.3 "采集不到 kube-scheduler 和 kube-controller-manager"
这两个组件默认只监听 localhost。需要在 kube-scheduler 和 kube-controller-manager 的启动参数里加上 --bind-address=0.0.0.0,然后创建对应的 Service 和 ServiceMonitor。
7.4 "ServiceMonitor 不生效"
检查 Prometheus 是否配置了正确的 serviceMonitorSelector。默认情况下,Prometheus 只发现带有相同 release 标签的 ServiceMonitor。
# 查看 Prometheus 的 serviceMonitorSelector 配置
kubectl -n monitoring get prometheus -o yaml | grep -A5 serviceMonitorSelector
八、高可用与长期存储方案选型
Prometheus 单实例的本地存储不适合大规模生产。常见选型:
Thanos :CNCF 孵化项目,提供长期存储、全局查询、数据去重。适合已有 Prometheus 部署、想平滑扩展的场景。优势是迁移风险小 ------几乎不需要改变现有的 Prometheus 配置和采集路径。缺点是运维复杂度高------需要部署 sidecar、querier、store gateway、compactor 等多个组件。
VictoriaMetrics :性能更强,资源占用更低。适合追求简单和低运维开销的团队。单二进制部署,比 Thanos 的运维复杂度低得多。
选型建议:
- 小规模(<50 节点) :Prometheus + 持久化存储就够了
- 中等规模,已有 Prometheus 部署:Thanos,迁移风险最小
- 新部署或对资源敏感:VictoriaMetrics,性能和成本都更优
⚠️ 彩蛋:Prometheus 3.x + Operator 0.92.0 的 retention 配置坑
Prometheus 3.x 移除了 --storage.tsdb.retentionCLI flag 。Prometheus Operator 0.92.0 开始支持将 retention 写入配置文件,但仅对 Prometheus >= v3.11.0 生效。
如果你在 Helm values 里还写着:
正确的写法是(仅当 Prometheus >= v3.11.0 且 Operator >= 0.92.0 时生效):
我因为这个配置问题,在一个生产集群上跑了整整一周才发现数据只保留了默认的 15 天。幸好及时发现了,不然 SLA 报告要出大问题。
如果你的 Prometheus 版本低于 v3.11.0 ,Operator 仍然会通过 CLI flags 传递 retention 配置,此时在 values 中使用 retention 字段是有效的。
另外要注意:3.14.0 的 EOL 是 2026-09-30 ,只有大约 6 周的生命周期。如果追求长期稳定,强烈推荐使用 3.13.2 LTS(支持到 2027-07-31)。
prometheusSpec:
retention: 15d # 这个在 3.x 里已经不生效了!
prometheusSpec:
tsdb:
retention:
time: 15d
# size: 100GB # 按大小限制,可选
# percentage: 80 # 按 PVC 容量百分比,可选
九、总结
用 Prometheus 监控 Kubernetes,核心就三件事:
- 理解服务发现------Pull 模型 + Kubernetes API 自动发现,这是整个体系的根基
- 用好 Operator------别手写 prometheus.yml,用 ServiceMonitor/PodMonitor 声明式管理
- 控制标签基数------标签设计决定性能上限,高基数标签是万恶之源
最后留个互动问题:你在用 Prometheus 监控 K8s 时遇到过最诡异的故障是什么? 欢迎在评论区分享,咱们一起避坑。
觉得有用的话,分享给团队里正在搞 K8s 监控的同事,少踩一个坑就是赚到。