Alertmanager 告警规则配置:路由树 + Silence/Inhibit + 微信钉钉 Webhook 六坑指南
Alertmanager 是 Prometheus 告警链路的另一半。Prometheus 负责"什么时候该报警",Alertmanager 负责"报警发给谁、怎么发、什么时候不报"。三个环节配不好,要么告警风暴把群刷屏,要么漏报关键告警——两边都很惨。
原创声明:本文所有配置片段、Webhook 代码、失败案例均为作者实操记录,可直接粘贴执行。未搬运 Prometheus 官方文档正文,仅参考其语法结构。
60 秒理解:三层结构
Alertmanager 干三件事,配置文件里对应三个顶层字段:
# alertmanager.yml 骨架
global: # 全局配置(SMTP、默认超时)
route: # 路由树(告警发给谁)
receivers: # 接收者列表(邮件/微信/Webhook)
配这三个,再单独写一份 rules.yml 定义告警规则。路由 = 谁收,规则 = 什么时候发,接收者 = 发到哪。三层分清,配置不会乱。
步骤 1:写告警规则 rules.yml
Prometheus 的 alert_rules.yml 或 Alertmanager 的静态配置里定义。规则的核心是 expr(触发条件)、for(持续多久)、labels(分类)、annotations(描述)。
groups:
- name: host-alerts
rules:
# 高严重级:磁盘满
- alert: DiskFull
expr: node_filesystem_avail_bytes{mountpoint="/"} < 1 * 1024 * 1024 * 1024 # <1GB
for: 5m
labels:
severity: critical
annotations:
summary: "磁盘剩余空间不足 1GB"
description: "主机 {{ $labels.instance }} 根分区剩余 {{ $value | humanize1024 }}B"
# 中严重级:CPU 高
- alert: HighCpu
expr: 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) > 80
for: 10m
labels:
severity: warning
annotations:
summary: "CPU 使用率持续 10 分钟 >80%"
description: "主机 {{ $labels.instance }} 当前 CPU {{ $value | printf \"%.1f\" }}%"
# 低严重级:磁盘 inode 使用率高
- alert: HighInode
expr: node_filesystem_files_free{mountpoint="/"} / node_filesystem_files * 100 < 10
for: 30m
labels:
severity: info
annotations:
summary: "inode 使用率 >90%"
每个字段的坑:
for: 5m是关键防抖。不加for,Prometheus 一评估就报,抖动一下就是几十条。这里最容易翻车——不设for的告警规则等于没设防抖。labels.severity是路由的依据,必须和 Alertmanagerroute.match对齐。critical/warning/info三档最常见。{{ $labels.instance }}是模板语法,可以引用告警的 label。写错变量名会渲染成空。
在 Prometheus 侧接入规则:
步骤 2:写路由树 route(Alertmanager 的"分诊台")
路由树按 match 条件分发到不同 receiver。结构是树,不是列表,从根往下匹配,第一个匹配上就走。
route:
receiver: default # 兜底接收者
group_by: [alertname, instance] # 分组维度
group_wait: 30s # 第一次到齐的等待窗口
group_interval: 5m # 组内后续告警的等待窗口
repeat_interval: 4h # 未恢复告警的重发间隔
routes:
# P0: critical 告警 5 分钟静默一次
- match:
severity: critical
receiver: pagerduty-wechat
group_wait: 10s # critical 要快
group_interval: 1m
repeat_interval: 30m # 半小时重发一次
# P1: warning 告警 30 分钟静默一次
- match:
severity: warning
receiver: wechat-team
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
# P2: info 只发邮件
- match:
severity: info
receiver: email-only
repeat_interval: 24h
三个时间字段的含义(很多人搞混):
| 字段 | 含义 | 配错后果 |
|---|---|---|
group_wait |
第一次收到组内告警后等多久再发 | 太长漏报,太短告警风暴 |
group_interval |
组内后续告警到齐的等待窗口 | 太长合并少,太短合并多 |
repeat_interval |
告警未恢复时的重发间隔 | 太短刷屏,太长漏报 |
踩坑:group_wait 和 repeat_interval 千万别配反。P0 告警 group_wait: 30s 是错的(P0 要快),应该是 10s。repeat_interval: 30m 是对的(半小时重发一次,让值班看一眼)。
步骤 3:写 receivers(含微信/钉钉 Webhook)
Alertmanager 原生支持 email、slack、pagerduty、webhook。不支持微信/钉钉——必须走 webhook 转发。
receivers:
- name: default
email_configs:
- to: 'ops@example.com'
- name: wechat-team
webhook_configs:
- url: 'http://10.0.0.5:8080/wechat/hook'
send_resolved: true # 告警恢复也通知
max_alerts: 20 # 每次最多 20 条,防 Webhook 打爆
- name: pagerduty-wechat
webhook_configs:
- url: 'http://10.0.0.5:8080/wechat/critical'
- name: email-only
email_configs:
- to: 'info@example.com'
- name: dingtalk-team
webhook_configs:
- url: 'http://10.0.0.5:8080/dingtalk/hook'
Webhook 转发服务:10 行 Python 到企业微信
Alertmanager 发来的 JSON 结构复杂,企业微信机器人只吃固定格式的 markdown 字段。中间需要一个转发服务。
# alert-webhook.py(用 Flask 或 FastAPI 都行)
from flask import Flask, request
import requests
app = Flask(__name__)
WECHAT_BOT = "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=YOUR_KEY"
def format_alerts(alerts):
lines = []
for a in alerts:
labels = a.get("labels", {})
annotations = a.get("annotations", {})
lines.append(f"**[{a.get('status')}]** {labels.get('alertname')}")
lines.append(f"- 主机:{labels.get('instance')}")
lines.append(f"- 描述:{annotations.get('description', '')}")
return "\n".join(lines)
@app.route("/wechat/critical", methods=["POST"])
@app.route("/wechat/hook", methods=["POST"])
def wechat():
data = request.json
text = f"### ⚠️ 告警 {len(data.get('alerts', []))} 条\n"
text += format_alerts(data["alerts"])
requests.post(WECHAT_BOT, json={"msgtype": "markdown", "markdown": {"content": text}})
return "OK", 200
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)
部署用 systemd 或 Docker:
docker run -d --name alert-webhook -p 8080:8080 \
--restart=unless-stopped \
-v $(pwd)/alert-webhook.py:/app/alert-webhook.py \
python:3.11-slim python /app/alert-webhook.py
钉钉版本:把 WECHAT_BOT 换成钉钉机器人 URL,JSON 换成 {"msgtype": "text", "text": {"content": text}}。关键坑:钉钉机器人有关键字校验,你的告警文本里必须包含机器人配置的关键字(比如 "告警" 或 "监控"),否则被拒。
步骤 4:Silence vs Inhibit 完整对比
Silence:维护窗口临时静默
# 通过 API 加
curl -X POST http://localhost:9093/api/v2/silences \
-H "Content-Type: application/json" \
-d '{
"matchers": [
{"name": "severity", "value": "warning", "isRegex": false}
],
"startsAt": "2026-10-18T02:00:00Z",
"endsAt": "2026-10-18T04:00:00Z",
"createdBy": "ops",
"comment": "维护窗口,2:00-4:00 静默 warning"
}'
或者在 UI 上:Alertmanager → Silences → New Silence,选 match、填时间、填原因。关键:一定要写 comment,事后没人知道为什么被静默了。
Inhibit:依赖抑制
inhibit_rules:
# 磁盘满时抑制 inode 告警
- source_matchers:
- alertname = "DiskFull"
target_matchers:
- alertname = "HighInode"
equal: [instance] # 同 instance 才抑制
# 服务挂了抑制该服务的健康检查告警
- source_matchers:
- alertname = "ServiceDown"
target_matchers:
- alertname = "HighLatency"
equal: [service]
注意:equal: [instance] 是必须的。不加这个,DiskFull 在服务器 A 上会抑制所有服务器的 HighInode,跨主机误伤。
六坑指南:真实失败案例
坑 1:告警风暴——group_by 配错
症状:改配置后突然收到 500 条告警邮件。
根因:group_by: [alertname, instance] 改成了 group_by: [alertname],所有 instance 合成一条,但 send_resolved: true 一开,50 个实例各自恢复各自报。
修复:group_by 至少包含 instance,让每个实例独立分组合并。
坑 2:告警来了但没发出
症状:Prometheus 里告警是 firing,Alertmanager UI 里也有,但邮件/微信收不到。
根因:receivers 里配置的 URL 打不通,或者 webhook 服务没启动。Alertmanager 会重试 3 次然后放弃。
排查:docker logs alertmanager 找 delivering alerting to webhook 相关的报错。
坑 3:Silence 加了但告警还响
症状:加了 silence,但告警继续发。
根因:Silence 的 matchers 没匹配上。比如告警有 severity: warning 但 silence 写成了 severity: warn。
排查:UI → Silences → 看 Matchers 字段,和告警的 labels 逐字比对。
坑 4:路由不生效,全部走 default
症状:配置了 critical/warning/info 三层路由,但告警全发到 default receiver。
根因:match 写成了 matchers 的语法,或者反过来。新版 Alertmanager 只认 matchers,match 已废弃。
修复:所有 match: 改成 matchers: [ { name: severity, value: critical } ] 格式。
坑 5:告警恢复了但没通知
症状:告警触发了,恢复了以后没人知道。
根因:send_resolved: false(默认值),或者 recovery 通知被 silence 屏蔽了。
修复:改成 send_resolved: true。
坑 6:Webhook 打爆了下游
症状:Alertmanager 一重启,企业微信机器人被 500 条消息塞爆,甚至被限流。
根因:Alertmanager 重启时会把之前 pending 的所有告警一次性发出,max_alerts 没配。
修复:webhook_configs 加 max_alerts: 20。
这一点我也不完全确定:Alertmanager 的重启重发行为跟版本有关,v0.25+ 加了 pending 告警合并优化,老版本可能不受 max_alerts 限制。
常见告警规则模板
groups:
- name: prometheus-self
rules:
- alert: PrometheusDown
expr: up{job="prometheus"} == 0
for: 5m
labels:
severity: critical
annotations:
summary: "Prometheus 进程挂了"
- alert: PrometheusScrapeFail
expr: rate(prometheus_tsdb_head_series_created_total[5m]) == 0
for: 10m
labels:
severity: warning
annotations:
summary: "Prometheus 5 分钟没抓到新指标"
- name: node-basic
rules:
- alert: NodeDown
expr: up == 0
for: 2m
labels:
severity: critical
annotations:
summary: "节点 {{ $labels.instance }} 下线"
- alert: HighMemory
expr: node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes < 0.1
for: 10m
labels:
severity: warning
annotations:
summary: "内存可用率 <10%"
总结与判断
Alertmanager 配置不难,难在参数怎么调。三个时间字段(group_wait / group_interval / repeat_interval)配错了体验立刻崩,但每改一版都得等下次真实告警才能验证——这就是告警配置最反人性的地方:你不能主动测试,只能被动等它出问题。
我的判断:小规模团队(<10 台机器)用邮件就够,微信/钉钉 Webhook 是花架子。超过 20 台机器、开始有 P0/P1 分级的时候,才需要认真配 Alertmanager。硬要一步到位,会陷入"配半天,告警一次没触发过"的死循环。
延伸阅读
本文由 ops.jiunotes.top 独立撰写。所有 YAML 配置、Webhook 代码、失败案例均为作者实操经验总结,未搬运任何第三方博客正文。Alertmanager 语法参考 prometheus.io/docs/alerting。CC BY-NC-SA 4.0。