Alertmanager 对接钉钉-企微 webhook 告警指南
Alertmanager 对接钉钉/企微 webhook 实测:webhook receiver 配置、v4 协议 payload 完整结构、直接推送官方端点失败回显、自建转换层(v4→钉钉/企微 markdown)全链路转发复现与字段映射
Alertmanager 对接钉钉-企微 webhook 告警指南
目标:实测 Alertmanager(0.34.1)通过
webhook_configs对接钉钉/企微机器人的完整链路——webhook receiver 配置、v4 协议 payload 完整结构、直接推送官方端点的失败回显(300005/93000)、自建转换层把 v4 payload 转为钉钉/企微 markdown 消息的全链路复现与字段映射。机器人创建为 ⚠️ 前置(详见《钉钉机器人 webhook 告警接入指南》《企业微信机器人 webhook 告警接入指南》),本环境的转发/转换逻辑在本地完整实测。
一、环境信息
| 信息项 | 值 |
|---|---|
| Alertmanager 版本 | 0.34.1(Ubuntu 22.04 单实例,systemd 托管) |
| 官方端点 | 钉钉 https://oapi.dingtalk.com/robot/send?access_token=<TOKEN>;企微 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=<KEY> |
| 直接对接实测 | 假 token/key → 300005 / 93000(见 §四) |
| 转换层 | 自建 Python 服务(监听 19091),接收 v4 → 转 markdown → 转发模拟端点 |
| 本地回显端点 | http://127.0.0.1:19090/dingtalk(复现官方端点收到钉钉格式消息) |
二、接收端准备(本地回显端点,模拟官方机器人端点)
本环境无真实钉钉/企微群,用 Python HTTP 服务接收并原样打印请求,用于验证"发出的消息长什么样":
python3 /tmp/webhook_echo.py 19090
💡 说明:该脚本监听 19090 端口,收到 POST 后打印
METHOD/PATH/HEADERS/BODY到控制台。真实环境用官方端点替换即可。
三、Alertmanager webhook receiver 配置
在 alertmanager.yml 中定义 receiver:
route:
group_by: ["alertname"]
group_wait: 1s
group_interval: 5s
repeat_interval: 1m
receiver: "dingtalk"
receivers:
- name: "dingtalk"
webhook_configs:
- url: "http://127.0.0.1:19091/convert"
send_resolved: true
max_alerts: 64
http_config:
timeout: 10s
| 参数 | 默认 | 说明 |
|---|---|---|
url | - | 接收端地址(官方端点或转换层) |
send_resolved | false | 是否发送 resolved 恢复通知 |
max_alerts | 0(不截断) | 单次请求最多携带告警数,超过被截断(truncatedAlerts 标记) |
http_config.timeout | 10s | 请求超时,超时触发 Alertmanager 端重试 |
http_config.bearer_token / authorization | - | 需要鉴权的接收端(如企业内部门户) |
配置后校验并热加载:
amtool check-config /etc/alertmanager/alertmanager.yml
curl -X POST http://127.0.0.1:9093/-/reload
实测回显(check-config):
Checking '/etc/alertmanager/alertmanager.yml' SUCCESS
四、实测 1:v4 payload 直接推送官方端点(失败回显)
把 Alertmanager 的 webhook url 直接指向官方端点时,Alertmanager 发送的是自身 v4 协议 JSON,与钉钉/企微要求的 msgtype 消息结构不兼容。用假凭据实测端点契约(真实凭据同样不识别 v4 结构,需转换层,见 §五/§六):
# 钉钉:v4 payload 直推
curl -s -X POST "https://oapi.dingtalk.com/robot/send?access_token=INVALID_TOKEN_123" \
-H "Content-Type: application/json" \
-d '{"receiver":"echo","status":"firing","alerts":[{"status":"firing","labels":{"alertname":"DiskFull","instance":"db-01","severity":"critical"},"annotations":{},"startsAt":"2026-10-08T21:30:01Z","endsAt":"0001-01-01T00:00:00Z"}],"groupLabels":{"alertname":"DiskFull"},"commonLabels":{"alertname":"DiskFull"},"externalURL":"http://am:9093","version":"4","groupKey":"{}:{alertname=\"DiskFull\"}"}'
实测回显:
{"errcode":300005,"errmsg":"token is not exist"}
# 企微:v4 payload 直推
curl -s -X POST "https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=FAKE-KEY-1234567890" \
-H "Content-Type: application/json" \
-d '<同上 v4 JSON>'
实测回显:
{"errcode":93000,"errmsg":"invalid webhook url, hint: [1791495031356212450879172], from ip: 42.63.89.89, more info at https://open.work.weixin.qq.com/devtool/query?e=93000"}
⚠️ 结论:即便换成有效凭据,v4 payload 也缺少
msgtype字段、结构与钉钉/企微协议不符,官方端点不会按告警卡片展示。生产对接必须经转换层(§五)把 v4 转成各自消息格式,或使用官方/社区现成组件(如 prometheus-webhook-dingtalk)。
五、实测 2:转换层全链路转发复现
转换层职责:接收 Alertmanager v4 payload → 提取关键字段 → 组装钉钉/企微 markdown 消息 → 转发官方端点。本环境转发到本地回显端点验证。
5.1 转换层服务(本环境实现,Python)
# /tmp/am_dingtalk_proxy.py(节选核心:v4 -> 钉钉 markdown)
def convert_v4(payload):
first = payload["alerts"][0]
labels, annos = first["labels"], first["annotations"]
msg = (
"### %s\n> %s\n\n"
"- 级别: **%s**\n- 实例: %s\n- 状态: %s\n"
"- 开始时间: %s\n- 分组: %s"
) % (
"【%s】%s" % ("恢复" if payload["status"] == "resolved" else "告警", labels["alertname"]),
annos.get("summary", "无摘要"),
labels.get("severity", "unknown"), labels.get("instance", "-"),
payload["status"], first["startsAt"][:19].replace("T", " "),
payload.get("groupKey", ""),
)
return {"msgtype": "markdown", "markdown": {"title": "【告警】" + labels["alertname"], "text": msg}}
启动转换层(监听 19091):
nohup python3 /tmp/am_dingtalk_proxy.py > /tmp/am_dingtalk_proxy.log 2>&1 &
5.2 触发告警验证链路
推送一条带注解的告警到 Alertmanager:
curl -s -X POST http://127.0.0.1:9093/api/v2/alerts \
-H "Content-Type: application/json" \
-d '[{"labels":{"alertname":"HighCPU","instance":"app-02","severity":"critical"},"annotations":{"summary":"CPU 使用率持续 95% 超过 10 分钟"},"startsAt":"2026-10-08T21:35:00Z"}]'
Alertmanager 路由后经 webhook 发出的 v4 payload 完整结构(转换层/回显端点实际收到):
{
"receiver": "echo",
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "HighCPU",
"instance": "app-02",
"severity": "critical"
},
"annotations": {
"summary": "CPU 使用率持续 95% 超过 10 分钟"
},
"startsAt": "2026-10-08T21:35:00Z",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "",
"fingerprint": "f091dfb75ab9ad11"
}
],
"notification_reason": "first notification",
"groupLabels": {
"alertname": "HighCPU"
},
"commonLabels": {
"alertname": "HighCPU",
"instance": "app-02",
"severity": "critical"
},
"commonAnnotations": {
"summary": "CPU 使用率持续 95% 超过 10 分钟"
},
"routeLabels": {},
"externalURL": "http://947a50672d4a:9093",
"version": "4",
"groupKey": "{}:{alertname=\"HighCPU\"}",
"truncatedAlerts": 0
}
转换层日志(已转为钉钉 markdown 消息):
=== converted to DingTalk markdown ===
{
"msgtype": "markdown",
"markdown": {
"title": "【告警】HighCPU",
"text": "### 【告警】HighCPU\n> CPU 使用率持续 95% 超过 10 分钟\n\n- 级别: **critical**\n- 实例: app-02\n- 状态: firing\n- 开始时间: 2026-10-08 21:35:00\n- 分组: {}:{alertname=\"HighCPU\"}"
}
}
=== echo response ===
{"status":"ok"}
回显端点(模拟钉钉端点)实际收到的消息体:
METHOD: POST
PATH: /dingtalk
HEADERS: {'Content-Type': 'application/json', 'Host': '127.0.0.1:19090', 'User-Agent': 'Python-urllib/3.10', 'Content-Length': '372'}
BODY: {
"msgtype": "markdown",
"markdown": {
"title": "【告警】HighCPU",
"text": "### 【告警】HighCPU\n> CPU 使用率持续 95% 超过 10 分钟\n\n- 级别: **critical**\n- 实例: app-02\n- 状态: firing\n- 开始时间: 2026-10-08 21:35:00\n- 分组: {}:{alertname=\"HighCPU\"}"
}
}
💡 链路结论:
告警来源 → Alertmanager(路由/分组/抑制/静默)→ webhook v4 → 转换层(v4→markdown)→ 钉钉/企微端点。Alertmanager 侧只需把 receiver 的url指到转换层即可,告警聚合去重等逻辑全部沿用 Alertmanager。
六、v4 → 钉钉/企微 字段映射与差异
| v4 payload 字段 | 映射到钉钉 markdown | 映射到企微 markdown |
|---|---|---|
alerts[].labels.alertname | markdown.title + 正文标题 | 正文标题(企微无 title 字段) |
alerts[].labels.instance/severity | 正文列表项 | 正文列表项 |
alerts[].annotations.summary/description | 正文引用行 | 正文引用行 |
status(firing/resolved) | 标题前缀【告警】/【恢复】 | 同左 |
groupKey / commonLabels | 分组信息行 | 同左 |
externalURL | 跳转链接(可选) | 同左 |
差异注意:
- 企微 markdown 无独立
title:会话列表直接显示正文首行,标题样式需写进content(如### 【告警】HighCPU)。 - 钉钉 markdown 有
title(会话列表纯文本标题)与text(正文)。 - 转换层必须处理
status=resolved(send_resolved: true时 Alertmanager 会发恢复通知),否则恢复事件被丢弃、群里只有告警没有恢复。 - 大告警批次会被
max_alerts截断,truncatedAlerts > 0时转换层可追加"另有 N 条被截断"提示。
七、常见问题
1. webhook 发送失败会怎样?
Alertmanager 对非 2xx 响应按指数退避重试(约 5s/10s/20s…),长时间失败后丢弃并记录 level=error;转换层需保证幂等(重复投递是正常的)。
2. 一条告警被分组后发几次?
按路由 group_by 分组聚合,repeat_interval 内同组只发一次;firing 与 resolved 各发一次(send_resolved 开启时)。
3. 必须自建转换层吗?
不是。可选:①社区现成组件(prometheus-webhook-dingtalk 等);②钉钉/企微官方"自定义机器人"配合云函数/Serverless 中转;③本文 §五 的自建方案(约 40 行,可控无外部依赖)。
4. Alertmanager 直接发官方端点收到 300005/93000?
凭据无效时必现;凭据有效时因 v4 结构不兼容同样无法按告警卡片展示。两步都确认后仍异常,按《钉钉机器人 webhook 告警接入指南》§六 /《企业微信机器人 webhook 告警接入指南》§五 排查。
八、参考链接
- Alertmanager webhook_configs 官方文档:https://prometheus.io/docs/alerting/latest/configuration/#webhook_config
- Alertmanager 通知模板与 v4 协议:https://prometheus.io/docs/alerting/latest/notifications/
- 钉钉机器人接入见《钉钉机器人 webhook 告警接入指南》,企微见《企业微信机器人 webhook 告警接入指南》,消息模板见《告警消息模板与最佳实践》