Kubernetes 监控实战:使用 Alertmanager 实现邮件告警、分组路由与告警抑制
前言
在前面的监控实践中,我们已经通过 ServiceMonitor 让 Prometheus 抓取了 NVIDIA DCGM Exporter 和 vLLM 的指标,并使用 PrometheusRule 编写了 GPU 与推理服务告警规则。
但是,Prometheus 负责的是“判断告警是否成立”,并不负责完成告警分组、通知路由、静默、抑制以及邮件发送。Alertmanager 正是用来处理这些工作的组件。Prometheus 官方也将两者的职责进行了区分:Prometheus 通过告警规则识别当前故障,Alertmanager 负责后续的聚合、限流、静默、依赖处理和通知分发。
本文基于 Prometheus Operator 提供的 AlertmanagerConfig CRD,完成以下功能:
普通告警
→ 发送到默认邮箱
带有 notify_group="ai-infra" 标签的告警
→ 发送到 AI Infra 专用邮箱
Watchdog 心跳告警
→ 保留在 Alertmanager 中,但不发送邮件
同一 namespace、同一 alertname:
critical 告警触发
→ 抑制 warning 和 info 通知
告警恢复
→ 发送恢复邮件
本文使用的实验环境如下:
Kubernetes 命名空间:monitoring
Prometheus:prometheus-k8s
Alertmanager:alertmanager-main
配置方式:Prometheus Operator AlertmanagerConfig
通知方式:QQ 邮箱 SMTP
业务监控对象:vLLM 推理服务
基础设施监控对象:NVIDIA GPU
一、Prometheus 和 Alertmanager 的告警链路
完整链路如下:
业务服务或 Exporter
↓
Prometheus 抓取指标
↓
PrometheusRule 计算告警条件
↓
告警持续满足 for 后进入 FIRING
↓
Prometheus 将告警发送给 Alertmanager
↓
Alertmanager 执行分组、去重、路由、抑制
↓
通过 SMTP 发送邮件通知
Prometheus 告警规则常见的状态包括:
-
INACTIVE:当前表达式不满足告警条件。 -
PENDING:表达式已经满足,但持续时间还没有达到for。 -
FIRING:表达式持续满足的时间已经达到for,告警正式触发。
PENDING 阶段主要由 Prometheus 自己维护;当告警进入 FIRING 后,Prometheus 才会把它作为需要通知的告警发送给 Alertmanager。Prometheus 官方文档也说明,for 用于要求告警条件持续满足指定时间,在达到该时间前告警处于 pending 状态。
下面是本次实验中 Prometheus 已加载的 vLLM 告警规则:

