第4章 告警源接入:常见监控系统告警接入方法

好,我们来聊个硬核话题——怎么把Zabbix、Prometheus、Grafana这些监控系统的告警,真正接到我们的工单系统里。说实话,这是整个告警处置流程的“水龙头”。开小了,故障没人发现;开大了,告警洪峰能把你淹没。

我见过不少团队,监控系统跑了大半年,告警全堆在邮件里没人管。为什么?就是没和工单系统打通嘛。你想想看,告警不转化成工单,就没有责任人、没有SLA、没有闭环。说白了,这步不做好,后面都是白搭。

核心原则:告警接入不是传数据,而是传 责任。每条告警都必须有明确的归属、时限和处置路径。

告警源接入核心逻辑 Zabbix Prometheus Grafana 告警过滤 / 格式化 去重 / 压缩 / 路由 工单系统 API 自动创建 / 升级 / 关闭 ⚠ 关键要点 1. 每条告警必须携带:主机标识、告警级别、触发时间、问题描述 2. 工单系统应返回 ticket_id,用于后续状态同步

4.1 Zabbix 告警接入

Zabbix 是我最早接触的监控系统。那时候还没 Prometheus 什么事儿呢。Zabbix 的告警接入方式很成熟,主要走 Action 动作 + 自定义脚本。

组件 用途 我踩过的坑
Action 定义触发条件(触发器级别、标签等) 默认条件太宽,导致告警泛滥
Media Type 脚本类型(Webhook、Email、自定义脚本) 脚本执行用户权限不足,常见
自定义脚本 调用工单 API 创建工单 超时设置太短,API 响应慢就丢告警

具体怎么做?我给你看一个标准的 Media Type 脚本框架。这里我们用 Python 写,调用工单系统的 REST API。

#!/usr/bin/env python3
# zabbix_to_ticket.py — 我自己项目里一直在用

import requests
import sys
import json

# 从 Zabbix 传递过来的宏
alert_subject = sys.argv[1]   # {ALERT.SUBJECT}
alert_message = sys.argv[2]   # {ALERT.MESSAGE}
alert_summary = f"{alert_subject}\n{alert_message}"

payload = {
    "title": f"[Zabbix] {alert_subject}",
    "description": alert_summary,
    "source": "zabbix",
    "priority": "P2" if "Critical" in alert_subject else "P3",
    "notify": ["ops-group"]  
}

# 你的工单系统 API 地址
ticket_api = "http://your-ticket-system/api/v1/tickets"
headers = {"Authorization": "Bearer YOUR_"}

try:
    resp = requests.post(ticket_api, json=payload, headers=headers, timeout=10)
    if resp.status_code == 201:
        ticket_id = resp.json().get("id")
        print(f"OK: Ticket #{ticket_id} created")
    else:
        print(f"FAIL: {resp.status_code} {resp.text}")
        sys.exit(1)
except Exception as e:
    print(f"FAIL: {e}")
    sys.exit(1)

曾经的教训:有一次我忘了在 Zabbix 的 Action 里勾选“自定义脚本”的执行用户。结果脚本以 nobody 用户运行,写日志的目录权限不对,脚本直接静默失败了。告警丢了两个多小时才发现。所以,一定要在脚本里加错误输出,并且 Zabbix 要配置收错误反馈。

4.2 Prometheus & Alertmanager 告警接入

Prometheus 告警走一条很清晰的链路:Prometheus Server 计算告警 -> Alertmanager 做分组/抑制/静默 -> 再发送出去。你想想看,Alertmanager 就像个水流调节阀,特别好用。

我建议你直接用 Alertmanager 的 Webhook Receiver,直接把告警 JSON 发给工单系统。不需要中间转一手。

看一下 Alertmanager 的配置片段:

# alertmanager.yml
receivers:
  - name: 'ops-ticket-webhook'
    webhook_configs:
      - url: 'http://your-ticket-system/api/v1/alertmanager'
        send_resolved: true
        http_config:
          basic_auth:
            username: 'alertmanager'
            password: 'your-password'

