第4章 告警源接入:常见监控系统告警接入方法
好,我们来聊个硬核话题——怎么把Zabbix、Prometheus、Grafana这些监控系统的告警,真正接到我们的工单系统里。说实话,这是整个告警处置流程的“水龙头”。开小了,故障没人发现;开大了,告警洪峰能把你淹没。
我见过不少团队,监控系统跑了大半年,告警全堆在邮件里没人管。为什么?就是没和工单系统打通嘛。你想想看,告警不转化成工单,就没有责任人、没有SLA、没有闭环。说白了,这步不做好,后面都是白搭。
核心原则:告警接入不是传数据,而是传 责任。每条告警都必须有明确的归属、时限和处置路径。
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 里。后面关单、升级、备注都能关联上。这个双向关联,在复盘时特别好用。
好,告警接入这块基本就这些。每个监控系统都有自己的脾气,但核心逻辑是一样的:取告警、格式化、发工单、拿回执。把这些做稳了,后面的处置流程才有了根基。你想想看,是不是这个道理?