周五晚上十一点,手机连着震动三次,值班群里有人发了张截图:支付服务核心业务的CPU使用率拉到顶,但打开Grafana Dashboard才发现只有一条孤零零的曲线,没有版本对比、没有上下游调用关系、连是哪个节点都分不清,翻了五分钟面板才定位到告警来源。事后复盘,监控这套东西其实早就装了——Prometheus和Grafana都在跑,数据也一直在采集,但“能跑”和“好用”之间,隔着服务发现、指标口径、告警收敛、面板设计这些几乎没人一次性讲透的东西。
这篇文章就围绕云原生监控这条主线,从Prometheus为什么能成为事实标准开始,把采集端、查询端、可视化端、告警端一整套链路里真正影响落地效果的细节拆开讲。适合正在搭监控体系的运维工程师、刚接手Kubernetes集群的开发者,以及想把自己的服务从“裸奔”状态拉起来的团队参考。
1. 为什么云原生监控的默认答案总是 Prometheus
先聊一个反直觉的事实:Prometheus 不是性能最强的监控系统,也不是功能最全的,但它在云原生环境里就是有压倒性优势,背后是架构设计取向的问题。
1.1 拉模型:监控系统主动出击带来的连锁优势
传统监控系统(比如Zabbix)走的是推模型,Agent把数据上报到Server,服务端负责接收和存储。Prometheus反过来,它是拉模型:Prometheus Server按配置的时间间隔去目标端点的 /metrics 接口抓取数据。
这个“拉”的设计在Kubernetes里带来了几个实打实的好处。第一,目标发现不再靠人工维护IP列表,而是直接对接Kubernetes API,Pod创建、销毁、漂移,Prometheus都能通过服务发现自动感知。第二,拉模型天然适合隔离故障域——监控系统挂了不影响被监控的业务,业务挂了监控系统也能第一时间发现它在列表里消失。第三,数据抓取行为本身可以被监控,比如 up == 0 这个经典表达式,就是靠拉模型才有的。
推模型没有存在的价值吗?也不是。Pushgateway这种组件就是给短生命周期任务准备的,比如批量计算任务,跑完就退出了,来不及被拉取。但我个人的经验是,业务指标尽量别依赖Pushgateway,因为它是单点,而且指标过期清理不及时很容易造成数据混乱。能用拉的就别用推的。
1.2 指标、标签与时间序列:理解数据结构才能写出高效查询
很多人在PromQL里写不出高效查询,根因是没理解它的底层数据结构。Prometheus存储的是一条条时间序列(Time Series),每条序列由两部分组成:
- 指标名(Metric Name),比如
http_requests_total - 一组标签(Labels),比如
{method="GET", endpoint="/api/user", status="200"}
换句话说,http_requests_total{method="GET", endpoint="/api/user", status="200"} 是一条独立的时间序列,http_requests_total{method="POST", ...} 是另一条。
标签才是监控系统里的核心抽象,它决定了你能从哪些维度切数据。这就像电商系统里的SKU和SPU——指标名是SPU,标签组合才是SKU。理解这一点之后,很多问题就通了:
- 为什么两个表达式查出来的数值对不上?因为时间序列的匹配逻辑是标签完全一致,差一个标签就是两条不同的线。
- 为什么某些查询特别慢?因为标签基数太大,扫的时间序列太多。
- 为什么面板上出现断断续续的曲线?因为标签组合变化,导致序列中断,典型例子是容器重建后
instance标签变了。
1.3 四种指标类型:Counter、Gauge、Histogram、Summary
指标类型是理解PromQL语义的基石,很多新手写查询出错就是因为类型没搞懂。
| 类型 | 含义 | 典型场景 | 核心注意点 |
|---|---|---|---|
| Counter | 单调递增计数器 | 请求数、错误数、CPU时间累计 | 只在重启时清零,查询要用 rate() 或 increase() |
| Gauge | 可升可降的瞬时值 | CPU使用率、内存使用量、当前连接数 | 直接使用即可,不要套 rate() |
| Histogram | 直方图,客户端分桶统计 | 请求延迟、响应大小 | 配合 histogram_quantile() 计算分位数,需要预留 _bucket 序列 |
| Summary | 摘要,客户端预计算分位数 | 同上 | 和Histogram类似,但分位数由客户端算好,无法聚合 |
Counter 是最容易出问题的。直接用 http_requests_total 画图,得到的是不断上涨的曲线,没有任何业务含义。必须配合 rate(http_requests_total[5m]) 才能表示每秒请求数。而Gauge类型如果套了 rate(),常常会出现负数或剧烈波动,因为Gauge本来就能上下变化。
Histogram 是另一个重灾区。要计算P99延迟,正确写法是:
promql复制histogram_quantile(0.99, sum(rate(my_request_duration_seconds_bucket[5m])) by (le))
很多人忘了 le 这个标签,导致没有维度可以聚合。这些都建立在对数据结构的理解之上,所以我把这一节放在最前面——所有后续的操作、排错、优化,最后都会回到这里。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 从零部署:选对安装姿势比执行命令更重要
部署Prometheus看起来简单,一个二进制文件就能跑起来,但在Kubernetes环境里,安装姿势直接决定了后续的维护成本和功能边界。
2.1 三种部署方式怎么选
我见过团队为了简单,直接在K8s集群里用Deployment裸跑一个Prometheus容器,配置靠挂载ConfigMap,发现目标靠手工写 static_configs。短期能跑,长期会非常痛苦,因为采集目标在云原生环境里是动态的,手工维护静态列表等于放弃了Kubernetes最核心的价值。
主流部署方式有三种,我做了个对比:
| 部署方式 | 优点 | 缺点 | 适用场景 |
|---|---|---|---|
| 二进制/单容器部署 | 简单直接,排查方便 | 没有服务发现,需要手工管理配置 | 测试环境、单机监控 |
| Helm Chart部署(prometheus-community/kube-prometheus-stack) | 全家桶,自带node-exporter、kube-state-metrics、Grafana、Alertmanager | 依赖Helm版本,升级需谨慎 | 大多数生产环境首选 |
| Prometheus Operator / 自定义CRD | 声明式管理采集配置,支持ServiceMonitor | 学习曲线陡峭,概念多 | 大规模多团队共享监控平台 |
生产环境我推荐Helm Chart方案,它底层就是Operator,但帮你把全家桶都初始化好了。如果你已经熟悉Operator的CRD模型,直接上Operator当然更灵活。
2.2 用 Helm 在 Kubernetes 里部署全家桶的完整步骤
以 prometheus-community/kube-prometheus-stack 为例,核心步骤就四步:
bash复制# 添加仓库
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
# 创建命名空间
kubectl create ns monitoring
# 安装全家桶
helm install prometheus prometheus-community/kube-prometheus-stack \
--namespace monitoring \
-f values.yaml
真正的工作量在 values.yaml。我通常会在里面覆盖这几个关键配置:
`
