我们前几篇把吐槽最多的坑补齐了,并且机器也纳管进来了,大屏也投上了。但是,有个重点的事情每有做-有效的监控没有做。
我的邮箱里至今躺着几千封告警邮件,删都没删过,但也没怎么看过。真正让监控产生价值的那一刻,是告警日志发送到运维同事的手机上、并且他愿意点开。
所以这篇讲的是:怎么把 Zabbix 的告警精准送到钉钉群和企业微信群里。我会给你可复制的 Webhook 脚本、逐项的参数表、路由矩阵,以及一张我整理的排错清单。
Zabbix 到 IM 群,一共三跳

整条链路就这五步,每一步都可能断:
触发器亮红灯 → 2. 动作(Action)匹配成功 → 3. 媒介类型(Media type)被调用 → 4. HTTP 请求打到机器人 → 5. 群里出现消息
我见过最多的问题是:第 2 步没配、第 4 步签名错、第 5 步把自己限流了。下面逐个拆。
先说清楚一条红线,钉钉和企微都一样:每个机器人每分钟最多 20 条消息。钉钉超了限流 10 分钟,企微直接给你 45009 api freq out of limit。注意,限流恰恰发生在故障最密集、你最需要它的那一刻——这条决定了下面所有的设计思路。
方案选型:三条路,我推荐第二条
| 邮件转发 | |||
| Webhook 媒介类型 | |||
| 自定义告警脚本 | AlertScriptsPath |
我个人推荐 Webhook 媒介类型:媒介类型在数据库里跟着备份走,不用 ssh 上去找脚本文件;需要复杂逻辑(比如代理、重试、聚合)再走 Python 脚本方案,文章后面也给了。
(我现在用的很多企业为微信的消息推送,也是webhook,这个是最简单的方式,只需要提供接口和需要传输的信息就好了,个人认为很方便。)
第一站:把机器人建出来
钉钉:群 > 群设置 > 智能群助手 > 添加机器人 > 自定义

上图是钉钉的webhook设置页面
创建完给两样东西,都存好:
Webhook 地址:形如 https://oapi.dingtalk.com/robot/send?access_token=xxxxx加签密钥: SEC开头的一串(只显示一次,关了就再也看不到)
安全设置有三种,选型建议一并给你:
| 不推荐 | ||
| 推荐 | ||
企业微信:群 > 右上角「三个点」> 消息推送 > 添加
官方现在叫「消息推送」(早些年的名字是"群机器人"),拿到形如 https://qyapi.weixin.qq.com/cgi-bin/webhook/send?key=xxxxx 的地址。
企微这边有几个硬约束要提前知道:外部群不支持添加,必须是纯企业微信群;Markdown 不支持表格和图片;没有加签机制,所以 Webhook 地址本身就是凭证,别截图发群里、别提交到代码仓库。
Zabbix 侧的 Webhook 媒介类型
路径:告警 → 媒介 → 创建媒介类型(部分版本在「管理 → 报警媒介类型」)。

类型选 Webhook,参数按下表填(顺序无所谓,名字要对得上):
钉钉脚本(带加签,可直接复制)
try {
Zabbix.Log(4, '[DingTalk] webhook value: ' + value);
var params = JSON.parse(value),
req = new HttpRequest(),
resp;
// 1) 加签:把 timestamp + "\n" + secret 做 HMAC-SHA256
var timestamp = Date.now().toString();
var stringToSign = timestamp + '\n' + params.secret;
// 坑点:Zabbix 的 hmac() 返回的是十六进制字符串,钉钉要的是 Base64
var hexDigest = hmac('sha256', params.secret, stringToSign);
var bin = '';
for (var i = 0; i < hexDigest.length; i += 2) {
bin += String.fromCharCode(parseInt(hexDigest.substr(i, 2), 16));
}
var sign = encodeURIComponent(btoa(bin));
// 2) 拼接签名后的 URL
var url = params.webhook_url + '×tamp=' + timestamp + '&sign=' + sign;
// 3) 组装 markdown 消息
var data = {
msgtype: 'markdown',
markdown: { title: params.subject, text: params.message },
at: { atMobiles: [], isAtAll: false }
};
if (params.at_mobiles) {
var mobiles = params.at_mobiles.split(','),
atText = '';
for (var j = 0; j < mobiles.length; j++) {
atText = atText + ' @' + mobiles[j];
}
data.at.atMobiles = mobiles;
data.markdown.text = params.message + '\n\n' + atText;
}
req.addHeader('Content-Type: application/json');
resp = req.post(url, JSON.stringify(data));
Zabbix.Log(4, '[DingTalk] HTTP ' + req.getStatus() + ' resp: ' + resp);
if (req.getStatus() < 200 || req.getStatus() > 299) {
throw 'HTTP status ' + req.getStatus();
}
// HTTP 200 也可能是业务失败,必须看 errcode
var ret = JSON.parse(resp);
if (ret.errcode !== 0) {
throw 'DingTalk errcode ' + ret.errcode + ': ' + ret.errmsg;
}
return JSON.stringify({ tags: { result: 'ok' } });
} catch (error) {
Zabbix.Log(4, '[DingTalk] send failed: ' + error);
throw 'DingTalk send failed: ' + error;
}
这里有两个坑我一并说了:一是 hmac() 返回十六进制而钉钉要 Base64,必须转换,不然永远返回 310000;二是时间戳要求毫秒级,而且服务器时间漂太多签名会失效,务必给 Zabbix 服务器配上 NTP。
企业微信脚本(无需加签)
try {
Zabbix.Log(4, '[WeCom] webhook value: ' + value);
var params = JSON.parse(value),
req = new HttpRequest(),
data = {
msgtype: 'markdown',
markdown: { content: '### ' + params.subject + '\n' + params.message }
};
// 需要 @ 人时填手机号(多个用英文逗号分隔)
if (params.at_mobiles) {
data.markdown.mentioned_mobile_list = params.at_mobiles.split(',');
}
req.addHeader('Content-Type: application/json');
var resp = req.post(params.webhook_url, JSON.stringify(data));
Zabbix.Log(4, '[WeCom] HTTP ' + req.getStatus() + ' resp: ' + resp);
var ret = JSON.parse(resp);
if (ret.errcode !== 0) {
throw 'WeCom errcode ' + ret.errcode + ': ' + ret.errmsg;
}
return JSON.stringify({ tags: { result: 'ok' } });
} catch (error) {
Zabbix.Log(4, '[WeCom] send failed: ' + error);
throw 'WeCom send failed: ' + error;
}
注:企微 @ 人的字段名(
mentioned_mobile_list/mentioned_list)以官方文档为准,如有变化请自行调整。
配完别急着闭环,媒介类型列表那一行右侧有个「测试」按钮,点它会让你填参数,能当场看到返回值——这是排查问题最快的方式。
消息模板别再写ABC
切到媒介类型的「消息模板」标签页,分别给 Problem(故障)、Problem recovery(恢复)、Problem update(更新)配内容。