二、检查 AlertmanagerConfig 是否能够生效
2.1 检查 Alertmanager 运行状态
先确认 Alertmanager Pod、Service 和自定义资源正常存在:
kubectl -n monitoring get pod | grep alertmanager
kubectl -n monitoring get svc | grep alertmanager
kubectl -n monitoring get alertmanager
在 Prometheus Operator 环境中,Alertmanager 自定义资源负责声明 Alertmanager 实例,Operator 再根据该资源创建 StatefulSet、Pod 和配套 Service。
2.2 检查 AlertmanagerConfig CRD 版本
AlertmanagerConfig 的 API 版本不能直接照抄其他环境,必须以当前集群已经安装并处于 served=true 状态的版本为准:
kubectl get crd alertmanagerconfigs.monitoring.coreos.com \
-o jsonpath='{range .spec.versions[?(@.served==true)]}{.name}{"\n"}{end}'
本次实验返回:
v1alpha1
因此本文使用:
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
如果你的集群返回其他版本,应同步修改 YAML 中的 apiVersion,不能只修改 CRD 名称。
2.3 检查 Alertmanager 对 AlertmanagerConfig 的选择范围
创建 AlertmanagerConfig 并不代表 Alertmanager 一定会加载它。需要检查 Alertmanager 自定义资源中的选择器:
kubectl -n monitoring get alertmanager main -o yaml
重点检查:
spec:
alertmanagerConfigSelector: {}
alertmanagerConfigMatcherStrategy:
type: None
这里有两个关键点。
alertmanagerConfigSelector: {} 表示选择符合命名空间范围的所有 AlertmanagerConfig。如果该字段完全未设置,资源选择器默认不会选择任何 AlertmanagerConfig。
alertmanagerConfigNamespaceSelector 如果未设置,默认只发现与 Alertmanager 自定义资源位于同一命名空间中的 AlertmanagerConfig。本文的 Alertmanager 和 AlertmanagerConfig 都位于 monitoring,因此可以不额外配置该字段。
注意:如果你的
Alertmanager资源由 Helm 或 Kustomize 管理,应在对应的 values 或清单源文件中修改,避免手工修改后又被重新覆盖。
三、创建 SMTP 授权码 Secret
邮件密码不能直接写在 AlertmanagerConfig 中。本文使用 Kubernetes Secret 保存 QQ 邮箱 SMTP 授权码。QQ 邮箱的 SMTP 授权码与网页登录密码不是同一个概念。
创建 alertmanager-smtp-auth.yaml:
apiVersion: v1
kind: Secret
metadata:
name: smtp-credentials
namespace: monitoring
type: Opaque
stringData:
password: "<QQ邮箱SMTP授权码>"
创建 Secret后,检查资源:
kubectl -n monitoring get secret smtp-credentials
后续 AlertmanagerConfig 通过下面的方式引用它:
authPassword:
name: smtp-credentials
key: password
其中:
-
name必须与 Secret 的名称一致。 -
key必须与stringData或data中保存授权码的键一致。 -
Secret 必须与
AlertmanagerConfig位于同一个命名空间,并且 Prometheus Operator 需要有权限读取它。
四、设计告警分组、路由和抑制规则
4.1 告警路由树
本文设计的路由树如下:
所有进入 Alertmanager 的告警
↓
alertname 是否为 Watchdog
├── 是 → null,不发送邮件
└── 否
↓
是否带有 notify_group="ai-infra"
├── 是 → email-ai-infra
└── 否 → email-default
Alertmanager 的路由是一个树形结构。每条告警先进入顶层路由,再依次匹配子路由。默认情况下,continue 为 false,告警匹配到第一个子路由后,不再继续匹配后续同级路由;如果没有匹配任何子路由,则由当前路由的接收器处理。
根路由配置为:
route:
receiver: email-default
表示未匹配专用子路由的告警统一发送到默认邮箱。
AI Infra 专用路由如下:
- receiver: email-ai-infra
matchers:
- name: notify_group
value: ai-infra
matchType: "="
只要告警中包含:
labels:
notify_group: ai-infra
就会进入 email-ai-infra 接收器。因为没有设置 continue: true,所以该告警不会再发送给默认接收器。
4.2 丢弃 Watchdog 邮件通知
Watchdog 是 kube-prometheus 中用于验证告警链路的心跳告警,通常会长期保持触发状态。本文让它保留在 Alertmanager 页面中,但不发送邮件:
- receiver: "null"
matchers:
- name: alertname
value: Watchdog
matchType: "="
对应的空接收器为:
- name: "null"
这里必须把 null 加上引号,避免 YAML 将其解析成空值。
4.3 告警分组
根路由使用以下分组字段:
groupBy:
- namespace
- alertname
这表示 namespace 和 alertname 都相同的告警会进入同一个通知组。
例如,下面两个 Pod 告警:
alertname=KubePodNotReady
namespace=ai-demo
pod=pod-a
alertname=KubePodNotReady
namespace=ai-demo
pod=pod-b
由于 pod 没有放入 groupBy,所以它们可以被合并到同一个通知组中,而不是为每个 Pod 单独发送一封邮件。Alertmanager 的分组机制主要用于在大规模故障中减少重复通知。
4.4 groupWait、groupInterval 和 repeatInterval
本文配置:
groupWait: 30s
groupInterval: 5m
repeatInterval: 10m
groupWait: 30s 表示一个新的告警组第一次出现后,先等待 30 秒再发送第一条通知。这样可以收集同组的其他告警,也可以等待更高级别的抑制源告警到达。如果告警在 groupWait 结束前恢复,该告警不会发送通知。
groupInterval: 5m 表示首条通知发送后,每隔 5 分钟检查该通知组是否有新告警加入,或者是否有告警恢复。只有通知组发生变化时,才会发送更新通知。
repeatInterval: 10m 表示告警持续未恢复,并且通知组没有变化时,距离上一次通知达到 10 分钟后再次发送提醒。Alertmanager 在每个 groupInterval 周期检查是否达到 repeatInterval,因此 repeatInterval 最好设置为 groupInterval 的整数倍。
以本文配置为例:
假设第一封通知发送后,告警一直处于触发状态,并且告警组没有发生变化:
告警出现时:
新告警组首次出现,开始等待 groupWait。
30 秒后:
groupWait 结束,发送第一封通知。
5 分 30 秒后:
到达第一个 groupInterval 检查点。
此时距离上一封通知只有 5 分钟,尚未达到 repeatInterval,
因此不发送重复通知。
10 分 30 秒后:
到达第二个 groupInterval 检查点。
此时距离上一封通知已经达到 10 分钟,并且告警仍未恢复、
告警组也没有发生变化,因此发送重复通知。
4.5 邮件接收器
邮件接收器主要使用以下字段:
emailConfigs:
- to: "<收件邮箱>"
from: "<发件邮箱>"
smarthost: smtp.qq.com:587
authUsername: "<发件邮箱>"
authPassword:
name: smtp-credentials
key: password
requireTLS: true
sendResolved: true
字段含义如下:
-
to:接收告警通知的邮箱。 -
from:邮件头中的发件地址。 -
smarthost:SMTP 服务器地址和端口,格式为hostname:port。 -
authUsername:SMTP 认证用户名,本实验使用完整 QQ 邮箱地址。 -
authPassword:从 Kubernetes Secret 中读取 SMTP 授权码。 -
requireTLS:要求 SMTP 连接使用 TLS。 -
sendResolved:允许在告警恢复后发送恢复通知。
这些字段均由 Prometheus Operator 的 EmailConfig API 定义。
4.6 critical 抑制 warning 和 info
本文配置以下抑制规则:
inhibitRules:
- sourceMatch:
- name: severity
value: critical
matchType: "="
targetMatch:
- name: severity
value: "warning|info"
matchType: "=~"
equal:
- namespace
- alertname
它的含义是:
存在 severity=critical 的源告警
↓
查找 severity=warning 或 severity=info 的目标告警
↓
要求源告警与目标告警的 namespace 和 alertname 相同
↓
抑制目标告警的通知
需要注意,抑制只是不再发送目标告警的通知,不会把目标告警从 FIRING 改成 INACTIVE,也不会从 Alertmanager 页面中删除它。Alertmanager 官方将 Inhibition 定义为:当某些源告警已经触发时,抑制符合条件的其他告警通知。
例如,两个告警规则可以使用相同的 alertname,但使用不同严重级别:
- alert: VllmRequestWaiting
labels:
severity: warning
- alert: VllmRequestWaiting
labels:
severity: critical
当两者位于同一个 namespace 时,critical 告警触发后,warning 通知会被抑制。
Silence 与 Inhibition 不同:Silence 是运维人员按照标签和时间范围手工创建的静默,适合计划维护;Inhibition 是根据其他正在触发的告警自动执行的抑制。
五、创建完整的 AlertmanagerConfig
创建 alertmanager-main-config.yaml:
apiVersion: monitoring.coreos.com/v1alpha1
kind: AlertmanagerConfig
metadata:
name: main-config
namespace: monitoring
spec:
route:
# 未匹配到子路由的告警发送给默认收件人。
receiver: email-default
# 同 namespace、同 alertname 的告警合并为一个通知组。
groupBy:
- namespace
- alertname
# 新告警组首次出现后等待 30 秒再发送通知。
groupWait: 30s
# 已经发送过通知的告警组,每 5 分钟检查一次是否发生变化。
groupInterval: 5m
# 告警持续未恢复且告警组没有变化时,每 10 分钟重复通知。
repeatInterval: 10m
routes:
# Watchdog 保留在 Alertmanager 中,但不发送邮件。
- receiver: "null"
matchers:
- name: alertname
value: Watchdog
matchType: "="
# 带有 notify_group="ai-infra" 标签的告警发送到专用邮箱。
# continue 默认为 false,匹配后不会继续匹配后续同级路由。
- receiver: email-ai-infra
matchers:
- name: notify_group
value: ai-infra
matchType: "="
receivers:
# 未匹配专用子路由的普通告警接收器。
- name: email-default
emailConfigs:
- to: "<默认告警收件邮箱>"
from: "<QQ发件邮箱>"
smarthost: smtp.qq.com:587
authUsername: "<QQ发件邮箱>"
authPassword:
name: smtp-credentials
key: password
requireTLS: true
sendResolved: true
# AI Infra 专用告警接收器。
- name: email-ai-infra
emailConfigs:
- to: "<AI Infra告警收件邮箱>"
from: "<QQ发件邮箱>"
smarthost: smtp.qq.com:587
authUsername: "<QQ发件邮箱>"
authPassword:
name: smtp-credentials
key: password
requireTLS: true
sendResolved: true
# 空接收器,只用于匹配后不发送任何通知。
- name: "null"
inhibitRules:
# 同 namespace、同 alertname 时,critical 抑制 warning 和 info。
- sourceMatch:
- name: severity
value: critical
matchType: "="
targetMatch:
- name: severity
value: "warning|info"
matchType: "=~"
equal:
- namespace
- alertname
将占位符替换为实际邮箱后创建资源,检查创建结果:
kubectl -n monitoring get alertmanagerconfig
kubectl -n monitoring describe alertmanagerconfig main-config
六、通过 NodePort 访问 Alertmanager Web 页面
创建 alertmanager-main-nodeport.yaml:
apiVersion: v1
kind: Service
metadata:
name: alertmanager-main-nodeport
namespace: monitoring
spec:
type: NodePort
selector:
alertmanager: main
ports:
- name: web
port: 9093
targetPort: web
nodePort: 30993
浏览器访问:
http://<NodeIP>:30993
下面是本次实验中的 Alertmanager 页面:
页面中可以看到不同告警已经进入不同接收器:
monitoring/main-config/email-default
monitoring/main-config/email-ai-infra
例如:
-
Kubernetes 组件告警、Pod 告警和 GPU 告警进入
email-default。 -
VllmTargetDown带有notify_group="ai-infra",因此进入email-ai-infra。
七、验证告警触发和邮件路由
7.1 验证告警从 PENDING 进入 FIRING
当告警表达式已经满足,但还没有持续达到 for 指定的时间时,Prometheus 页面显示为 PENDING:
告警条件持续达到 for 后,状态变成 FIRING:
进入 FIRING 后,Prometheus 将告警状态发送给 Alertmanager,Alertmanager 再根据路由和接收器配置发送邮件。
7.2 验证普通 GPU 告警
GPU 温度告警没有配置:
notify_group: ai-infra
因此不会匹配 AI Infra 子路由,最终由根路由发送到:
email-default
收到的邮件如下:

