roxy-wi/IncidentRelay
GitHub: roxy-wi/IncidentRelay
IncidentRelay 是一个面向 SRE 与 DevOps 团队的开源自托管值班调度与事件响应平台,提供告警路由、轮换排班、多渠道通知和升级提醒等核心能力。
Stars: 77 | Forks: 4

# IncidentRelay
**适合希望完全掌控其事件工作流的团队的、自托管的值班调度、告警路由、告警分发、提醒和升级功能。**
IncidentRelay 帮助 SRE、DevOps、平台、基础设施和运维团队通过正确的渠道将告警路由给正确的人员,而无需依赖托管的事件管理平台。
它提供了值班系统的核心构建块:
- 访问组和基于 RBAC 的组角色;
- 团队和值班轮换;
- 带有独立 token 的告警接入路由;
- Alertmanager、Zabbix、Sentry、LibreNMS 和通用 webhook 集成;
- Mattermost、Slack、Telegram、Discord、Microsoft Teams、电子邮件、webhook 和语音呼叫通知;
- 级别控制的浏览器/PWA 推送通知;
- 用于浏览器推送、电子邮件和语音呼叫跟进的个人通知规则;
- 确认和解决工作流;
- 提醒和升级给下一位值班用户;
- 轮换覆盖;
- 告警静音;
- 用于计划任务工作和告警行为控制的维护窗口;
- 值班安排的日历视图;
- 个人 API token;
- Swagger/OpenAPI 文档。
IncidentRelay 专为需要可预测行为、明确所有权、轻松集成以及完全控制告警路由的**自托管环境**而设计。

## 为什么选择 IncidentRelay?
许多团队需要值班路由,但并不总是需要庞大的 SaaS 事件平台。
IncidentRelay 专注于实用的工作流程:
```
Monitoring system -> Route -> Team -> Rotation -> Notification channels -> ACK / Resolve
```
每个路由拥有独立的接入 token,因此外部系统可以将告警发送到精确的告警路径:
```
ROUTE_INTAKE_TOKEN -> Route -> Team -> Rotation -> Channels
```
通道仅描述通知的发送目的地。路由决定哪个团队接收告警以及使用哪些通道。
个人浏览器推送和个人通知规则独立于路由通道。它们针对被分配用户自己的浏览器设备和联系方式。
这使得告警分发更易于推理、更易于审计,并且对于自托管部署更加安全。

## 亮点
### 设计即为自托管
在你自己的环境中运行 IncidentRelay,使用你自己的数据库、你自己的网络规则和你自己的运维策略。
### 基于路由的告警接入
告警接入 token 属于路由,而不是通道。这样可以清楚地知道允许哪个传入集成向哪个团队和轮换提交告警。
### 多团队和多组支持
将组作为访问边界。团队、轮换、路由、通道、告警和静音都是通过组和成员身份来限定范围的。
### 升级和提醒
未经确认的告警可以触发重复提醒,然后根据团队配置升级给下一位值班用户。
### Mattermost 实时操作
Mattermost Bot API 模式支持交互式的 `Acknowledge` 和 `Resolve` 按钮、消息更新以及基于严重程度的附件颜色。
### Telegram 操作和 worker
Telegram 通知可以包含操作按钮和告警链接。Telegram 的回调/轮询处理由可选的 `incidentrelay-telegram-worker` 服务处理。
### 可插拔的语音呼叫
可以通过自定义语音提供商扩展 IncidentRelay,以用于自托管安装。提供商可以实现文本转语音呼叫、呼叫状态回调、DTMF 按钮回调、通过手机键盘进行 ACK / Resolve 操作,以及可选的呼叫状态轮询。
### 浏览器/PWA 推送和个人规则
用户可以从其个人资料中启用浏览器推送,并在活动的浏览器或已安装的 PWA 设备上接收告警通知。浏览器推送可以包含 `Acknowledge` 和 `Resolve` 操作。
个人通知规则允许用户定义通过浏览器推送、电子邮件或语音呼叫进行后续分发,而无需将浏览器推送转变为路由通道。
### API 优先
IncidentRelay 包含 Swagger/OpenAPI 文档以及具有针对告警、资源和配置文件访问范围的个人 API token。

