Prometheus 监控 K8s 从入门到入坑:工作原理 + 部署实操 + 避坑指南

新接手一个 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 的升级版,在较大规模集群中性能更好,新集群应该优先用 endpointsliceendpointslice 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_idrequest_id 这种高基数值当作标签。我见过一个团队把 trace_id 塞进标签,Prometheus 内存直接飙到 20GB,集群差点崩了。正确的做法是用 status_codemethod 这种有限枚举值。

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 对应的 appVersionv0.93.0kube-state-metrics v2.19.1 对应 Helm Chart 版本为 8.0.0

四、配置详解:ServiceMonitor 和 PodMonitor

在动手部署之前,先搞懂这两个最重要的 CRD 概念。

4.1 这俩到底啥区别?

ServiceMonitorPodMonitor 是 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 面板没数据"

排查路径

  1. 打开 Prometheus UI → Status → Targets,看目标状态是 UP 还是 DOWN
  2. 如果是 DOWN,检查对应 Pod 的 /metrics 端点是否能从 Prometheus Pod 访问到
  3. 检查 ServiceMonitor 的 selector 是否匹配了正确的标签
  4. 检查 relabel 配置是否意外丢弃了标签

7.2 "Prometheus Pod OOMKilled"

大概率是标签基数太高,或者 retention 时间太长导致 TSDB 膨胀。解决方案:

  1. 检查是否有高基数标签(prometheus_tsdb_head_series 指标可以看时间序列总数)
  2. 缩短 retention 时间
  3. 增加内存 limit
  4. 考虑使用 recording rule 做预聚合
  5. 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 flagPrometheus 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,核心就三件事:

  1. 理解服务发现------Pull 模型 + Kubernetes API 自动发现,这是整个体系的根基
  2. 用好 Operator------别手写 prometheus.yml,用 ServiceMonitor/PodMonitor 声明式管理
  3. 控制标签基数------标签设计决定性能上限,高基数标签是万恶之源

最后留个互动问题:你在用 Prometheus 监控 K8s 时遇到过最诡异的故障是什么? 欢迎在评论区分享,咱们一起避坑。

觉得有用的话,分享给团队里正在搞 K8s 监控的同事,少踩一个坑就是赚到。

相关推荐
AAA@峥1 小时前
从零搭建 Prometheus 完整监控告警体系|Linux 部署 + node_exporter+Grafana 可视化
云原生·grafana·prometheus
虎王物联2 小时前
Docker BuildKit多阶段构建:IoT固件交叉编译流水线实战
运维·物联网·ci/cd·docker·容器·物联网嵌入式
10mAh2 小时前
【Docker】磁盘空间被占满怎么清理?——overlay2、容器日志与 Build Cache 排查实战
docker·容器·eureka
xhaxy2 小时前
docker,k8s安装,k8s集群搭建(OS7)
docker·容器·kubernetes
SelectDB技术团队3 小时前
Apache Doris 多云原生实践:SaaS、BYOC 与四大公有云覆盖
数据库·阿里云·云原生·华为云·腾讯云·亚马逊云·写入更新
名字还没想好☜12 小时前
Docker 容器安全加固实战:非 root、只读根文件系统、drop capabilities 与最小攻击面
运维·安全·docker·容器·kubernetes
鹤落晴春12 小时前
有状态应用 vs 无状态应用
运维·云原生·k8s
码--到成功12 小时前
Docker、Kubernetes安装系列 二
docker·容器·kubernetes
M--Y14 小时前
Docker镜像与仓库管理详解
docker·容器