Zabbix 接入

工作原理

┌─────────────────────────────────────────────────────────────────────┐
│                          Zabbix Server                               │
│                                                                      │
│   Zabbix Agent ──checks──→ Items → Triggers ──events──→ 灵王OPS    │
│                                              │                       │
│                                       (Webhook Media)                │
└─────────────────────────────────────────────────────────────────────┘

Zabbix 通过 Webhook Media Type 将告警事件推送到灵王 OPS。灵王 OPS 负责: - 告警去重(基于 host + event_id) - 按团队路由(通过 URL 中的 tenant_id) - 触发通知(邮件、钉钉、飞书等) - 告警历史与统计分析


前置条件

  • 已部署 Zabbix Server(4.0 及以上)
  • 可访问灵王 OPS 的 :8080 端口
  • 知道你的团队 ID(在团队页面 → 团队设置中查看)

Zabbix Webhook 配置

创建 Media Type

  1. 登录 Zabbix Web UI
  2. 进入 Administration → Media types
  3. 点击 Create media type
  4. 配置以下参数:
参数
Name 灵王 OPS Webhook
Type Webhook
Script 见下方脚本

Webhook Script (JavaScript):

var ZabbixWebhook = function(params) {
    var url = params.url;
    var topic = params.topic;
    var proxy = params.proxy;

    var req = new CurlHttpRequest();
    if (proxy) {
        req.setProxy(proxy);
    }
    req.addHeader('Content-Type: application/json');

    var body = JSON.stringify({
        request: "sender_data",
        host: params.host,
        events: [{
            eventid: params.eventid,
            clock: params.clock,
            ns: params.ns || "0",
            severity: params.severity,
            name: params.triggername,
            triggers: [{
                triggerid: params.triggerid,
                expression: params.expression,
                description: params.triggername,
                severity: params.severity,
                status: params.triggerstatus,
                priority: params.priority
            }]
        }]
    });

    Zabbix.log(4, '[ Zabbix Webhook ] Sending request: ' + body);

    var response = req.post(url, body);

    Zabbix.log(4, '[ Zabbix Webhook ] Response: ' + response);

    if (req.Status() !== 200) {
        throw 'Webhook request failed with status ' + req.Status();
    }

    try {
        var result = JSON.parse(response);
        if (result && result.info) {
            Zabbix.log(4, '[ Zabbix Webhook ] Success: ' + result.info);
        }
    } catch (e) {
        Zabbix.log(4, '[ Zabbix Webhook ] Parse error: ' + e);
    }

    return response;
};

try {
    var params = JSON.parse(value);
    var url = params.url;
    var topic = params.topic || '';
    var proxy = params.proxy || '';

    // 构建 URL(包含 tenant_id)
    var webhook_url = url.replace('{team_id}', params.team_id);

    ZabbixWebhook({
        url: webhook_url,
        topic: topic,
        proxy: proxy,
        host: params.host,
        eventid: params.eventid,
        clock: params.clock,
        ns: params.ns,
        severity: params.severity,
        triggername: params.triggername,
        triggerid: params.triggerid,
        expression: params.expression,
        triggerstatus: params.triggerstatus,
        priority: params.priority
    });

    return 'OK';
} catch (e) {
    Zabbix.log(4, '[ Zabbix Webhook ] Exception: ' + e);
    throw 'Webhook error: ' + e;
}

配置 Parameters

在 Webhook 的 Parameters 标签页添加以下参数:

Parameter Value
url http://ops.sengyueplay.com:8080/api/v1/alerts/zabbix/{team_id}
team_id {ALERT.TEMPLATE.ID} 或固定团队 ID
host {HOST.HOST}
eventid {EVENT.ID}
clock {EVENT.TIME}
ns {EVENT.NSEVENT}
severity {EVENT.SEVERITY}
triggername {TRIGGER.NAME}
triggerid {TRIGGER.ID}
expression {TRIGGER.EXPRESSION}
triggerstatus {TRIGGER.STATUS}
priority {TRIGGER.PRIORITY}

高级配置

选项
Process tags ☑️ 启用
Full event details ☑️ 启用
Retry interval 10s
Timeout 10s

告警恢复(Problem Recovery)

Zabbix 原生 Webhook 不支持自动发送恢复通知,但可以通过以下方式实现:

方式一:使用 {EVENT.RECOVERY_STATUS}

更新 Webhook Script 支持恢复事件:

// 在 Webhook Script 开头添加
var event_status = params.event_status || "PROBLEM";

if (event_status === "RESOLVED") {
    Zabbix.log(4, '[ Zabbix Webhook ] Skipping recovery event (handled separately)');
    return 'OK';
}

在 Parameters 中添加:

Parameter Value
event_status {EVENT.RECOVERY_STATUS}

方式二:配置 Recovery operations

