☰
K8s监控基石:kube-prometheus-stack部署与指标采集全解析
2026/10/13 5:34:51 网站建设 项目流程

做 K8s 集群运维,特别是公司内部已经有多个业务线在上面跑之后,我最先意识到的问题不是“如何发布服务”,而是“看不见集群里正在发生什么”。某个命名空间里的 Deployment 因为一次探活失败被不断重启,节点磁盘使用率悄悄突破 90%,业务高峰期 HPA 自动把副本从 2 扩到 20,这些现象如果只能靠用户投诉和半夜响应来发现,那排查成本会高得离谱。所以,给 Kubernetes 补上可视化监控告警,我把它放在了所有平台建设的前置位。整个体系的第一环,就是先把 Prometheus 部署起来,把指标采集链路打通;只有数据进来了,后面的 Grafana 面板、Alertmanager 通知才有意义。

这篇内容面向的是已经能正常使用 K8s、但还没有成体系监控的团队。我会从部署前的思路、环境准备、具体安装步骤、核心配置拆解一直到常见问题的排查,完整记录一次 kube-prometheus-stack 的落地过程。标题里的【1】不是套路,这个系列我确实打算分几篇来写,这一篇专心解决“采得到”的问题。

1. 项目概述与部署前思考

1.1 动态环境下的监控逻辑

K8s 的调度逻辑决定了监控体系和传统服务器监控有本质区别。以前监控一台物理机,只需要固定 IP、固定端口,Agent 装好之后就是一个稳定目标;但 K8s 里 Pod 随时可能被销毁、重建、漂移到另一台节点,Service 的 Endpoint 列表也在实时变化。如果继续用“手工添加目标”的方式采集,维护量会失控,而且漏掉临时任务和单副本实例几乎是必然的。

Prometheus 模型天然适配这种动态环境。它采用主动拉模式(Pull),监控服务只需要暴露一个 HTTP 的 /metrics 端点,Prometheus 服务端会通过 Kubernetes API 的服务发现机制,持续发现新的 Pod、Service、节点等目标并采集指标。你可以把它理解成一套“自动点名系统”:不关心同学坐在哪个教室,只要名单里能找到 TA 就行。更关键的是,Prometheus 数据模型里每个指标都带有标签,比如 Pod 名、命名空间、节点名都可以作为维度,查询时能以任意维度做聚合和过滤,这比传统监控的数值列表灵活得多。

这也解释了为什么很多云原生监控方案都会围绕 Prometheus 来做:它不只是一个监控软件,更像是一套能被 K8s 原生管理的数据采集标准。我们不需要在每个 Pod 里装 Agent,业务应用只要引入对应语言客户端或自己输出 Prometheus 格式指标即可,成本低、接入也统一。

1.2 选型:用全套整合栈而不是零散组件

确定用 Prometheus 之后,紧接着是选择部署形态。我第一版只用 Helm 安装了单独的 Prometheus Server,ServiceMonitor 和告警规则全靠手工维护,结果业务隔三差五新增服务,监控配置也跟着改,很快就乱成一团。后来切到 kube-prometheus-stack,才算是把这一块理顺。

kube-prometheus-stack 本质上是一套预打包的监控解决方案,核心由 Prometheus Operator 驱动。Operator 用 CRD(CustomResourceDefinition)把监控目标、告警规则、通知配置都抽象成了 K8s 资源。比如 ServiceMonitor 定义“采集哪些 Service”、PrometheusRule 定义“什么情况触发告警”、AlertmanagerConfig 定义“告警往哪里发”。我们提交这些 YAML 后,Operator 负责把资源配置变成底层 Prometheus 实例的配置。这种声明式管理方式,让监控配置和业务部署一样走 Git 流程,可以 review、可以回滚。

除了 Prometheus Operator,这个 chart 还把 Grafana、Alertmanager、kube-state-metrics、node-exporter 都打包了。第一次部署时可能会觉得组件很多,但实际运行起来会发现它们职责非常清晰:Prometheus 管指标采集与存储,Grafana 管展示,Alertmanager 管告警分发,kube-state-metrics 负责把 K8s 对象状态转换成指标,node-exporter 负责暴露节点级指标。作为系列第一篇,我建议不要只装一个裸 Prometheus,而是直接装整套栈,把后面可视化、告警需要的组件一次到位,后面两篇文章就可以直奔主题,不用再回过头补组件。

