第2章 告警源集成:Prometheus、Zabbix、Grafana 对接方法归纳总结
告警源集成,说白了就是把监控系统的告警事件“喂”给告警工单系统。这一步要是没做好,后面闭环做得再漂亮也是白搭。我早期接手的几个项目,问题都出在对接层——要么告警丢了,要么重复推送,要么字段对不上。
这一章,我把三种主流监控系统的对接套路拆开揉碎,讲清楚原理、配置和常见坑。你先看张总览图,心里有个脉络。
2.1 Prometheus + Alertmanager:Webhook 是标配
Prometheus 本身只负责采集和存储指标,告警规则定义在独立文件里。触发告警后,由 Alertmanager 负责路由、抑制、静默和发送。对接工单系统,最直接的方式就是使用 Alertmanager 的 Webhook receiver。
对接流程一句话:配置 alerting rule → Alertmanager 匹配路由 → 调用你的 Webhook URL → 解析 JSON 并创建工单。
核心配置示例
在 Alertmanager 的配置文件里加一个 receiver,指向你的告警接收服务。我在项目里是这样写的:
# alertmanager.yml 片段
route:
group_by: ['alertname', 'instance']
group_wait: 10s
group_interval: 30s
repeat_interval: 4h
receiver: 'webhook-to-tickets'
receivers:
- name: 'webhook-to-tickets'
webhook_configs:
- url: 'http://your-ticket-service/api/v1/alert'
send_resolved: true
http_config:
basic_auth:
username: 'alertmanager'
password: 'you-should-use-secret'
这里面有一个我踩过的坑:send_resolved: true 必须打开,否则恢复告警不会推送给工单系统,导致工单永远无法自动关闭。别问我怎么知道的……
我个人习惯:在 Webhook 接收端做一层简单的幂等校验。Prometheus 的告警可能在网络抖动时重复推送,利用 fingerprint 或 alertname+instance 作为唯一键,防止重复工单。
字段映射表
Prometheus 的告警 JSON 结构比较标准,你需要把以下字段映射到工单系统:
| Prometheus 字段 | 说明 | 建议映射到工单字段 |
|---|---|---|
| labels.alertname | 告警名称 | 标题 |
| labels.severity | 严重级别 (critical/warning/info) | 优先级 |
| labels.instance | 实例标识 | 资源名称 |
| annotations.summary | 概要描述 | 描述 |
| annotations.description | 详细描述 | 详情 |
| startsAt | 触发时间 | 发现时间 |
| endsAt | 恢复时间(resolved 时有效) | 解决时间 |
注意:severity 字段的值通常是小写英文,工单系统里可能是中文或数字级别的,记得做一层映射。我曾经用 critical → P1、warning → P2、info → P3 来对应。
2.2 Zabbix:Action + Script 是最灵活的方式
Zabbix 的对接方式比 Prometheus 要多一些。官方支持 Webhook(6.0 以后),但很多老项目还在用 Action + Script 的方式。我个人更推荐后者,因为可定制空间大,而且不依赖 Zabbix 版本。
基本原理:Zabbix 触发告警时 → 执行 Action → 调用自定义脚本(如 Python 或 Shell)→ 脚本把告警信息 POST 到工单接口。
关键步骤:
- 在 Zabbix 前端创建 Action,触发器条件按需设置。
- Action 的 Operation 类型选“Remote command”,指定脚本路径。
- 脚本通过环境变量或参数接收告警信息。
脚本接收参数示例
#!/bin/bash
# alert_to_ticket.sh
# 接收 Zabbix 传过来的参数
ALERT_SUBJECT="$1"
ALERT_MESSAGE="$2"
ALERT_SEVERITY="$3"
# 构造 JSON
PAYLOAD=$(cat <<EOF
{
"title": "$ALERT_SUBJECT",
"message": "$ALERT_MESSAGE",
"severity": "$ALERT_SEVERITY",
"source": "zabbix",
"trigger_time": "$(date -u +'%Y-%m-%dT%H:%M:%SZ')"
}
EOF
)
curl -X POST -H "Content-Type: application/json" \
-d "$PAYLOAD" \
http://your-ticket-service/api/v1/alert
避坑指南:我曾经在 Zabbix 5.4 里用 Webhook 原生功能,发现它不支持自定义 HTTP Header。后来改回 Action+Script,轻松解决了认证问题。所以你如果用的是老版本,别硬上 Webhook。
Zabbix 6.0+ 原生 Webhook 配置
如果你用新版本,可以直接用 Mediatypes 里的 Webhook 模板。我建议复制一份默认模板再改:
- Administration → Media types → Create media type
- Type 选 Webhook,填写你的告警 URL
- Parameter 设置:
{ALERT.SUBJECT},{ALERT.MESSAGE},{ALERT.SEVERITY} - Script 里用 JavaScript 拼接 HTTP 请求——Zabbix 内部用的是 Go 的 JS 引擎。
2.3 Grafana:Alerting 模块的 Webhook 集成
Grafana 8.0 之后重构了告警模块,现在叫 Grafana Alerting。它统一了来自 Prometheus、Loki、Tempo 等数据源的告警规则,然后通过“通知策略”发送。对接工单系统同样用 Webhook。
你想想看,如果你团队已经用 Grafana 做统一监控面板,那直接在 Grafana 里配告警,再推给工单系统,是最省事的。少维护一个中间件。
配置路径
- Alerting → Contact points → New contact point
- Type 选 Webhook,填写 URL
- 可选设置:Basic Auth、TLS、自定义 HTTP Header
- Notification policy 里选择该 contact point
Grafana 告警 JSON 示例(部分关键字段):
{
"status": "firing",
"labels": { "alertname": "HighCPU", "instance": "web-01" },
"annotations": { "summary": "CPU > 90%", "description": "实例 web-01 的 CPU 已持续 5 分钟 > 90%" },
"startsAt": "2025-01-20T10:00:00Z",
"endsAt": "0001-01-01T00:00:00Z",
"generatorURL": "http://grafana/explore..."
}
这个结构和 Prometheus 的相似,但多了 generatorURL,非常有用——你可以把它放进工单的“关联链接”里,工程师点一下就能跳到 Grafana 看当时的时序图。我每接手一个新项目,第一件事就是把这个链接补上,排查效率翻倍。
注意:Grafana Alerting 默认对同一个告警实例的重复通知有抑制,但如果你配置了多个通知策略,可能会收到重复工单。建议在工单接收端做去重,或者把 notification policy 的“分组”设置得严格一些。
2.4 三种对接方式对比
表格一看就清楚,哪种场景用哪种方案:
| 特性 | Prometheus + Alertmanager | Zabbix Action+Script | Grafana Alerting |
|---|---|---|---|
| 配置复杂度 | 低(标准 Webhook) | 中(需写脚本) | 低(UI 配置) |
| 版本兼容 | 所有版本 | 所有版本(推荐) | Grafana 8.0+ |
| 可定制性 | 中等(JSON 固定格式) | 高(脚本任意改造) | 中等(模板有限) |
| 数据处理能力 | Alertmanager 支持路由、抑制 | 需自己处理去重 | 内置分组、抑制 |
| 工单系统对接 | 直接 POST JSON | 任意 HTTP 调用 | 直接 POST JSON |
| 社区成熟度 | 极高 | 极高 | 中高 |
2.5 我在实践中总结的几条铁律
- 统一告警格式:不管你接多少监控源,工单系统看到的字段结构必须一致。我自己的做法是做一个“告警数据清洗层”,把 Prometheus/Zabbix/Grafana 的 JSON 都转成统一的 schema,再塞给工单 API。
- 一定要加 Unique ID:每个告警实例需要一个全局唯一 ID。Prometheus 用 fingerprint,Zabbix 用 event_id,Grafana 用 fingerprint 加时间戳。工单系统拿这个 ID 做幂等,重复推送不会产生重复工单。
- 重试与超时:工单服务偶尔会挂,Webhook 发不出去怎么办?Alertmanager 默认会重试多次,但时间间隔不短。我建议在接收端用队列缓冲(比如 Redis List 或 Kafka),让告警先入队,再异步消费。这样哪怕工单系统重启,告警也不会丢。
- 恢复告警闭环:一定要把“resolved”推送给工单系统。如果不推,工单永远处于“处理中”状态,闭环就是个笑话。嗯,这个前面提过,但值得再说一次。
关于告警风暴的处理:我曾经在双十一大促碰到告警风暴——几百个实例同时 CPU 飙高,Alertmanager 的 Webhook 瞬间被击穿,工单系统直接 502。后来我在 Webhook 前加了一层简单的限流:令牌桶算法,每秒最多 50 个请求进工单系统,其余的丢到队列里慢慢处理。虽然工单会延迟几分钟,但系统稳住了。这件事告诉我,对接层必须考虑限流和降级。