跳转至

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 是路由的依据,必须和 Alertmanager route.match 对齐。critical / warning / info 三档最常见。
  • {{ $labels.instance }} 是模板语法,可以引用告警的 label。写错变量名会渲染成空。

在 Prometheus 侧接入规则:

# prometheus.yml
rule_files:
  - /etc/prometheus/rules/alert_rules.yml

步骤 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。