## 支持的集成
### 传入告警源
| 来源 | Endpoint |
|-----------------|-------------------------------------------|
| Alertmanager | `POST /api/integrations/alertmanager` |
| Zabbix | `POST /api/integrations/zabbix` |
| Sentry | `POST /api/integrations/sentry/` |
| LibreNMS | `POST /api/integrations/librenms` |
| 通用 webhook | `POST /api/integrations/webhook` |
### 通知通道
| 通道 | 备注 |
|---|---|
| Mattermost | Incoming webhook 模式或具有按钮和更新的 Bot API 模式 |
| Slack | Webhook 通知 |
| Telegram | Bot 通知和可选的操作按钮 |
| Discord | Webhook 通知 |
| Microsoft Teams | Webhook 通知 |
| 电子邮件 | 电子邮件收件人 |
| Webhook | 通用出站 webhook |
| 语音呼叫 | 用于自托管语音集成的可插拔 provider API |
浏览器/PWA 推送属于个人资料级别,而不是通知通道。用户在个人资料中启用它,IncidentRelay 会向被分配用户的活动浏览器/PWA 设备发送推送通知。
## 安装
选择与你的环境相匹配的安装方法。
### Docker Compose
推荐用于快速启动、测试和简单的自托管部署。
```
cd docker
docker compose up -d --build
```
使用 PostgreSQL:
```
cd docker
docker compose \
-f docker-compose.yml \
-f docker-compose.postgres.yml \
up -d
```
了解更多:[Docker 安装](docs/getting-started/docker.md)
### Kubernetes (Helm)
[`helm/incidentrelay`](helm/incidentrelay) 中提供了一个 Helm chart。它部署了 Web UI 以及调度器和 Telegram worker,将 values 中的应用程序配置渲染到 Secret 中,并连接了 `/healthz` 和 `/readyz` 探针。
```
helm install incidentrelay ./helm/incidentrelay \
--set image.repository=registry.example.com/incidentrelay \
--set image.tag=1.0.15-beta \
--set config.main.secret_key="$(openssl rand -hex 32)"
```
默认值在共享的 PersistentVolumeClaim 上使用 SQLite。这严格来说是单节点设置:在网络支持的 `ReadWriteMany` 存储(NFS 等)上使用 SQLite 是导致数据库损坏的已知原因。数据库迁移在 web pod 启动时运行,因此请将 `web.replicaCount` 保持为 `1`(或者禁用 `web.runMigrations` 并进行外部迁移)。对于任何多节点或多副本的情况,请将 `config.database` 指向 PostgreSQL:
```
helm install incidentrelay ./helm/incidentrelay \
--set config.main.secret_key="$(openssl rand -hex 32)" \
--set config.database.type=postgresql \
--set config.database.host=postgres.example.svc \
--set config.database.port=5432 \
--set config.database.name=incidentrelay \
--set config.database.user=incidentrelay \
--set config.database.password=change-me \
--set persistence.enabled=false
```
`incidentrelay.conf` 中的所有设置都可以在 [values.yaml](helm/incidentrelay/values.yaml) 中的 `config.*` 下找到;你也可以通过 `existingConfigSecret` 引入预渲染的配置。
### 从 RPM 仓库安装到 RedHat 系发行版
推荐用于 RHEL、Rocky Linux、AlmaLinux 和 CentOS Stream。
```
sudo dnf install -y curl
sudo curl -fsSL \
https://repo.incidentrelay.io/incidentrelay.repo \
-o /etc/yum.repos.d/incidentrelay.repo
sudo dnf makecache
sudo dnf install -y incidentrelay
```
对于较旧的基于 yum 的系统:
```
sudo yum install -y curl
sudo curl -fsSL \
https://repo.incidentrelay.io/incidentrelay.repo \
-o /etc/yum.repos.d/incidentrelay.repo
sudo yum makecache
sudo yum install -y incidentrelay
```
了解更多:[RedHat RPM 安装](docs/getting-started/rpm-installation.md)
### 手动 systemd 安装
当你想直接从源代码运行 IncidentRelay 或手动管理 Python 环境时,推荐使用此方法。
了解更多:[Systemd 安装](docs/getting-started/systemd.md)
## 运行时布局
RPM 和 systemd 安装使用的常见路径:
```
/var/www/incidentrelay # application code
/var/www/incidentrelay/venv # Python environment or venv-compatible wrapper
/etc/incidentrelay/incidentrelay.conf # main configuration file
/var/lib/incidentrelay # runtime data
/var/log/incidentrelay # logs
/usr/local/lib/incidentrelay/voice_providers # custom voice providers
```
Systemd 服务:
```
incidentrelay.service # HTTP API, UI, webhooks
incidentrelay-scheduler.service # reminders, escalations, periodic jobs
incidentrelay-telegram-worker.service # optional Telegram callbacks/polling
```
系统用户:
```
incidentrelay
```
## 配置
IncidentRelay 从以下位置读取配置文件路径:
```
INCIDENTRELAY_CONFIG_FILE
```
示例:
```
export INCIDENTRELAY_CONFIG_FILE=/etc/incidentrelay/incidentrelay.conf
```
对于生产环境,请设置用于生成链接和回调 URL 的公共 URL:
```
[server]
public_base_url = https://incidentrelay.example.com
```
SQLite 适用于小型单节点安装:
```
[database]
type = sqlite
path = /var/lib/incidentrelay/incidentrelay.db
```
对于大型或长期运行的生产安装,推荐使用 PostgreSQL:
```
[database]
type = postgresql
host = 127.0.0.1
port = 5432
name = incidentrelay
user = incidentrelay
password = change-me
```
了解更多:[配置](docs/getting-started/configuration.md)
## 首次设置
安装后,初始化数据库并创建第一位管理员。
### 运行数据库迁移
对于 RPM/systemd 安装:
```
sudo -u incidentrelay \
INCIDENTRELAY_CONFIG_FILE=/etc/incidentrelay/incidentrelay.conf \
/var/www/incidentrelay/venv/bin/python \
/var/www/incidentrelay/manage.py migrate
```
对于 Docker 安装:
```
docker compose exec incidentrelay \
python manage.py migrate
```
### 创建第一个管理员用户
对于 RPM/systemd 安装:
```
sudo -u incidentrelay \
INCIDENTRELAY_CONFIG_FILE=/etc/incidentrelay/incidentrelay.conf \
/var/www/incidentrelay/venv/bin/python \
/var/www/incidentrelay/manage.py create-admin \
--username admin \
--password 'change-me-123' \
--email admin@example.com
```
对于 Docker 安装:
```
docker compose exec incidentrelay \
python manage.py create-admin \
--username admin \
--password 'change-me-123' \
--email admin@example.com
```
在生产环境中使用这些命令之前,请更改密码和电子邮件。
## 基础 UI 设置流程
首次登录后:
```
1. Create a group
2. Create users
3. Add users to the group
4. Create a team
5. Add users to the team
6. Create a rotation
7. Add rotation members
8. Create notification channels
9. Create a route
10. Copy the route intake token
11. Configure browser push VAPID keys if browser/PWA notifications are required
12. Ask users to enable browser push or profile notification rules if required
13. Configure Alertmanager, Zabbix, or webhook sender
14. Send a test alert
15. Acknowledge or resolve the alert
```
详细指南:[首次登录和初始设置](docs/getting-started/first-login.md)
## Alertmanager 请求示例
```
curl -X POST http://127.0.0.1:8080/api/integrations/alertmanager \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer ALERTMANAGER_ROUTE_TOKEN' \
-d '{
"status": "firing",
"alerts": [
{
"status": "firing",
"labels": {
"alertname": "DiskFull",
"severity": "critical",
"team": "infra",
"instance": "host1"
},
"annotations": {
"summary": "Disk is full",
"description": "/var is 95% full"
},
"fingerprint": "disk-full-host1-var"
}
]
}'
```
更多示例:
- [Alertmanager 集成](docs/integrations/alertmanager.md)
- [Zabbix 集成](docs/integrations/zabbix.md)
- [通用 webhook 集成](docs/integrations/generic-webhook.md)
## Mattermost 按钮和消息更新
Mattermost 有两种模式。
**Incoming webhook 模式**仅发送纯文本消息。
当你需要以下功能时,推荐使用 **Bot API 模式**:
- `Acknowledge` 按钮;
- `Resolve` 按钮;
- ACK / Resolve 后的消息更新;
- 基于严重程度的颜色。
更多详细信息:[Mattermost 集成](docs/integrations/mattermost.md)
## 自定义语音提供商
IncidentRelay 支持为自托管安装提供自定义语音提供商。
提供商是一个 Python 模块,可以放置在以下位置:
```
/usr/local/lib/incidentrelay/voice_providers
```
自定义提供商可以实现:
- 文本转语音呼叫创建;
- 提供商呼叫 ID 跟踪;
- 呼叫状态回调;
- DTMF 按钮回调;
- 通过手机键盘进行 ACK / Resolve 操作;
- 可选的呼叫状态轮询。
从这里开始:
- [自定义语音提供商](docs/voice-providers/index.md)
- [Provider API](docs/voice-providers/provider-api.md)
- [配置](docs/voice-providers/configuration.md)
- [回调和 DTMF](docs/voice-providers/callbacks.md)
- [安全性](docs/voice-providers/security.md)
- [故障排除](docs/voice-providers/troubleshooting.md)
- [示例提供商](docs/examples/voice_providers/)
## API 文档
Swagger UI 可在以下位置访问:
```
/docs
```
OpenAPI JSON 可在以下位置访问:
```
/api/openapi.json
```
## 文档
| 主题 | 链接 |
|---|---|
| 入门指南 | [docs/getting-started/](docs/getting-started/index.md) |
| Docker 安装 | [docs/getting-started/docker.md](docs/getting-started/docker.md) |
| RedHat RPM 安装 | [docs/getting-started/rpm-installation.md](docs/getting-started/rpm-installation.md) |
| Systemd 安装 | [docs/getting-started/systemd.md](docs/getting-started/systemd.md) |
| 配置 | [docs/getting-started/configuration.md](docs/getting-started/configuration.md) |
| 首次登录 | [docs/getting-started/first-login.md](docs/getting-started/first-login.md) |
| 组和 RBAC | [docs/concepts/groups-and-rbac.md](docs/concepts/groups-and-rbac.md) |
| 团队、轮换、路由 | [docs/concepts/teams-rotations-routes.md](docs/concepts/teams-rotations-routes.md) |
| 路由接入 token | [docs/concepts/route-intake-tokens.md](docs/concepts/route-intake-tokens.md) |
| 维护窗口 | [docs/concepts/maintenance-windows.md](docs/concepts/maintenance-windows.md) |
| 服务 | [docs/concepts/services.md](docs/concepts/services.md) |
| 通道 | [docs/concepts/channels.md](docs/concepts/channels.md) |
| Alertmanager | [docs/integrations/alertmanager.md](docs/integrations/alertmanager.md) |
| Zabbix | [docs/integrations/zabbix.md](docs/integrations/zabbix.md) |
| 通用 webhook | [docs/integrations/generic-webhook.md](docs/integrations/generic-webhook.md) |
| Mattermost | [docs/integrations/mattermost.md](docs/integrations/mattermost.md) |
| 告警 | [docs/usage/alerts.md](docs/usage/alerts.md) |
| 浏览器推送 | [docs/usage/browser-push.md](docs/usage/browser-push.md) |
| 日历 | [docs/usage/calendar.md](docs/usage/calendar.md) |
| 静音 | [docs/usage/silences.md](docs/usage/silences.md) |
| 轮换覆盖 | [docs/usage/rotation-overrides.md](docs/usage/rotation-overrides.md) |
| 个人资料和 API token | [docs/usage/profile-and-tokens.md](docs/usage/profile-and-tokens.md) |
| 日志 | [docs/administration/logging.md](docs/administration/logging.md) |
| 故障排除 | [docs/administration/troubleshooting.md](docs/administration/troubleshooting.md) |
| 演示数据 | [docs/administration/demo-data.md](docs/administration/demo-data.md) |
| Schema 检查 | [docs/administration/schema-check.md](docs/administration/schema-check.md) |
| 自定义语音提供商 | [docs/voice-providers/index.md](docs/voice-providers/index.md) |
## 演示数据
创建演示数据:
```
python manage.py demo-data
```
该命令会创建演示组、用户、团队、轮换、通道、路由以及路由接入 token。
静态演示数据检查:
```
python app/check_demo_data.py
```
更多详细信息:[演示数据](docs/administration/demo-data.md)
## Schema 检查
运行迁移后,验证配置的数据库中是否存在所有 Peewee 模型表和列:
```
python app/check_schema.py
```
预期输出:
```
Schema check OK: all model tables and columns exist.
```
更多详细信息:[Schema 检查](docs/administration/schema-check.md)
## 故障排除
如果告警不可见或未分发:
```
1. Check that the correct route intake token was used.
2. Check that the endpoint matches the route source.
3. Check that route matchers match alert labels.
4. Check that the group is active.
5. Check that the team is active.
6. Check that the UI active group is correct.
7. Select "All my groups" and reload the Alerts page.
8. Check routing_error in the integration response.
9. Check JSON logs by error_id if the server returned one.
```
更多详细信息:[故障排除](docs/administration/troubleshooting.md)
## 许可证
查看 [LICENSE](LICENSE)。
标签:值班调度, 告警路由, 子域名突变, 测试用例, 自托管, 请求拦截, 运维监控, 逆向工具