Prometheus 是云原生监控的事实标准。它用 Pull 模型周期性抓取 Kubernetes 集群指标,配合 Grafana 把数据变成可读看板,再用 Alertmanager 把异常推送到钉钉、飞书或邮件。本文从部署到告警,手把手带你搭一套能跑在生产环境的 Prometheus + Grafana 监控告警体系。
Prometheus 为什么是云原生监控首选
传统监控(如 Zabbix)多为 Push 模型:被监控端主动上报。但在 Kubernetes 里,Pod 随时扩缩、IP 不断变化,Push 模型很难跟上拓扑。Prometheus 反过来——服务端主动去拉(Pull),并借助 Kubernetes 服务发现自动感知每一个新 Pod,无需手动登记。指标以时间序列(TSDB)存储,天然适合做”过去 5 分钟 CPU 涨了多少”这类查询。
四种核心指标类型
| 类型 | 语义 | 典型场景 |
|---|---|---|
| Counter | 只增不减的累加值 | 请求总数、错误数 |
| Gauge | 可增可减的瞬时值 | CPU、内存、队列长度 |
| Histogram | 样本分布 + 分桶计数 | 请求延迟分布 |
| Summary | 分位数近似计算 | P95 / P99 延迟 |
写埋点时先想清要算什么:算”速率”用 Counter,算”当前值”用 Gauge,算”延迟分布”用 Histogram。选错类型,后面的 PromQL 会非常别扭。
在 Kubernetes 部署监控栈
手动拼 Prometheus、Alertmanager、Grafana、node-exporter 很繁琐。社区把这一整套封装成了 kube-prometheus-stack(Operator 形式),开箱即带大量 ServiceMonitor 与官方看板。用 Helm 一条命令即可拉起:
# 添加仓库并部署整套监控栈
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo update
helm install kps prometheus-community/kube-prometheus-stack \
-n monitoring --create-namespace
# 验证核心组件都起来
kubectl get pods -n monitoring
kubectl get svc -n monitoring | grep -E 'prometheus|grafana|alertmanager'
装好后,集群节点、控制面、核心组件的指标已经被自动抓取。你只需关心”自己的业务怎么暴露 /metrics”。若你的服务跑在 Docker Compose 而非 K8s,可参考我们之前的《Docker Compose 一键编排》先把服务稳定跑起来,再考虑上 K8s 监控。
配置抓取:从 Node 到 Pod
Prometheus 通过 scrape_configs 决定抓谁。在 Operator 体系里,你不用改 Prometheus 主配置,而是声明一个 ServiceMonitor 自定义资源,Operator 会自动把它翻译成抓取规则。下面让 Prometheus 每 15 秒抓取带 app: my-app 标签的服务的 /metrics:
# ServiceMonitor:让 Prometheus 自动抓取某服务的 /metrics
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: my-app
namespace: monitoring
spec:
selector:
matchLabels:
app: my-app
endpoints:
- port: http
path: /metrics
interval: 15s
业务侧只要用客户端库(如 Java 的 Micrometer、Go 的 promhttp)在 /metrics 暴露指标,并给 Service 打上对应 label,数据就会自动流入 Prometheus。
写第一条告警规则
告警规则用 PromQL 表达”什么算异常”。for 表示持续多久才触发,避免抖动误报。下面两条覆盖了最常见的两个场景:实例失联与 Pod 频繁重启——后者往往连着《CrashLoopBackOff 排查》里提到的容器反复崩溃。
groups:
- name: k8s-alerts
rules:
- alert: 实例宕机
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} 已失联 2 分钟"
- alert: Pod频繁重启
expr: increase(kube_pod_container_status_restarts_total[10m]) > 3
for: 5m
labels:
severity: warning
annotations:
summary: "{{ $labels.namespace }}/{{ $labels.pod }} 近 10 分钟重启超过 3 次"
规则写好用 promtool check rules 校验语法,再热加载。想看哪些 Pod 卡在调度阶段导致没指标,可对照《K8s Pod Pending 排查》一起排查。
用 Grafana 把指标变成看板
Prometheus 自带的表达式浏览器适合临时查数,但日常盯盘靠 Grafana。Grafana 接上 Prometheus 数据源后,导入官方看板(Node Exporter Full 编号 1860、K8s 集群概览 315)就能直接看到节点与集群水位。数据源可以用配置即代码(provisioning)落库,避免人工点界面:
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
url: http://kps-kube-prometheus-stack-prometheus:9090
access: proxy
isDefault: true
Grafana 的数据库密码、钉钉机器人 token 这类敏感信息,建议用《External Secrets Operator》从云厂商密钥管理同步进来,而不是写死在明文的 ConfigMap 里。监控体系本身也应纳入 GitOps——可参考《ArgoCD 实战》把上述 YAML 全部版本化管理。
告警触达:Alertmanager 路由
Prometheus 只负责”产生告警”,真正去重、分组、静默、路由到接收端的是 Alertmanager。下面把 critical 级别单独路由到一个”加急”钉钉群,普通告警走默认群,group_wait 控制合并窗口,避免告警风暴刷屏:
route:
receiver: dingtalk
group_by: ['alertname', 'namespace']
group_wait: 30s
routes:
- match:
severity: critical
receiver: dingtalk-urgent
receivers:
- name: dingtalk
webhook_configs:
- url: https://oapi.dingtalk.com/robot/send?access_token=xxxx
- name: dingtalk-urgent
webhook_configs:
- url: https://oapi.dingtalk.com/robot/send?access_token=yyyy
除了钉钉,Alertmanager 原生支持 Email、Slack、Webhook、PagerDuty 等。把监控接进《GitHub Actions》这类 CI 流水线后,还能在发布后自动校验关键指标是否异常波动。
上线前检查清单
- Prometheus 的 Targets 页面里,业务 endpoint 状态为 UP;
- Alertmanager 里能看到告警在 Pending / Firing 切换,而非一直空;
- Grafana 面板有真实曲线,不是空图;
- 故意触发一次告警,确认接收端真的收到消息(先小流量验证,再全量);
- 用
kubectl port-forward临时暴露 UI 排障,长期应走 Ingress + 鉴权,别裸奔公网。
PromQL 实战:从速率到分位数
监控真正值钱的是”会查”。Prometheus 查询语言 PromQL 里,rate() 算区间平均速率,irate() 看瞬时变化更灵敏,适合做实时图表。下面几条是日常最高频的查询,建议直接存进 Grafana 看板:
# 过去 5 分钟每秒请求数(QPS)
rate(http_requests_total[5m])
# 请求成功率(排除 5xx 后占比)
sum(rate(http_requests_total{code!~"5.."}[5m]))
/ sum(rate(http_requests_total[5m]))
# P95 请求延迟(依赖 Histogram 分桶)
histogram_quantile(0.95,
rate(http_request_duration_seconds_bucket[5m]))
# 节点 CPU 使用率(扣除 idle)
1 - avg by(instance)(rate(node_cpu_seconds_total{mode="idle"}[5m]))
两个坑必须提醒:Histogram 的分桶要在埋点端提前规划好,否则 histogram_quantile 算不出真实分位数;Counter 永远配 rate() 使用,直接对 Counter 做加减会得到被重启重置污染的错误结果。指标类型选错,PromQL 就会处处别扭。
指标保留与长期存储
默认 Prometheus 本地 TSDB 只保留 15 天,且单机容量有上限。生产环境建议把 retention 调到 30 天,关键指标再通过 remote_write 转存到长期存储(Thanos、Cortex 或 Grafana Mimir),既能降采样省钱,又能跨集群统一查询。示意配置如下:
# Prometheus 远程写(接入 Mimir 长期存储,示意)
remoteWrite:
- url: https://mimir.example.com/api/v1/push
queue_config:
max_samples_per_send: 2000
write_relabel_configs:
- source_labels: [__name__]
regex: 'node_.*|kube_.*'
action: keep
长期存储本身也应纳入前面的 Grafana 看板与告警体系,形成”采集 — 存储 — 可视化 — 告警”的完整闭环。监控不是一次性工程,而是随业务演进持续调参的能力。
监控体系的四个常见误区
搭好栈只是第一步,很多团队倒在”用”上。避开下面四个坑,监控才真正有用:
- 只监控不告警:看板做得漂亮却没人盯,异常发生时一片静默,等于没监控。监控的终点是”该知道的人知道”。
- 阈值拍脑袋:CPU 80% 一刀切,正常抖动也狂叫,久而久之告警被静音(告警疲劳)。阈值应基于历史基线,对核心服务用多档分级。
- 指标基数爆炸:每个接口都打全维度 label,基数失控会把 TSDB 直接打挂。只保留真正用于聚合与下钻的标签。
- 当一次性工程:业务变了规则没变,等出事才发现看板早失效。告警规则要随发布一起评审、一起进 Git。
小结
一套可落地的云原生监控 = Prometheus 抓数据 + Grafana 做可视化 + Alertmanager 管触达。先用 kube-prometheus-stack 快速起栈,再用 ServiceMonitor 接入业务指标,最后用 PromQL 把”异常”定义成告警规则。监控不是上线后的点缀,而是你敢在凌晨改生产、出了问题能 5 分钟定位的底气。




