`dingtalk_configs` 报错:告警送钉钉

先说结论: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 全链路测试,再单独评估高可用、密钥轮换与跨网访问策略。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容