
简介在云原生环境中K8S集群规模扩大后系统监控与告警成为运维刚需。这套基于kube-prometheus-stack的部署资源合集面向云原生、SRE及K8S运维人员覆盖Prometheus、Prometheus Operator、Alertmanager、Grafana和Prometheus Adapter等核心组件配置适合需要快速搭建集群监控体系、定位告警链路并理解组件协同的中高级工程师。资源包共299个文件以272个yaml配置为主辅以tpl模板、md说明文档、helmignore规则文件及Chart.lock整体仅约690KB轻量且结构清晰便于按模块快速查阅与复用。目前已有783人学习下载对生产环境实践和二次开发有较高参考价值。合集中包含custom-dashboard.json与完整Helm图表相关文件可帮助读者理解ServiceMonitor服务发现机制、告警规则编写、数据保留策略和Prometheus Adapter的HPA联动配置快速复用并二次调整监控配置降低从零部署成本提升对集群状态的掌控能力为集群稳定性保障提供有力支撑。1. 基于 kube-prometheus-stack 部署监控告警系统从 Helm 安装到告警落地的完整拆解记得有一回某公司线上集群的一个节点内存被打满kubelet 开始驱逐 Pod但因为当时只搭了基础的 Metrics Server没有任何告警通知直到业务方反馈接口超时才定位到问题。事后复盘最缺的不是监控数据而是一套「能发现问题、能通知到人」的完整告警链路。kube-prometheus-stack 就是解决这个问题的开源组合它把 Prometheus、Prometheus Operator、Alertmanager、Grafana、Prometheus Adapter 打包成一个 Helm Chart一次部署就能拿到采集、存储、可视化、告警四件套。适合正在维护生产集群的运维也适合刚接触云原生监控、想用社区最佳实践而不是自己拼装组件的开发者。这篇笔记按我实际部署的顺序来写组件怎么协作、values 怎么改、ServiceMonitor 怎么写、Alertmanager 怎么配以及那些踩过才知道的坑。2. 组件架构与选型为什么这套 Chart 能省掉一半工作量2.1 核心组件分工kube-prometheus-stack 不是一个单体应用而是把多个开源组件拼成一套「开箱即用的监控循环」。理解每个组件在链路里的位置后面配置才不会乱。链路大致是采集端Prometheus ServiceMonitor→ 存储端Prometheus TSDB→ 告警端Prometheus 规则评估 → Alertmanager 通知→ 展示端Grafana 可视化。Prometheus时序数据库负责抓取指标、存储数据、执行 PromQL 和告警规则。默认部署为 StatefulSet通过prometheus.yml配置采集目标。Prometheus Operator用 CRD 管理 Prometheus 实例。它监听 ServiceMonitor、PodMonitor、PrometheusRule 等自定义资源自动把变更转成 Prometheus 配置文件。这意味着你不需要手动改prometheus.yml而是通过 kubectl 操作 CRD 来声明式管理采集和告警规则。Alertmanager接收 Prometheus 推送的告警做分组、抑制、静默然后发送到邮件、企业微信、Slack 等渠道。它负责解决「告警风暴」和「重复报警」的问题。Grafana数据可视化默认预置了 kubernetes 相关的仪表盘。可以直观看节点 CPU、内存、Pod 状态、网络流量等信息。Prometheus Adapter把 Prometheus 中的自定义指标暴露成 Kubernetes 的 Metrics API这样 HPA 就能根据「每秒请求数」「消息队列积压数」等业务指标扩缩容。2.2 为什么选 Helm Chart 而不是手动拼装有段时间我习惯手动部署先装 Prometheus再装 Operator再手动配 Grafana。三套 YAML 来自不同项目的不同维护节奏版本一乱就翻车。kube-prometheus-stack 用 Helm Chart 把版本锁定在一起解决了三个实际问题版本兼容性Chart 内部会约束 Prometheus、Alertmanager、Grafana 的镜像版本默认配置下组件之间 API 兼容不会出现 Operator 支持的新 CRD 字段和 Prometheus 旧版本不匹配的问题。升级可回退Helm 自带的helm upgrade和--history-max机制升级失败可以直接回滚比手动覆盖 YAML 安全得多。参数集中化Chart 把所有可配置项暴露成 values.yaml 的字段管理 Grafana 的 admin 密码、持久化大小、告警渠道等都在一个文件里改。有一个细节值得注意Chart 部署时会在集群里创建 CRD。CRD 的生命周期和普通资源不同Helm 默认不删除 CRD卸载时需谨慎处理。3. 部署 kube-prometheus-stack从仓库准备到自定义 values3.1 前置检查与基础操作开始前先确认环境Kubernetes 集群版本 1.26 或更高我用某测试集群验证过1.24 版本会碰到升级到新版 CRD 的兼容问题Helm 版本 3.12。集群要有足够的资源Prometheus 和 Grafana 加上 Alertmanager默认配置大约需要 2C4G 的可用容量如果资源紧张把 Prometheus 副本数改为 1关闭部分 Grafana 插件。第一步添加官方仓库并更新索引helm repo add prometheus-community https://prometheus-community.github.io/helm-charts helm repo update helm search repo prometheus-community/kube-prometheus-stack -l | head -5逻辑prometheus-community 是社区维护的 Chart 仓库与其他第三方仓库不同它提供的 kube-prometheus-stack 是当前最活跃、跟随 upstream 最新版本发布的来源。helm search ... -l看历史版本目的是避免直接安装最新版遇到未验证的兼容问题。参数说明-l显示所有历史版本默认只显示最新。第二步创建命名空间并拉取默认配置kubectl create ns monitoring helm show values prometheus-community/kube-prometheus-stack /tmp/default-values.yamlhelm show values输出的是 Chart 维护者定义的默认值。我一般会先存一份做参照然后用-f传自定义 values 覆盖而不是直接改默认文件。3.2 自定义 values.yaml 的核心参数直接安装默认 Chart 能跑起来但离「生产可用」还有距离。我会在 values 里至少改这几个块# /tmp/prod-values.yaml global: rbac: create: true grafana: adminPassword: admin ingress: enabled: true ingressClassName: nginx hosts: - grafana.example.com persistence: enabled: true storageClassName: standard-rwo size: 10Gi prometheus: prometheusSpec: retention: 15d replicas: 1 resources: requests: memory: 2Gi cpu: 500m limits: memory: 4Gi cpu: 2 storageSpec: volumeClaimTemplate: spec: storageClassName: standard-rwo resources: requests: storage: 50Gi alertmanager: enabled: true alertmanagerSpec: replicas: 1 storage: volumeClaimTemplate: spec: storageClassName: standard-rwo resources: requests: storage: 5Gi prometheusOperator: resources: requests: cpu: 100m memory: 256Mi逻辑说明prometheus.prometheusSpec.retention控制数据保留时长15 天是我在存储成本和数据回溯时长之间的折中storageSpec.volumeClaimTemplate让 Prometheus 数据落到持久卷而不是 Pod 重建即丢grafana.adminPassword是 Grafana 管理员密码这里明文写在 values 里生产环境可以用--set grafana.adminPasswordFromSecret引用 SecretChart 版本 50 支持这个参数。参数说明resources.limits不能设置得太小而 kill 掉 PodPrometheus 在规则重载和大量查询时会有内存峰值limits 设 4Gi 是经验值。storageClassName根据你自己的集群存储类来填我用的是 standard-rwo如果你的集群是local-path或者云厂商默认的要改成对应名字。3.3 安装与状态验证helm upgrade --install kube-prometheus-stack \ prometheus-community/kube-prometheus-stack \ -n monitoring \ -f /tmp/prod-values.yaml \ --version 61.9.0安装时用--version锁定版本号避免之后别人执行helm upgrade时误拉到不兼容的新版本。等待一下然后检查关键 Pod 的状态kubectl -n monitoring get pods -l app.kubernetes.io/instancekube-prometheus-stack kubectl -n monitoring get crd | grep monitoring预期看到prometheus-operator、alertmanager-*、prometheus-*、grafana-*的 Pod 处于 Running 状态CRD 列表里出现servicemonitors.monitoring.coreos.com、prometheusrules.monitoring.coreos.com等。如果 Prometheus Pod 一直 CrashLoopBackOff先kubectl -n monitoring logs prometheus-kube-prometheus-stack-prometheus-0 --tail50看日志里是否有存储权限、配置错误的信息。验证 Grafana 能访问后下一步是让这套系统真正“看到”你的业务指标而不是只监控集群本身。4. 定制采集目标与告警通知ServiceMonitor、PrometheusRule、AlertmanagerConfig 三件套4.1 ServiceMonitor 打通业务指标采集集群自带的监控kubelet、cAdvisor、node-exporter在安装时已自动配置好。要让 Prometheus 采集你自己业务的/metrics端点需要定义 ServiceMonitor。它的作用是把「哪个 Service 的哪个端口需要被采集」告诉 Prometheus Operator再由 Operator 转成 Prometheus 的抓取配置。# k8s-monitor-example-service-monitor.yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: example-api namespace: business spec: selector: matchLabels: app: example-api endpoints: - port: metrics interval: 30s path: /metrics scheme: http namespaceSelector: matchNames: - business逻辑说明selector.matchLabels是必须的——它决定了哪些 Service 会被匹配到。这里的app: example-api是一个业务应用 Service 的标签。endpoints里port必须是 Service 里定义的端口名目标 Pod 的 metrics 接口默认在 9100 或 8080 等规则由你自己暴露的端点决定。namespaceSelector.matchNames限制了监听范围如果你的 Prometheus 是集群级部署在 monitoring 命名空间但权限到 all这个字段可以省略但写上更安全避免误采集。参数说明interval建议不小于 15s采集太频繁会消耗大量存储如果业务端点的 metrics 数据量大把 interval 调到 60s 甚至 120s。这个资源创建后可以等 30 秒再到 Prometheus UI 的 Targets 页面确认服务已被发现。如果状态一直是 Down优先查三个方向Service 端口名是否匹配、endpoints 里的 path 是否存在、目标 Pod 有没有运行在期望命名空间。4.2 PrometheusRule 自定义告警规则自带 Chart 里包含了一批 Kubernetes 告警规则比如节点 CPU 高、Pod 反复重启。但业务告警比如某接口 QPS 骤降需要自己写 PrometheusRule。告警规则文件由 Prometheus Operator 衔接Prometheus 会定期评估这些规则并决定是否触发告警。apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: business-api-rules namespace: monitoring spec: groups: - name: business-api rules: - alert: ApiRequestLatencyHigh expr: | histogram_quantile(0.95, sum(rate(http_request_duration_seconds_bucket{appexample-api}[5m])) by (le) ) 1.5 for: 10m labels: severity: warning annotations: summary: API 95% 延迟超过 1.5s description: 实例 {{ $labels.pod }} 最近 5 分钟 P95 延迟为 {{ $value }}s逻辑说明告警规则分四部分——alert是告警名expr是 PromQL 表达式for表示连续满足多久才触发labels和annotations是告警附带的元数据。上面这个例子计算了最近 5 分钟内 95 分位延迟如果连续 10 分钟超过 1.5 秒就触发告警。for: 10m这个参数很关键它避免了瞬时毛刺导致的误报。参数说明expr里的http_request_duration_seconds_bucket需要业务端点是 Histogram 类型指标如果你的业务用的是 Summary 类型那样无法直接算分位。severity: warning是自定义 label可以在 Alertmanager 里按优先级做分组后面会用到。4.3 AlertmanagerConfig 把告警发到企业微信Alertmanager 本身定义通知渠道也是使用 CRD 来配置。不同的接收方对应不同的配置。以企业微信为例Chart 65 版本开始推荐用 AlertmanagerConfig CRD 而不是修改 SecretapiVersion: monitoring.coreos.com/v1alpha1 kind: AlertmanagerConfig metadata: name: wechat-alert-config namespace: monitoring spec: route: receiver: wechat-alert groupBy: [alertname, namespace] groupWait: 30s groupInterval: 5m repeatInterval: 4h receivers: - name: wechat-alert wechatConfigs: - apiURL: https://qyapi.weixin.qq.com/cgi-bin/ corpID: your-corpid secret: key: wechat-secret name: wechat-secret agentID: 1000002 toUser: all逻辑说明AlertmanagerConfig会被 Alertmanager 自动加载但默认 Chart 配置下Alertmanager 的alertmanagerConfigSelector只会监听带特定 label 的 AlertmanagerConfig。确保这个 CRD 上有 label并在 Alertmanager spec 中通过alertmanagerConfigSelector指定匹配。参数说明groupBy将相同的告警分组避免同一时刻多个 Pod 都报同一个告警groupWait是分组前等待时间用来合并瞬间产生的同类告警repeatInterval表示已发送的告警间隔多久再发一次提醒4 小时是个合理值不会刷屏也不会漏通知。secret是引用 Kubernetes Secret 中的值具体字段视企业微信 API 要求而定。配置完成后可以手动触发一条测试告警比如把某个 Deployment 副本数缩到 0观察企业微信是否收到通知。这一步过了整套告警链路就通了。5. 避坑与排查生产端部署三个月踩过的五个坑5.1 现象Helm 安装卡在 CRD 创建超时用 helm 安装时长时间卡在Wait-For-CRD然后超时失败。 原因集群的 API Server 承载压力过大或者 CRD 太大kube-prometheus-stack 的 CRD 有几百 KB创建超时。 解决先手动应用 CRD 再安装。在 Chart 目录下运行kubectl apply -f charts/kube-prometheus-stack/crds/然后再执行 helm install加--skip-crds跳过 Helm 创建 CRD。从那以后我搭建新集群时都会先做这一步省了 5 分钟等待时间。5.2 现象Prometheus Pod 反复重启日志提示 PVC 冲突在云厂商环境StorageClass 是standard-rwo但 Prometheus Operator 创建的 PVC 绑不上节点Pod 调度失败或一直 ContainerCreating。 原因云厂商的卷是区域性资源当 Pod 迁移到另一个可用区时PVC 无法跨区挂载。 解决把 Prometheus 固定调度到有卷的节点加上 nodeSelector 或 nodeAffinity。另一个更通用的解法如果数据丢失可以容忍就不用 PVC直接改为内存存储把storageSpec删除测试环境我常这样干生产不要这么玩。5.3 现象Grafana 仪表盘变量为空图表显示 No data新装的 Grafana选好集群节点发现 CPU、内存图表没有数据。 原因Grafana 的数据源是自动配置的但 Prometheus 实例名变了或者 Gafana 用的是默认 datasource UID和实际创建的不一致。 解决检查 Grafana 的 datasource 配置Confguration → Data Sources → PrometheusURL 应为http://kube-prometheus-stack-prometheus.monitoring:9090如果 URL 错就手动改。另一个常见原因是 Grafana 版本和 Chart 内置的 dashboard json 不兼容解决方式是升级 Grafana 镜像或者把 dashboard json 里的 version 改低一点。5.4 现象自定义 ServiceMonitor 不生效目标页一直 0/0创建了 ServiceMonitor但 Prometheus Targets 页面看不到任何目标。 原因三个高频坑Selector 没匹配到 Service端点端口名对不上或者 Prometheus 的serviceMonitorSelector没有选到你的 ServiceMonitor。第三个坑最隐蔽——你在 monitoring 命名空间的 ServiceMonitor理论上会被匹配但如果你的 values 里prometheus.prometheusSpec.serviceMonitorSelector配置了matchLabels它就只会选中带那个 label 的 ServiceMonitor。 解决给 ServiceMonitor 加上和匹配规则一致的 label比如app.kubernetes.io/part-of: kube-prometheus-stack。检查顺序先kubectl get servicemonitor -n business确认存在再kubectl describe prometheus -n monitoring看 spec 里的serviceMonitorSelector最后去 Prometheus UI 的 Targets 页面看。5.5 现象告警通知刷屏一小时内收到上百条节点故障时告警风暴把个人微信推爆。 原因Alertmanager 的groupBy粒度太细没按告警名分组每条告警单独发送同时缺少抑制规则。 解决把 groupBy 的值改为[alertname, namespace]设置groupWait: 30s。再加一条抑制规则如果节点已经 Down则抑制该节点上所有 Pod 的告警这样核心原因一条消息就够了。抑制规则的配置在 AlertmanagerConfig 的inhibitRules字段里。6. 从监控到验证用 PromQL 调优告警阈值给告警响应提速部署完成、告警能推送到手机这只是开始。我在某次故障演练中吃过亏一个业务异常Prometheus 已经触发了几条相关告警但一线处理的人要花几分钟在 Grafana 上拼 PromQL 才能定位问题。从那以后我养成了一个习惯每个告警规则的 annotations 里把「怎么看这条告警」的方法直接写进去并配上调试 PromQL 的技巧。6.1 用 PromQL 验证告警阈值先创建一个临时 PrometheusRule故意把阈值调得很低触发告警验证完再改回正常值apiVersion: monitoring.coreos.com/v1 kind: PrometheusRule metadata: name: debug-rule namespace: monitoring spec: groups: - name: debug rules: - alert: DebugAlert expr: vector(1) 0 annotations: description: 调试告警验证链路vector(1) 0是一个永远为真的表达式马上会触发这个告警能在不依赖业务指标的前提下测试 Alertmanager 的编排是否正确。测试完直接kubectl delete prometheusrule debug-rule删掉。6.2 通用的告警响应技巧方法一给告警附上诊断 PromQL。在 annotations 里加一条runbook或troubleshooting字段写一个查询语句比如节点内存告警就写topk(10, container_memory_working_set_bytes{nodexxx, container!})这样收到告警的人复制到 Grafana 就能直接看。方法二用记录规则加速复杂查询。如果某条 PromQL 特别重比如跨多个 namespace 聚合并计算分位数每次查询都实算会很慢用 recording rule 预计算。默认 Chart 自带了一些以kube_前缀的规则可以在 Prometheus UI → Status → Rules 里查看。方法三验证告警 title 是否包含定位信息。Alertmanager 的通知模板里把实例 IP、命名空间、Pod 名放到标题里。这样手机弹窗就能看到是谁出了问题不用点进详情才知道。6.3 一个验证告警的终验习惯每次改完告警规则我都会跑一遍相同的验证流程# 触发测试告警 kubectl -n monitoring exec alertmanager-kube-prometheus-stack-alertmanager-0 -- \ amtool --alertmanager.urlhttp://localhost:9093 alert add \ --annotationmessagetest \ --annotationnamespacedefault \ --labelalertnameTestAlert \ --labelseveritycritical \ --endtime.Now().Add(time.Hour)等待 60 秒确认通知渠道收到测试消息然后清除kubectl -n monitoring exec alertmanager-kube-prometheus-stack-alertmanager-0 -- \ amtool --alertmanager.urlhttp://localhost:9093 alert expire TestAlert这套流程跑顺之后我对告警真正放心了。从那以后每次搭新的集群或接新的业务我都强制走一遍「部署 → 导入仪表盘 → 模拟故障 → 确认推送 → 调阈值」的闭环改规则时顺手把诊断 PromQL 写进 annotations。监控系统最怕的不是不会配置而是配完了没人敢说「它一定会响」。希望这篇笔记帮你少踩几个坑把监控告警真正用起来。本文还有配套的精品资源点击获取