HQY

×

Zabbix7告警之钉钉企微告警配置指导

hqy hqy 发表于2026-10-23 16:20:06 浏览4 评论0

抢沙发发表评论

我们前几篇把吐槽最多的坑补齐了,并且机器也纳管进来了,大屏也投上了。但是,有个重点的事情每有做-有效的监控没有做。

我的邮箱里至今躺着几千封告警邮件,删都没删过,但也没怎么看过。真正让监控产生价值的那一刻,是告警日志发送到运维同事的手机上、并且他愿意点开。

所以这篇讲的是:怎么把 Zabbix 的告警精准送到钉钉群和企业微信群里。我会给你可复制的 Webhook 脚本、逐项的参数表、路由矩阵,以及一张我整理的排错清单。

Zabbix 到 IM 群,一共三跳

图片

整条链路就这五步,每一步都可能断:

  1. 触发器亮红灯 → 2. 动作(Action)匹配成功 → 3. 媒介类型(Media type)被调用 → 4. HTTP 请求打到机器人 → 5. 群里出现消息

我见过最多的问题是:第 2 步没配、第 4 步签名错、第 5 步把自己限流了。下面逐个拆。

先说清楚一条红线,钉钉和企微都一样:每个机器人每分钟最多 20 条消息。钉钉超了限流 10 分钟,企微直接给你 45009 api freq out of limit。注意,限流恰恰发生在故障最密集、你最需要它的那一刻——这条决定了下面所有的设计思路。

方案选型:三条路,我推荐第二条

方案
做法
优点
缺点
邮件转发
发到 QQ/163 再走邮件提醒
零配置
送达慢、易被当作垃圾邮件、基本没人看
Webhook 媒介类型
(推荐)
Zabbix 7.0 原生 JS 脚本,界面里填
不用往服务器放文件、界面可维护、自带测试按钮
JS 环境是 Duktape,有些库没有
自定义告警脚本
Python 脚本放 AlertScriptsPath
完全可控,能做代理、重试、落盘日志、消息合并
要管文件权限、属主、SELinux

我个人推荐 Webhook 媒介类型:媒介类型在数据库里跟着备份走,不用 ssh 上去找脚本文件;需要复杂逻辑(比如代理、重试、聚合)再走 Python 脚本方案,文章后面也给了。

(我现在用的很多企业为微信的消息推送,也是webhook,这个是最简单的方式,只需要提供接口和需要传输的信息就好了,个人认为很方便。)


第一站:把机器人建出来

钉钉:群 > 群设置 > 智能群助手 > 添加机器人 > 自定义

图片

上图是钉钉的webhook设置页面

创建完给两样东西,都存好:

  • Webhook 地址:形如 https://oapi.dingtalk.com/robot/send?access_token=xxxxx
  • 加签密钥:SEC 开头的一串(只显示一次,关了就再也看不到)

安全设置有三种,选型建议一并给你:

方式
说明
我的评价
自定义关键词
消息里必须含某个词
不推荐
,知道了 URL 就能伪造
加签
HMAC-SHA256 签名
推荐
,不依赖固定 IP
IP 白名单
只允许指定出口 IP
出口 IP 固定的话可以叠加用

企业微信:群 > 右上角「三个点」> 消息推送 > 添加

官方现在叫「消息推送」(早些年的名字是"群机器人"),拿到形如 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 + '&timestamp=' + 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)三个都不能漏

  1. Operations:发给对应媒介/用户组。同时打开阶梯升级,比如「步骤 1-2 每 10 分钟发一次给值班群;步骤 3-5 发给组长并 @ 手机号」——Zabbix 会在没被确认的情况下自动升级。
  2. Recovery operations:这条 90% 的人忘配,结果就是只报不复,群里永远看不到"好了"。
  3. Update operations:有人认领(Acknowledge)时同步到群里,避免两个人同时去处理同一台机器。

抑制与降噪的三个开关

  • 动作里把 Maintenance status: Pause operations during maintenance 勾上,计划维护期别刷屏;
  • 只把 Average 及以上送 IM,Warning 以下攒成日报;
  • 用依赖关系(Host/Trigger dependencies)把"交换机挂了导致下面 50 台主机全红"收敛成一条。

这几件事做完,你把 20 条/分钟的红线从"天天踩"变成"基本不碰"。

排错清单:出问题先查这张表


现象
大概率原因
怎么验
返回 310000
加签算错:时间戳非毫秒、密钥错、没做 Base64 或 URL 编码
看服务端日志 grep DingTalk /var/log/zabbix/zabbix_server.log
企微返回 45009
超过 20 条/分钟
降噪或拆机器人分流
HTTP 200 但群里没消息
漏判了响应体里的 errcode(如关键词不匹配 310000 之外的错误)
看返回体 JSON
脚本方案完全没反应
脚本不在 AlertScriptsPath 或没执行权限
grep AlertScriptsPath /etc/zabbix/zabbix_server.conf
;chmod +x
权限报错
脚本属主不是 zabbix 用户
chown zabbix:zabbix
中文乱码
脚本未声明 UTF-8
Python 首行加 # -*- coding: utf-8 -*-
签名时好时坏
服务器时间漂移timedatectl status
,确认 chrony/NTP 在跑
恢复消息收不到
没配 Recovery operations
回到动作里补


告警链路的工程难度不高,但它是整个监控体系唯一真正被人感知的部分。前面做纳管、做大屏、做高可用 Proxy,最后一段没打通,前面所有的努力都是摩尔定律级别的浪费。

我的经验是:宁可少发、不要多发。一条精准的 @ 你的 High 级告警,比五十条没人看的 Warning 有价值得多。

本文配置基于 Zabbix 7.0 LTS,界面文案与宏名称请以你实际版本的官方文档为准;第三方机器人接口的限流与安全策略可能调整,使用前建议再核一次官方公告。


打赏

本文链接:https://www.kinber.cn/post/6821.html 转载需授权!

分享到:


推荐本站淘宝优惠价购买喜欢的宝贝:

image.png

 您阅读本篇文章共花了: 

群贤毕至

访客