在 Zabbix Actions 中配置 Recovery operations:

  1. 进入 Configuration → Actions
  2. 选择 Recovery actions 或创建新动作
  3. Operations 中添加 Webhook,Parameters 同上

方式三:通过 Zabbix Problem 页面手动确认

当问题在 Zabbix 中恢复后,事件会自动标记,灵王 OPS 会通过定时同步获取状态变化。


告警级别映射

Zabbix Severity 灵王 OPS Severity
Not classified (0) info
Information (1) info
Warning (2) medium
Average (3) high
High (4) high
Disaster (5) critical

验证接入

手动发送测试告警

# 获取团队 ID(替换为你的)
TEAM_ID="your-team-id"

curl -X POST "http://localhost:8080/api/v1/alerts/zabbix/${TEAM_ID}" \
  -H "Content-Type: application/json" \
  -d '{
    "request": "sender_data",
    "host": "web-server-01",
    "events": [
      {
        "eventid": "12345",
        "clock": "'"$(date +%s)"'",
        "ns": "123456789",
        "severity": "3",
        "name": "High CPU usage on web-server-01",
        "triggers": [
          {
            "triggerid": "10001",
            "expression": "nodata(/CPU,10m)",
            "description": "High CPU usage on web-server-01",
            "severity": "3",
            "status": "0",
            "priority": "3"
          }
        ]
      }
    ]
  }'

验证告警列表

登录管理后台 → 告警页面,确认测试告警出现。


多团队配置

如果你的 Zabbix 管理多个团队的告警,可以通过模板或主机组区分:

方式一:通过不同 Media Type

为每个团队创建独立的 Webhook Media Type:

Media Type 1: url = http://ops.sengyueplay.com:8080/api/v1/alerts/zabbix/{team_id_A}
Media Type 2: url = http://ops.sengyueplay.com:8080/api/v1/alerts/zabbix/{team_id_B}

方式二:通过脚本动态获取 team_id

在 Webhook Script 中根据主机信息动态设置 team_id:

// 在 Webhook Script 中
var hostgroup = params.host_group || '';

if (hostgroup.indexOf('TeamA') !== -1) {
    params.team_id = 'team-a-uuid';
} else if (hostgroup.indexOf('TeamB') !== -1) {
    params.team_id = 'team-b-uuid';
} else {
    params.team_id = 'default-team-uuid';
}

var webhook_url = url.replace('{team_id}', params.team_id);

Parameters 中添加:

Parameter Value
host_group {HOSTGROUP.NAME}

故障排查

告警未出现在平台

  1. 确认 Webhook 已正确配置并启用
  2. 检查 Media 已关联到用户(Administration → Users → Media)
  3. 确认 URL 可达:curl -v http://ops.sengyueplay.com:8080/health
  4. 查看 Zabbix Server 日志:tail -f /var/log/zabbix/zabbix_server.log
  5. 查看灵王 OPS 后端日志:tail -f /tmp/lingwang.log

Webhook 发送失败

  1. 检查 Webhook 脚本语法是否正确
  2. 确认 Zabbix Server 能够访问灵王 OPS 地址
  3. 检查超时设置(建议 10s)
  4. 查看 Zabbix Audit log 中的 Webhook 执行记录

告警重复

  • Zabbix 的去重基于 host + event_id
  • 如果同一触发器产生多个事件,会创建多个告警
  • 可以在 Zabbix 中调整 trigger 的 Recovery expression 减少重复

告警级别不正确

  • 确认 Zabbix 的 Severity 值正确传递
  • 检查 {EVENT.SEVERITY} 参数是否包含有效值(0-5)
  • 检查 severity 映射是否正确

性能与限制

项目 限制
单次请求最大事件数 100 条
请求超时 10s
Webhook 重试次数 3 次
建议 Retry interval 10s

完整配置示例

Administration → Media types → Create media type

Name: 灵王 OPS Webhook
Type: Webhook
Script: [见上方 Webhook Script]
Parameters:
  - url = http://ops.sengyueplay.com:8080/api/v1/alerts/zabbix/{team_id}
  - team_id = your-team-uuid
  - host = {HOST.HOST}
  - eventid = {EVENT.ID}
  - clock = {EVENT.TIME}
  - ns = {EVENT.NSEVENT}
  - severity = {EVENT.SEVERITY}
  - triggername = {TRIGGER.NAME}
  - triggerid = {TRIGGER.ID}
  - expression = {TRIGGER.EXPRESSION}
  - triggerstatus = {TRIGGER.STATUS}
  - priority = {TRIGGER.PRIORITY}

Process tags: ✓
Full event details: ✓
Timeout: 10s
Retry interval: 10s

Administration → Users → Media

Type: 灵王 OPS Webhook
Send to: (留空或填写任意值,team_id 在 Parameters 中配置)
When active: 1-7,00:00-24:00
Use if severity: (选择需要的级别)
Status: Enabled