# 用 ibex / Webhook 触发自愈

特定事件触发时，通过 ibex 在受影响主机上跑脚本，或调用一个 Webhook。

最后校对于 2026-10-10

这页办完你会得到：一条告警触发时，夜莺自动在**出问题的那台机器上**执行一段脚本， 执行结果、每台机器的 stdout / stderr 和退出码都能在界面上查到。

入口：**告警通知 → 告警自愈**，页面顶部两个 tab——**自愈脚本**（`/job-tpls`）和 **历史任务**（`/job-tasks`）。

## 开始之前[​](#开始之前 "开始之前的直接链接")

自愈走的是内置的 ibex 模块，不需要单独部署，但两端的开关都要打开。

**服务端**：`etc/config.toml` 里确认这一段（默认就是开的）：

```
[Ibex]

Enable = true

RPCListen = "0.0.0.0:20090"
```

改过就重启夜莺。20090 是 agent 拉取脚本任务、回传执行结果的 RPC 端口， 和 HTTP 端口是两个，防火墙上要单独放行。

**目标机器**：categraf 的 `conf/config.toml` 里把 ibex 打开，指向夜莺服务端：

```
[ibex]

enable = true

## ibex flush interval

interval = "1000ms"

## n9e ibex server rpc address

servers = ["127.0.0.1:20090"]

## temp script dir

meta_dir = "./meta"
```

`servers` 是数组，多实例部署时全填上，categraf 会自己挑延迟最小的那个，挂了会切。 机器超过一万台时把 `interval` 调大些（比如 `2500ms`），别把服务端压垮。改完重启 categraf。

开源版的 categraf 就带 ibex，不需要换版本。没装 categraf 的机器执行不了自愈脚本—— 新建自愈脚本的表单里也写着这条前置依赖。

## 1. 写一个自愈脚本[​](#1-写一个自愈脚本 "1. 写一个自愈脚本的直接链接")

**告警通知 → 告警自愈 → 自愈脚本**，点 **创建**：

| 字段      | 说明                                               |
| --------- | -------------------------------------------------- |
| Title     | 标题，说明这个脚本干什么                           |
| Tags      | 标签，用于分类                                     |
| Account   | 执行账号。慎用 root，除非确实要代表操作系统意志    |
| Batch     | 并发度。0（默认）全并发，1 顺序执行，2 每次两台    |
| Tolerance | 容忍几台失败。0（默认）一台都不容忍，失败立刻暂停  |
| Timeout   | 单机脚本超时秒数，默认 30                          |
| Host      | 执行机器列表。**自愈场景可以留空**，机器由事件决定 |
| Pause     | 暂停点，做完某台之后停一下                         |
| Script    | 脚本内容                                           |
| Args      | 附在脚本之后的参数，多个用双逗号分隔：`arg1,,arg2` |

脚本能拿到事件的标签：告警触发任务时，事件的全部标签会拼成一个 JSON 对象 **从标准输入喂给脚本**，另外附上 `alert_severity`（级别数字）、 `alert_trigger_value`（触发时值）、`is_recovered`。shell 脚本里这样读：

```
tags=$(cat)

ident=$(echo "$tags" | jq -r .ident)
```

## 2. 挂到告警规则上[​](#2-挂到告警规则上 "2. 挂到告警规则上的直接链接")

**告警通知 → 规则管理**，编辑一条规则，在通知配置那一段找到 **告警自愈**， 点加号加一行：

* **自愈模板**：选刚才建的那个（下拉里只列当前业务组的模板）；
* **执行机器**：**通常留空**。留空时从事件的 `ident` 标签取机器， 也就是「哪台机器出问题就在哪台上跑」。填了就固定在那几台上跑。

一条规则可以挂多行，触发时逐行执行。看不到「告警自愈」这一段，是因为你的角色没有 自愈脚本的权限，见[角色与权限](https://n9e.github.io/zh/docs/security/roles.md)。

## 3. 触发一次，去历史任务看结果[​](#3-触发一次去历史任务看结果 "3. 触发一次，去历史任务看结果的直接链接")

让规则真的烧一次（写一条必然触发的规则最快，见[测试触发](https://n9e.github.io/zh/docs/alerting/test-fire.md)）， 然后去 **告警自愈 → 历史任务**。

预期结果：多出一条任务，标题是「模板标题 FH: 机器名」。点进去能看到：

* 目标机器列表和每台的执行状态；
* 每台的 stdout / stderr；
* 退出码，0 成功、非 0 失败；
* 执行耗时。

一条都没有，就按下面这节逐条排查。

## 什么情况下不会执行[​](#什么情况下不会执行 "什么情况下不会执行的直接链接")

* **恢复事件不执行。** 只有告警触发会跑自愈，恢复不跑。
* **订阅出来的那一份不执行。** 自愈只挂在源规则上，跑一次；别的团队订阅了这条告警， 不会再触发一遍脚本。见[订阅规则](https://n9e.github.io/zh/docs/events/subscriptions.md)。
* **取不到机器就放弃。** 执行机器留空、事件又没有 `ident` 标签时，这次自愈直接跳过。 日志里能看到 `event_callback_ibex: failed to get host`。
* **权限不够不执行。** 后端会用**最后修改这个自愈模板的人**的身份，校验 「模板所属业务组 – 目标机器 – 执行账号」这个三元组。那个人没有这台机器的操作权限， 任务下不去。改过模板的人要确保自己对目标机器有权限。
* **目标机器上 categraf 没开 ibex。** 任务建出来了但一直没人来取，状态停着不动。

## 不想跑脚本，只想调一个 Webhook[​](#不想跑脚本只想调一个-webhook "不想跑脚本，只想调��一个 Webhook的直接链接")

不需要在机器上执行命令、只想通知一个外部系统去做事时，用工作流里的 **Webhook 回调** 处理器：把整条事件 POST 给你的地址，响应体不看，发出去就算完。 适合开工单、触发 CI/CD、调自动化平台。

配法见[事件 Pipeline](https://n9e.github.io/zh/docs/events/pipelines.md)；如果还想拿对方的返回值改事件， 那要用的是事件更新处理器，两者的区别见[改写标签与补充上下文](https://n9e.github.io/zh/docs/events/relabel-enrich.md)。

## 下一步[​](#下一步 "下一步的直接链接")

* 事件到人之前还会经历什么：[降噪与路由模型](https://n9e.github.io/zh/docs/concepts/noise-routing.md)
* 让脚本只在特定事件上跑：[条件路由](https://n9e.github.io/zh/docs/events/routing.md)
* 端口开在哪：[端口清单](https://n9e.github.io/zh/docs/reference/ports.md)