2. 部署前环境准备

2.1 版本清点与兼容性

Prometheus Operator 依赖 Kubernetes API 的能力,版本不匹配会直接导致 CRD 安装失败或者控制器报错。所以安装前,我习惯先记录下当前集群版本和 Helm 版本:

kubectl version --short helm version

如果你的 Kubernetes 是 1.26 或更高,当前主流的 kube-prometheus-stack 版本基本都能兼容;如果还在 1.20 以下,就需要去 chart 的 README 里查看对应的支持矩阵。不要觉得版本检查很多余,社区 issue 里最常见的一类问题就是把新版 chart 装到旧集群,然后 operator 的日志里充满 unknown field。

另外,还需要确认当前 kubectl 权限是否可以创建命名空间、StatefulSet、CRD。有些团队里的账号是只读的,装 chart 时一直卡在创建资源阶段,还以为网络问题。可以先执行kubectl auth can-i create namespace来判断。

2.2 持久化方案与存储类

Prometheus 把时序数据写在本地磁盘,所以存储是硬需求。对于单节点的测试环境,可以用 emptyDir,但 Pod 重启后数据就没了,生产不可接受。K8s 里正确的做法是让每个 Prometheus 副本通过 PVC(PersistentVolumeClaim)挂一块独立存储,这样即使 Pod 漂移,数据也能跟着持久卷走。

在部署前,必须确认集群里有哪些 StorageClass:

kubectl get storageclass

如果是空,可以参考自己集群的存储方案,比如本地磁盘可以部署 local-path-provisioner,云环境通常自带 default 存储类。没有 StorageClass 也可以安装 chart,但后续 PVC 会一直 Pending,最终 Prometheus Pod 起不来。这个坑我踩过,所以现在每次布置前都会先看一遍存储类。

2.3 Helm仓库与命名空间

用 Helm 管理监控栈,最大的好处是升级、卸载干净。添加官方 chart 仓库和创建命名空间都可以用命令行完成:

helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update kubectl create namespace monitoring

命名空间建议统一叫 monitoring,方便后续配置网络策略和 RBAC。如果公司里有全局的 Helm 仓库缓存,也可以直接用内部代理地址,这个取决于你的网络环境。初次部署不建议在命名空间上玩花样,越标准越好。

2.4 资源规划与配额习惯

kube-prometheus-stack 默认的资源请求其实不高,但真实跑起来之后内存增长很快。一个中型集群(约 200 个 Pod)下,Prometheus 单副本的内存很容易到 2Gi 以上,如果还开了很多聚合查询,4Gi 都不一定够。所以我不建议在资源紧张的小节点上直接安装。

大致估算的话,整套监控栈至少需要 3 个 CPU 和 4Gi 内存。其中:

  • Prometheus:500m~1000m CPU,1Gi~2Gi 内存
  • Grafana:200m~500m CPU,512Mi~1Gi 内存
  • Alertmanager:100m~300m CPU,256Mi~512Mi 内存
  • node-exporter:每个节点 100m CPU 和 150Mi 内存
  • kube-state-metrics:100m CPU 和 200Mi 内存

建议给监控组件单独打一个 taint 节点,或者至少设置单独的命名空间 ResourceQuota,避免监控和业务抢资源。我见过不少集群因为监控和业务混在一起,业务大促时 Prometheus 被 OOMKilled,结果恰恰在最需要监控的时候监控挂了,非常尴尬。

3. Prometheus部署实操

3.1 编写values.yaml

这里开始进入实际部署。安装 kube-prometheus-stack 不用直接跑默认参数,最好先准备自己的 values.yaml,把存储、资源、访问方式固定下来。一个能跑起来的最小配置大概长这样:

# values-monitoring.yaml global: rbac: create: true prometheus: prometheusSpec: retention: 15d storageSpec: volumeClaimTemplate: spec: storageClassName: local-path accessModes: ["ReadWriteOnce"] resources: requests: storage: 50Gi grafana: adminPassword: admin persistence: enabled: true storageClassName: local-path size: 10Gi service: type: NodePort nodePort: 32001 alertmanager: alertmanagerSpec: storage: volumeClaimTemplate: spec: storageClassName: local-path resources: requests: storage: 10Gi prometheus-node-exporter: hostNetwork: true