设计时的习惯:我会在工单系统里专门写一个接口,只消费 Alertmanager 的 JSON。然后把 labels、annotations 里的关键字段(alertname、severity、instance)直接映射成工单属性。这样告警创建工单,resolution 后自动关单。

Prometheus 的告警 JSON 结构大概长这样。这里的是简化版本,但核心字段都保留了。

{
  "receiver": "ops-ticket-webhook",
  "status": "firing",
  "alerts": [
    {
      "status": "firing",
      "labels": {
        "alertname": "HighMemoryUsage",
        "instance": "web-01:9100",
        "severity": "critical"
      },
      "annotations": {
        "summary": "Memory usage > 90%",
        "description": "web-01 memory usage at 94%"
      },
      "startsAt": "2025-04-01T10:00:00Z",
      "endsAt": "0001-01-01T00:00:00Z"
    }
  ]
}

工单系统收到这个 JSON,如果 status 是 firing,就创建或更新工单;如果是 resolved,就自动关闭工单。这个闭环很干净。

核心经验:send_resolved 一定要设为 true。不然告警恢复了,工单还打开着。我记得有一次漏配了,线上告警恢复了三天,工单还挂在“处理中”。运维同学盯着那个工单看了两天,以为是新告警。浪费了不少人力。

4.3 Grafana 告警接入

Grafana 的告警接入稍微特殊一点。它是可视化层,告警规则写在 Dashboard 或 Alerting 模块里。我个人的看法是,Grafana 适合做 辅助告警源,比如业务监控面板里的阈值告警,不太建议用它当唯一告警源。

Grafana 支持 Webhook 渠道,和 Alertmanager 类似。配置起来很快:

# 进入 Grafana 的 Alerting -> Contact points -> 新建
# 类型选 Webhook

URL: http://your-ticket-system/api/v1/grafana
可选设置:
  - 勾选 "Disable Resolve Message" (如果你想让工单系统自己判断)
  - 自定义 HTTP Header: X-Source: grafana

Grafana 发出来的告警 JSON 和 Prometheus 有些区别。它会带一个 dashboardId 和 panelId,这个在回查问题时特别方便。

{
  "title": "[Alerting] CPU Load High",
  "state": "alerting",
  "message": "CPU load on server-04 > 90% for 5 min",
  "orgId": 1,
  "dashboardId": 42,
  "panelId": 8,
  "tags": {
    "severity": "warning",
    "team": "platform"
  }
}

曾经的教训:Grafana 的告警重复发送很坑。默认配置下,每条告警每次评估都发一次。在没有降噪机制的情况下,我的工单系统被刷了上千条重复工单。后来我加了两个处理:一是在 Grafana 里拉长 Group wait 时间;二是在工单 API 里做 alert_id 的去重幂等。嗯,从此安心了。

4.4 告警接入的通用规范

不管用什么监控系统,接入工单系统时,有几个字段是必须有的。我整理了一个通用规范表,你直接拿去做 API 设计。我们曾因为字段不统一,运维同学在工单里到处翻日志,后来统一了标准,效率高了不少。

字段 说明 示例
alert_id 全局唯一标识,去重用 zabbix-12345 / prom-firing-678
title 简短标题,工单列表展示 [Critical] High Memory on web-01
severity 严重级别,映射工单优先级 critical / warning / info
source 告警来源标识 zabbix / prometheus / grafana
description 详细描述,处置参考 Memory usage at 94%, threshold 90%
start_at 触发时间,用于计算持续时长 2025-04-01T10:00:00Z

我个人习惯:工单系统收到告警后,立即返回一个 ticket_id。监控脚本把这个 id 写回告警的 annotation 里。后面关单、升级、备注都能关联上。这个双向关联,在复盘时特别好用。

好,告警接入这块基本就这些。每个监控系统都有自己的脾气,但核心逻辑是一样的:取告警、格式化、发工单、拿回执。把这些做稳了,后面的处置流程才有了根基。你想想看,是不是这个道理?