故障标题:
故障 {TRIGGER.SEVERITY}:{HOST.NAME} {TRIGGER.NAME}
故障正文(Markdown):
**【告警】{EVENT.SEVERITY}**
> 主机:{HOST.NAME}
> 时间:{EVENT.DATE} {EVENT.TIME}
> 详情:{TRIGGER.NAME}
> 当前值:{ITEM.LASTVALUE}
> 事件ID:{EVENT.ID}
> 处理:到 监测-问题 里按事件ID检索
(文中为了避开渲染,宏用了全角花括号,实际请换成英文半角的 { })
恢复正文照猫画虎,但一定要带上 持续时长 宏,方便事后复盘 MTTR。
Actions 才是"精准"的关键
前面全是"怎么发",这一段才是"发给谁"。
路径:告警 → 动作 → 触发器动作 → 创建动作。
参考这张路由矩阵去配多条动作:

具体怎么落地,我给你一套规则:
条件(Conditions)怎么组合
主机组 等于 Linux-Payment | |
触发器严重性 大于等于 Average | |
标签名 等于 scope标签值 等于 支付 | |
主机名称 包含 test |
前提是你在主机上打好了标签(主机 → 标签),比如 scope: 支付、owner: 张三。标签是这套精准路由的地基,前面几篇纳管主机时顺手打上最省事。
操作(Operations)三个都不能漏
Operations:发给对应媒介/用户组。同时打开阶梯升级,比如「步骤 1-2 每 10 分钟发一次给值班群;步骤 3-5 发给组长并 @ 手机号」——Zabbix 会在没被确认的情况下自动升级。 Recovery operations:这条 90% 的人忘配,结果就是只报不复,群里永远看不到"好了"。 Update operations:有人认领(Acknowledge)时同步到群里,避免两个人同时去处理同一台机器。
抑制与降噪的三个开关
动作里把 Maintenance status: Pause operations during maintenance勾上,计划维护期别刷屏;只把 Average 及以上送 IM,Warning 以下攒成日报; 用依赖关系(Host/Trigger dependencies)把"交换机挂了导致下面 50 台主机全红"收敛成一条。
这几件事做完,你把 20 条/分钟的红线从"天天踩"变成"基本不碰"。
排错清单:出问题先查这张表
310000 | grep DingTalk /var/log/zabbix/zabbix_server.log | |
45009 | ||
errcode(如关键词不匹配 310000 之外的错误) | ||
AlertScriptsPath 或没执行权限 | grep AlertScriptsPath /etc/zabbix/zabbix_server.confchmod +x | |
chown zabbix:zabbix | ||
# -*- coding: utf-8 -*- | ||
| 服务器时间漂移 | timedatectl status | |
告警链路的工程难度不高,但它是整个监控体系唯一真正被人感知的部分。前面做纳管、做大屏、做高可用 Proxy,最后一段没打通,前面所有的努力都是摩尔定律级别的浪费。
我的经验是:宁可少发、不要多发。一条精准的 @ 你的 High 级告警,比五十条没人看的 Warning 有价值得多。
本文配置基于 Zabbix 7.0 LTS,界面文案与宏名称请以你实际版本的官方文档为准;第三方机器人接口的限流与安全策略可能调整,使用前建议再核一次官方公告。
本文链接:https://www.kinber.cn/post/6821.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:

支付宝微信扫一扫,打赏作者吧~
