先说结论:dingtalk_configs 不是原生 Alertmanager 可用的接收器字段,直接写进 alertmanager.yml 会导致配置校验失败。正确链路是:
Prometheus → Alertmanager → prometheus-webhook-dingtalk → 钉钉机器人
Alertmanager 只负责把告警发给 prometheus-webhook-dingtalk;转换服务再把 Alertmanager Webhook 消息转换成钉钉机器人能够接收的请求。
这类“监控已经报警了,值班群却没人看到”的问题,关键不是反复修改消息模板,而是先确认请求停在哪一层。 同时要注意两个 URL 的职责不能填反:Alertmanager 的 webhook_configs 填转换服务地址,转换服务配置里才填钉钉机器人 Webhook。
dingtalk_configs 不是接收器字段
原生 Alertmanager 会按照自己的配置结构校验接收器。webhook_configs 是受支持的通用 Webhook 接收器,但 dingtalk_configs 不在该结构中,因此不能期待它像 email_configs 或 slack_configs 一样直接工作。
有时这个字段并非来自 Alertmanager 本体,而是 Helm、Operator 或其他上层封装提供的自定义 values 配置。这时不能只看 values 文件,应该继续检查最终渲染出来的 alertmanager.yml。上层可以有自己的参数名称,但最终交给 Alertmanager 的文件仍必须符合原生配置格式。
先用当前安装包中的 amtool 检查最终配置:
amtool check-config /etc/alertmanager/alertmanager.yml
Prometheus 配置也单独检查,避免把规则文件或目标地址的问题误认为 Alertmanager 接收器问题:
promtool check config /etc/prometheus/prometheus.yml
promtool check rules /etc/prometheus/rules/dingtalk-test.yml
不同版本、不同装载方式生成的错误文本可能不同,因此不应写死某个报错码。需要确认的核心事实只有一个:dingtalk_configs 不能作为原生 Alertmanager 接收器字段使用。
三种接入方式及取舍
接入方式分为三类:Webhook 直连钉钉、借助转换服务,或者自己实现转换程序。表中另列无效的 dingtalk_configs,作为对照。
| 方案 | Alertmanager 侧 | 格式转换由谁完成 | 主要取舍 |
|---|---|---|---|
dingtalk_configs |
原生校验不通过 | 无 | 不可用 |
webhook_configs 直连钉钉 |
指向钉钉机器人地址 | 无 | Alertmanager 发送的是告警 Webhook JSON,不会自动变成钉钉机器人消息,通常无法直接送达 |
webhook_configs 加 prometheus-webhook-dingtalk |
指向转换服务 | 转换服务 | 接入成本适中,是默认选择 |
webhook_configs 加自建转换程序 |
指向自己的服务 | 自建程序 | 格式和鉴权最灵活,但要承担代码、日志、升级与维护成本 |
Webhook 是 Alertmanager 扩展其他通知渠道的通用入口,但协议转换仍然需要额外一层。prometheus-webhook-dingtalk 接收 Alertmanager Webhook,再调用钉钉机器人,钉钉消息格式的适配也由它完成。
如果没有特殊的鉴权、模板或私有部署要求,优先选择 webhook_configs 加 prometheus-webhook-dingtalk。只有在消息格式必须完全定制、转换逻辑需要和内部系统深度联动时,才值得维护自建程序。
转换服务先接好机器人
先在目标钉钉群创建自定义机器人,取得带访问令牌的 Webhook 地址。钉钉界面的入口和安全设置可能调整,不宜把某个固定菜单路径写死在排查文档里;复制机器人地址后,应同时确认它对应当前目标群。
prometheus-webhook-dingtalk 的配置重点是机器人地址。参考已有配置格式,可以写成:
url: 'https://oapi.dingtalk.com/robot/send?access_token=<TOKEN>'
webhook_mention_all: false
如果确实需要提醒所有人,再把 webhook_mention_all 改为 true。这个配置属于转换服务,不是 Alertmanager 路由参数。
机器人地址包含敏感令牌,不应提交到 Git,也不要在工单、群聊或公开日志里粘贴完整地址。配置文件可以限制读取权限:
chmod 600 /etc/prometheus-webhook-dingtalk/dingtalk.yml
实际有两条方向不同的连接:
Alertmanager → http://<转换服务>:8060/dingtalk/webhook1/send
转换服务 → https://oapi.dingtalk.com/robot/send?access_token=<TOKEN>
第一条地址可以没有机器人令牌,第二条才是敏感配置。转换服务的启动参数、配置文件名和接口路径可能随版本变化;参考文章中的 Alertmanager、Prometheus 和转换服务版本只能作为样例,实际部署应以所选版本的官方发布说明为准。
如果转换服务和 Alertmanager 都运行在 Docker 中,优先让两者加入同一个 Docker 网络,并通过服务名访问,例如:
url: 'http://prometheus-webhook-dingtalk:8060/dingtalk/webhook1/send'
如果 Alertmanager 是宿主机进程,而转换服务在容器中,则要根据端口发布方式选择宿主机可达地址。不要把容器里的 127.0.0.1 当成宿主机回环地址;它在容器中指向容器自身。
两段告警配置分开写
Alertmanager 配置负责选择接收器、设置分组和决定是否发送恢复通知:
global:
resolve_timeout: 2m
route:
receiver: dingtalk-webhook
group_by: ['alertname']
group_wait: 10s
group_interval: 10s
repeat_interval: 1h
receivers:
- name: dingtalk-webhook
webhook_configs:
- url: 'http://prometheus-webhook-dingtalk:8060/dingtalk/webhook1/send'
send_resolved: true
这里有三个容易忽略的地方。
route.receiver 必须和 receivers[].name 一致;配置了更具体的 route.match 时,还要检查最终命中的子路由。send_resolved 决定 Alertmanager 是否向 Webhook 发送恢复通知。group_by、group_wait、group_interval 和 repeat_interval 则控制通知如何分组、何时首次发送以及未恢复时多久重复提醒。
Prometheus 配置只负责加载规则并把告警交给 Alertmanager:
global:
evaluation_interval: 15s
rule_files:
- rules/*.yml
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager:9093
alertmanager:9093 适用于 Prometheus 和 Alertmanager 位于同一个 Docker 网络的情况;如果 Prometheus 直接运行在宿主机上,应换成 Alertmanager 的宿主机可达 IP 或 DNS 名称。Prometheus 负责规则计算,Alertmanager 负责通知路由、分组、静默与抑制,两者职责不要混在一起。
先单层验证再串起来
配置先过解析器
先执行前面提到的两条检查命令:
amtool check-config /etc/alertmanager/alertmanager.yml
promtool check config /etc/prometheus/prometheus.yml
只有配置能够通过解析,后面的网络和机器人问题才有排查价值。配置阶段失败时,先处理 dingtalk_configs、YAML 缩进、receiver 名称和最终渲染结果,不要先改防火墙。
转换服务先做直连
绕过 Prometheus 和 Alertmanager,直接给转换服务发送一条符合 Alertmanager Webhook 结构的测试消息。下面使用动态时间,避免测试数据携带明显过期的开始时间:
STARTS_AT="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
cat > dingtalk-test.json <<EOF
{
"version": "4",
"groupKey": "{}:{alertname=\"DingTalkSelfTest\"}",
"status": "firing",
"receiver": "dingtalk-webhook",
"groupLabels": {
"alertname": "DingTalkSelfTest"
},
"commonLabels": {
"alertname": "DingTalkSelfTest",
"severity": "warning"
},
"commonAnnotations": {
"summary": "Alertmanager Webhook self test",
"description": "This message validates the bridge and DingTalk robot only."
},
"externalURL": "http://alertmanager.example.com:9093",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "DingTalkSelfTest",
"severity": "warning"
},
"annotations": {
"summary": "Alertmanager Webhook self test",
"description": "This message validates the bridge and DingTalk robot only."
},
"startsAt": "${STARTS_AT}",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "http://prometheus.example.com:9090/graph"
}
]
}
EOF
向转换服务发送:
curl -i -sS -X POST 'http://127.0.0.1:8060/dingtalk/webhook1/send' \
-H 'Content-Type: application/json' \
--data-binary @dingtalk-test.json
这一步只验证“转换服务到钉钉”,不能证明 Alertmanager 的 send_resolved 已经生效。响应状态和正文以当前转换服务版本的实际返回为准,不要预设成功码或错误文本。
还可以生成一条恢复消息,直接检查转换服务是否会向钉钉发送 resolved 通知:
jq '.status = "resolved"
| .alerts[0].status = "resolved"
| .alerts[0].endsAt = (now | todateiso8601)' \
dingtalk-test.json > dingtalk-resolved-test.json
curl -i -sS -X POST 'http://127.0.0.1:8060/dingtalk/webhook1/send' \
-H 'Content-Type: application/json' \
--data-binary @dingtalk-resolved-test.json
再走完整告警链
直接调用转换服务成功后,再用一条临时规则验证 Prometheus、Alertmanager 和转换服务之间的真实路径。为了得到可恢复的告警,可以监控一个临时抓取目标是否不可达。
假设 Prometheus 直接运行在宿主机上,增加以下抓取配置:
scrape_configs:
- job_name: dingtalk-self-test
scrape_interval: 5s
static_configs:
- targets:
- 127.0.0.1:9101
再创建规则:
groups:
- name: dingtalk-self-test
rules:
- alert: DingTalkSelfTest
expr: up{job="dingtalk-self-test"} == 0
for: 0m
labels:
severity: warning
annotations:
summary: "DingTalk end-to-end self test"
description: "The temporary scrape target is down."
先让 9101 端口没有服务,Prometheus 抓取得到 up=0 后应触发告警。随后在另一个终端启动一个临时 HTTP 服务:
python3 -m http.server 9101 --bind 127.0.0.1
目标恢复可达后,up 变成 1,告警结束,Alertmanager 应在 send_resolved: true 的情况下发送恢复通知。测试完成后删除这条临时规则和抓取配置。
如果 Prometheus 位于容器中,127.0.0.1 指向 Prometheus 容器自身,必须换成同一 Docker 网络中可达的临时目标,否则这次测试只证明了错误的目标地址。
对照两端状态
分别查看 Prometheus 和 Alertmanager 保存的告警:
curl -sS 'http://127.0.0.1:9090/api/v1/alerts' \
| jq '[.data.alerts[] | select(.labels.alertname == "DingTalkSelfTest") | {state: .state, labels: .labels}]'
curl -sS 'http://127.0.0.1:9093/api/v2/alerts' \
| jq '[.[] | select(.labels.alertname == "DingTalkSelfTest") | {state: .status.state, labels: .labels}]'
同时观察两端日志:
journalctl -u alertmanager -f
journalctl -u prometheus-webhook-dingtalk -f
容器部署则使用对应的 docker logs -f 命令。重点对齐三个时间点:Prometheus 产生告警、Alertmanager 发出 Webhook、转换服务向钉钉发起请求。最后再以目标群里是否出现 firing 和 resolved 消息作为送达依据。
群里没消息沿链路倒查
“群里没消息”只是最终表现,不是一个故障点。按请求方向倒查,通常比从钉钉机器人设置开始碰运气更快。
| 现象 | 先检查哪一层 | 具体检查 | 常见原因 |
|---|---|---|---|
| 配置校验直接失败 | 最终 Alertmanager 配置 | 搜索 dingtalk_configs,检查 YAML 缩进、receiver 名称和渲染结果 |
使用了非原生字段,或上层模板没有正确生成配置 |
| Prometheus 没有产生告警 | Prometheus | 规则加载状态、表达式结果、/api/v1/alerts |
规则未加载、表达式没有匹配、目标本来就正常 |
| Alertmanager 有告警,转换服务没有请求 | Alertmanager 到转换服务 | route.receiver、Webhook URL、DNS、端口、防火墙和 Docker 网络 |
receiver 不匹配、地址指向错误网络命名空间 |
| 转换服务收到请求,钉钉没有消息 | 转换服务到钉钉 | 机器人地址、令牌、机器人侧安全设置、转换服务记录的钉钉响应 | 令牌失效、机器人被限制、请求未通过机器人侧校验 |
| 只收到 firing | 恢复通知链路 | send_resolved、告警是否真正结束、转换服务对 resolved 的处理 |
恢复通知未启用,或测试告警一直处于 firing |
| 消息重复 | Alertmanager 路由与重复策略 | group_by、group_interval、repeat_interval,以及是否为重试 |
同一告警仍在持续,或通知策略与预期不同 |
| 部分告警缺失 | Alertmanager 路由 | 子路由匹配条件、静默和抑制规则 | 告警被路由到其他 receiver,或被静默、抑制 |
| 消息字段为空 | 标签、注解和模板 | labels、annotations、Go template 及当前模板文件 |
数据源没有字段,或模板引用了不存在的键 |
| 消息发到了错误群 | 转换服务配置 | 转换服务中的机器人 Webhook | 多群部署时仍引用了旧机器人地址 |
Prometheus 层没有告警时,继续调 Webhook 没有意义。Alertmanager 层已经有告警、转换服务却没有请求时,重点检查 URL、DNS 和网络地址,而不是机器人令牌。转换服务已经收到请求但钉钉没有消息时,再核对机器人地址、令牌和机器人侧限制,并以转换服务记录的钉钉响应为依据。
Alertmanager 返回 Webhook 请求成功,只能证明转换服务接收了请求,不能单凭这个结果推断钉钉群已经收到消息。反过来,转换服务直接测试成功,也不代表 Alertmanager 的路由和 send_resolved 一定正确,两段验证各自解决不同问题。
分组、恢复与模板分开调
路由分组决定哪些告警被放进同一批通知。group_by 选择分组标签,group_wait 决定新分组首次通知前等待多久,group_interval 控制同一分组后续通知之间的最小间隔,而 repeat_interval 控制告警持续未恢复时的重复提醒周期。
因此,同一条告警按间隔再次出现,不一定是 Webhook 被重复调用,也可能是 Alertmanager 按 repeat_interval 正常重发。测试时先把重复周期设置得足够短,但不要为了测试永久保留高频提醒。
恢复通知是另一条独立链路。webhook_configs.send_resolved: true 允许 Alertmanager 发送 resolved 消息;告警本身也必须真正结束,而不是仅仅在钉钉消息里手工标记。转换服务还需要支持当前消息格式中的恢复状态。遇到“钉钉能收到故障,却收不到恢复”,应把 send_resolved、告警结束时间和转换服务三者分开检查。
静默和抑制同样不属于模板问题。静默会阻止匹配告警继续通知,抑制规则会在另一条告警存在时抑制相关告警;如果 Alertmanager 页面里能看到告警,但转换服务没有对应请求,需要先排除静默与抑制。
模板只负责决定消息长什么样。prometheus-webhook-dingtalk 支持 Go template,相关资料给出了 --web.enable-ui 参数和 http://localhost:8060/ui 预览入口,可用来检查标题、标签、注解和恢复状态是否渲染正确;具体启动参数仍以安装版本为准。 @所有人 则由转换服务的 webhook_mention_all 控制,不要把它误写成 Alertmanager 路由条件。
跨网地址必须单独验证
跨网部署时,每一段地址都要从请求发起方的网络命名空间验证,而不是从运维人员所在电脑验证。
同一台主机上的宿主机进程,可以使用回环地址;同一 Docker 网络中的容器,应优先使用服务名;不同主机或不同网络,则需要可路由的 IP 或 DNS。Prometheus 指向 Alertmanager 的 9093 端口,Alertmanager 指向转换服务的 8060 端口,这是两条独立的连接路径,其中任何一条不通都会让整条告警链断开。
可以先检查 TCP 和 HTTP 层:
nc -vz alertmanager 9093
curl -fsS 'http://alertmanager:9093/-/ready'
nc -vz prometheus-webhook-dingtalk 8060
这些命令要在实际发起请求的容器或主机上执行。参考文章中的跨网案例使用 TCP 公网入口连接 Alertmanager 的 9093 端口,但那只是一种特定网络条件下的连通方案,不应把公网映射当成通用部署方式。管理端口直接暴露还会扩大可被滥用的入口,需要结合访问来源限制或受控反向代理处理。
方案选择与上线边界
默认方案仍然是 webhook_configs 加 prometheus-webhook-dingtalk:Alertmanager 保留分组、静默、抑制和恢复通知能力,转换服务负责适配钉钉消息格式。自建转换程序只有在格式、鉴权或内部集成需求无法由现成服务满足时才值得采用。
这套方案也有明确边界:prometheus-webhook-dingtalk 是第三方组件,接口路径、启动参数和配置格式可能随版本变化;机器人令牌需要单独保管;转换服务本身也是一个需要监控的单点。本文不声称在特定环境中实测,也不虚构终端输出。上线前至少应固定组件版本,分别完成转换服务直连和 Prometheus 全链路测试,再单独评估高可用、密钥轮换与跨网访问策略。












暂无评论内容