简单解释一下:prometheus.prometheusSpec.retention设置数据保留 15 天,storageSpec里的 PVC 指定使用 local-path 这个 StorageClass;Grafana 开了持久化,并映射到一个 NodePort 端口 32001,方便临时访问;Alertmanager 同理也有独立 PVC。prometheus-node-exporter.hostNetwork: true是为了让节点指标采集不走容器网络,直接通过宿主机端口获取。

这里要注意,每个 StorageClass 名字必须和上面第2节确认的结果一致,否则 PVC 创建不出来。还有,如果不打算让 Grafana 用 NodePort,也可以先不开 service 类型,后面通过 port-forward 访问。

3.2 安装命令与启动

配置写好后,执行安装:

helm upgrade --install prometheus prometheus-community/kube-prometheus-stack \ -n monitoring \ -f values-monitoring.yaml

我习惯用 upgrade --install,因为以后修改 values 再次执行就是更新,不会破坏初次安装。如果安装成功,命令会打印一段 NOTES,提示 Grafana 的访问地址和 admin 密码。此时先不要急着关终端,另外开一个窗口持续观察 Pod:

kubectl get pods -n monitoring -w

正常情况下能看到这些 Deployment/StatefulSet 逐步变成 Running:

  • alertmanager-prometheus-k8s-0
  • prometheus-k8s-0
  • prometheus-operator-xxx
  • grafana-xxx
  • node-exporter-xxx(每个节点一个)
  • kube-state-metrics-xxx

如果你看到 prometheus-k8s-0 一直处于 1/2 Running,不要慌,这通常是它的第二容器 config-reloader 还没就绪,等一会儿即可。真正要关注的是 CrashLoopBackOff 或者 Pending,这两个说明有配置或资源问题,后面第 5 节再展开。

3.3 访问Prometheus验证采集

Pod 起来了,链路有没有通还另说。第一步验证,可以先看 Prometheus 自身的 Web UI:

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

打开浏览器访问 localhost:9090,进入 Status -> Targets。这里就是 Prometheus 自动发现到的所有采集目标,正常情况会有几十个 target,状态为 UP。如果大部分是 DOWN,不要继续做后面的事情了,先解决采集失败问题。在 Targets 页面里点任何一个 target,都能看到具体报错,比如 connection refused、context deadline exceeded 等,排查方向很直接。

接着在 Graph 页执行一条最简单的查询:

up

返回结果应该是一系列时间序列,每个 values 是 1 或 0。1 代表该目标最近一次采集成功。如果某个指标为 0,结合 Targets 页面看它为什么失败。

3.4 接入一个业务ServiceMonitor示例

kube-prometheus-stack 自带的是系统组件监控,业务应用不会自动出现在 Targets 里。把业务接进来的标准姿势是创建 ServiceMonitor。比如业务应用 demo-app 已经通过 Service 暴露了 8080 端口,端口名是 metrics,且 /metrics 接口返回 Prometheus 格式指标,然后创建下面这个资源:

apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: demo-app-sm namespace: demo labels: release: prometheus spec: selector: matchLabels: app: demo-app endpoints: - port: metrics interval: 30s

创建之后,Prometheus 会在下一个 reconcile 周期自动发现它,并开始采集。这个例子最关键的细节是metadata.labels.release: prometheus。因为我们安装 chart 时设置的 release 名字叫 prometheus,默认创建的 Prometheus 会要求 ServiceMonitor 一定要带这个 label,才能完成关联。很多人接了业务半天没数据,查到最后就是少了这个 label。

到这里,Prometheus 部署和基本采集链路已经通了。可视化告警里“可视化”前置条件也就有了数据来源,后面可以放心配置 Grafana 和 Alertmanager。

4. 核心配置拆解与访问方式

4.1 资源限制与数据保留