邮件中包含告警名称、GPU UUID、主机名、GPU 编号、命名空间、严重级别、当前指标值和告警描述。
需要特别说明:为了快速验证邮件链路,本次实验期间曾临时把 PromQL 的温度阈值调低,但没有同步修改 annotations.description,所以截图中出现了“描述为超过 80 度,但当前值为 51”的不一致。这只是测试配置造成的展示问题,不代表 51 > 80。实际使用时,PromQL 阈值和告警描述必须保持一致,避免误导接收人。
7.3 验证 AI Infra 专用路由
vLLM 告警规则中需要包含:
labels:
severity: critical
notify_group: ai-infra
当 Prometheus 无法持续抓取 vLLM /metrics,并且告警达到 for 指定的持续时间后,VllmTargetDown 进入 FIRING。由于该告警带有:
notify_group=ai-infra
因此匹配 email-ai-infra 子路由,而不会发送给默认接收器。收到的 vLLM 告警邮件如下:
从邮件中可以看到:
alertname=VllmTargetDown
namespace=ai-demo
notify_group=ai-infra
severity=critical
7.4 验证恢复通知
恢复 vLLM 服务,使 Prometheus 能够重新抓取 /metrics。当告警条件不再满足后,Prometheus 会把告警恢复状态发送给 Alertmanager。由于两个邮件接收器都配置了:
sendResolved: true
因此 Alertmanager 可以向对应收件人发送恢复通知。需要注意,sendResolved 只控制接收器是否发送恢复消息,不负责决定告警什么时候恢复。告警是否恢复仍然由 Prometheus 的表达式计算结果决定。
7.5 验证告警抑制
准备两个同名、同命名空间但严重级别不同的告警:
alertname=VllmRequestWaiting
namespace=ai-demo
severity=warning
alertname=VllmRequestWaiting
namespace=ai-demo
severity=critical
当二者同时触发时,critical 告警满足 sourceMatch,warning 告警满足 targetMatch,并且两者的 namespace 和 alertname 相同,因此 warning 通知会被抑制。
预期结果是:
critical:正常发送邮件
warning:仍然处于 FIRING,但显示为 Inhibited,不再重复发送邮件
八、总结
本文完成了从 Prometheus 告警规则到 Alertmanager 邮件通知的完整链路:
PrometheusRule 判断告警
↓
告警经过 PENDING 后进入 FIRING
↓
Prometheus 将告警发送给 Alertmanager
↓
Alertmanager 按 namespace 和 alertname 分组
↓
根据 alertname 和 notify_group 匹配路由
↓
critical 抑制同名 warning 和 info 通知
↓
通过 QQ SMTP 发送告警与恢复邮件
最终实现效果如下:
普通告警
→ email-default
notify_group="ai-infra"
→ email-ai-infra
Watchdog
→ null,不发送邮件
同 namespace、同 alertname 的 critical
→ 抑制 warning 和 info 通知
告警恢复
→ sendResolved 发送恢复邮件
至此,Prometheus 不仅可以发现 GPU 和 vLLM 服务异常,Alertmanager 也能够按照告警类型和严重程度,把通知发送给正确的接收人,并通过分组和抑制减少重复告警。
更多推荐


所有评论(0)