第一次安装能跑,不代表配置能适合生产。我一般会花两天时间观察 Prometheus 的内存和磁盘趋势,再回头调整 values。至少需要关注三个参数:

  • prometheus.prometheusSpec.resources.requests:给调度器一个基础保障值,低于这个值不调度。
  • prometheus.prometheusSpec.resources.limits:给容器设置内存上限,防止 OOM 把节点打挂。
  • prometheus.prometheusSpec.retention/retentionSize:控制数据保留长度。

举一个实际配置示例:

prometheus: prometheusSpec: retentionSize: 40Gi resources: requests: cpu: 500m memory: 1Gi limits: cpu: 1000m memory: 3Gi

retentionSize配合 PVC 容量使用比较合理,比如 PVC 50Gi,数据保存 40Gi 就触发清理,留出压缩和 WAL 的余量。如果只用retention: 15d,面对突然大量指标也可能把磁盘打满,所以我更推荐按体积限制。

4.2 存储与PVC检查

安装后记得检查 PVC 状态:

kubectl get pvc -n monitoring

正常情况下所有 PVC 都是 Bound。如果你发现 Prometheus 的 PVC 一直 Pending,大概率是 StorageClass 名不对或没有对应的 Provisioner。另外,PVC 一旦被 StatefulSet 使用,storageClassName就不能直接修改了,因为它属于不可变字段。要换存储类,只能先把 Prometheus StatefulSet 删除,再把 PVC 删掉,最后用新 values 重建。这个过程会导致已有的监控数据丢失,所以部署前一定要确认存储方案。

另一个和存储相关的细节是,如果你用本地存储类的 ReadWriteOnce,Prometheus 那个 Pod 会固定在某台节点上,这是设计使然。不要试图在单副本模式下让它“漂移”,除非底层存储支持 ReadWriteMany。

4.3 Ingress暴露与Grafana访问

NodePort 用于临时验证还可以,但生产环境更推荐通过 Ingress 暴露,并加一层认证。如果集群里已经有 nginx-ingress,可以在 values 里开启 Grafana Ingress:

grafana: ingress: enabled: true ingressClassName: nginx hosts: - grafana.example.local path: /

注意,Ingress 需要正确设置host,然后在本地 hosts 文件或 DNS 里解析到 Ingress Controller 的地址。否则即使 Ingress 创建成功,也只是空路由。开启 Ingress 之后,建议关闭 NodePort 服务,避免安全组把端口暴露到公网。

Prometheus 和 Alertmanager 同样可以配置 Ingress,不过它们的 Web UI 通常不对普通开发开放,建议保持在集群内访问,需要时用 kubectl port-forward 或临时 NodePort。

4.4 Alertmanager告警通道占位

既然系列标题是“监控告警”,Alertmanager 也必须先就位。chart 默认创建了一个 Alertmanager 实例,但它的 receiver 是 null,也就是说告警只产生,不会发到任何地方。我不想把整篇的重点扯到告警配置上,但这里先留个伏笔——后面写告警规则和通知渠道时会专门讲。

就部署阶段而言,我们只需要确认 Alertmanager 能正常启动,并且可以在Status -> Cluster Status页面看到它自身的状态。之后我们创建 PrometheusRule 时,告警会经过 Alertmanager 按路由规则分发;这一步先让组件存在,后续留到系列第二篇再填接收器。

5. 常见问题与排查实录

5.1 Pod Pending与PVC绑定失败

症状是 prometheus-k8s-0 一直 Pending,事件里出现persistentvolumeclaim "prometheus-prometheus-k8s-db-prometheus-k8s-0" not found或者waiting for a volume to be created。排查命令:

kubectl describe pod prometheus-k8s-0 -n monitoring kubectl get pvc -n monitoring

如果 PVC 处于 Pending,就去查 StorageClass 是否存在,以及 Provisioner 是否正常。有时候是 local-path-provisioner 没装,也有时候是云盘资源不够导致卷创建超时。不解决存储问题,Prometheus 是永远起不来的。

5.2 镜像Pull失败

症状是 Pod 状态 ImagePullBackOff,kubectl describe 里可以看到 Failed to pull image。最直接的原因就是当前节点无法访问镜像仓库,或者镜像 tag 不对。在受控环境里,建议把镜像提前导入节点,或者在 values 中覆盖 image repository 和 tag,指定为内网镜像仓库地址。例如:

prometheus: prometheusSpec: image: repository: registry.internal/prometheus tag: v2.54.1

这里要注意不要指定latest,否则 config-reloader 对比镜像版本时会因为 tag 相同而无法感知更新,出现“配置变了但镜像不更新”的诡异问题。固定 tag 是生产常识。

5.3 时区与Grafana显示问题

监控数据的时间戳大多以 UTC 存储,展示层如果按 GMT,就会比本地时间早 8 小时。Grafana 页面右上角可以临时切换时区,但默认还是 UTC。如果希望一打开就是你本地时间,可以在 values 里设置容器环境变量:

grafana: env: TZ: Asia/Shanghai

Prometheus 本身不需要改时区,因为它的数据时间本来就是 UTC epochs。很多新手非要把 Prometheus 容器内的时区改成北京时间,完全没有必要,反而会增加和其他查询系统对齐时间的复杂度。

5.4 数据采集到了,Grafana却一片空白

这个问题的典型场景是:Prometheus Targets 里能看到业务指标,Grafana 的数据源也能连通,但某个 Dashboard 大盘全是“No data”。排查思路从数据源和变量入手:

  • 检查 Grafana 数据源 URL 是否写成了http://prometheus-operated:9090,注意端口是 9090,不是 80。
  • 检查 Dashboard 的 job 名与 Prometheus 中的 target 标签是否一致。如果 dashboard 期望 job=kubernetes-pods,但你的 ServiceMonitor 没有设置 jobLabel,序列的 job 就会默认为 ServiceMonitor 名。
  • 检查 Dashboard 用的指标名称是否已经改名。常见的是老版本 node-exporter 指标和 1.25+ 版本的指标命名有差异,很多第三方大盘没有及时更新。

遇到这种情况,最好的方法是在 Grafana 的 Explore 页面手动查询{job="..."}看一眼标签是否正确,再反推到 Dashboard 变量。

5.5 高可用多副本的坑

有人一上来就把 Prometheus 副本数调成 2,结果两个副本都启动失败。原因是 Prometheus Operator 创建的 StatefulSet 会用不同的 PVC 名称,如果存储类不支持多副本同名卷、或者节点亲和性不一致,就会导致其中一个副本起不来。另外,Alertmanager 多副本需要开启集群模式,涉及流量复制等配置,也不是加个 replica 就行。普通规模集群,完全没必要一开始就上多副本。先把单副本的数据链路跑稳,后续如果量大了,优先考虑远端存储方案,而不是单纯加副本。

5.6 日常排查命令速查

最后整理一组高频命令,方便出了状况快速定位:

# 查看监控命名空间内所有Pod状态 kubectl get pods -n monitoring -o wide # 查看Prometheus StatefulSet详情 kubectl describe statefulset prometheus-k8s -n monitoring # 查看Prometheus配置是否被Operator同步 kubectl get prometheus prometheus-k8s -n monitoring -o yaml # 查看ServiceMonitor关联关系 kubectl get servicemonitor -n monitoring # 看Prometheus日志 kubectl logs prometheus-k8s-0 -c prometheus -n monitoring

用这些命令基本能覆盖 90% 的启动或采集问题。真正卡住时,不要凭感觉改配置,先看事件和日志,再回头检查 values。

写到这里,Prometheus 在 K8s 里的部署闭环已经完整了。我个人最大的体会是,部署本身并不难,难的是把“监控目标发现、数据采集、持久化、访问入口”这几条线一次理顺。很多人装完 Prometheus 后还是发现监控不可用,往往不是 chart 的问题,而是缺少对整个采集链路的目标感。如果你也是第一次做这件事,建议按这样的顺序验证:先看 Pod 都 Running,再看 Targets 都 UP,接着用 PromQL 查几条指标,最后再看 Grafana 有没有图形。每一步都确认过了,再进入下一步,才不会把问题留给后面的告警阶段。

下一篇我会继续整理告警规则的写法,以及 Alertmanager 如何接入真实通知渠道,到时候会给出可以直接套用的 PrometheusRule 示例。部署阶段留下的这些基础配置如果能固化成模板,后面再搭建新的监控环境,基本上就是复制粘贴和改个存储类名字的事。

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

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

立即咨询