饮墨

子安饮墨馀三斗,留与卿儿作赋来

Grafana OnCall:开源值班告警管理,替代 PagerDuty 的实战方案

痛点

运维团队到了一定规模,告警值班管理就成了绕不开的问题:谁该接这条告警?升级策略怎么配?值班表怎么轮转?PagerDuty、OpsGenie 这类 SaaS 工具好用,但每人每月 $21-$49 的费用,10 人团队一年下来就是 $2500-$6000。对于已经重度使用 Grafana 栈的团队,Grafana OnCall 是一个值得认真考虑的开源替代方案。

Grafana OnCall(原 Amixr)2022 年开源后持续迭代,2024 年已合并进 Grafana OSS 核心,作为内置插件随 Grafana 一起部署。它覆盖了值班轮转、告警路由、升级策略、多渠道通知等核心需求,且与 Grafana Alerting 原生集成。

方案概览

Grafana OnCall 的核心架构:

Alertmanager / Grafana Alerting
                  Grafana OnCall (Integration)
                ├── Route  Escalation Chain
                 ├── Step 1: Notify on-call engineer (Slack/Telegram/Phone)
                 ├── Step 2: Wait 5min, notify backup
                 └── Step 3: Wait 10min, notify manager
                └── Schedule (轮转值班表)
              ├── Layer 1: Primary on-call (weekly rotation)
              └── Layer 2: Secondary backup

核心组件:

组件 作用
Integration 接收告警的入口(Alertmanager、Webhook、Email 等)
Route 根据标签/内容将告警路由到不同升级链
Escalation Chain 升级策略:通知谁、等多久、下一步找谁
Schedule 值班轮转表,支持多层覆盖
ChatOps Slack/Telegram/MS Teams 集成,直接在聊天中 Ack/Resolve

实操步骤

Step 1: 部署 Grafana OnCall(Docker Compose)

Grafana 11+ 已内置 OnCall 插件,但独立部署的 OnCall Engine 功能更完整(支持电话/短信通知)。推荐用 Docker Compose:

# docker-compose.yml
version: "3.8"

x-environment: &oncall-env
  DATABASE_TYPE: sqlite3
  BROKER_TYPE: redis
  BASE_URL: http://oncall.example.com:8080
  SECRET_KEY: "change-me-to-random-string-32chars"
  REDIS_URI: redis://redis:6379/0
  DJANGO_SETTINGS_MODULE: settings.hobby
  CELERY_WORKER_QUEUE: "default,critical,long,slack,telegram,webhook,retry,celery,grafana"
  GRAFANA_API_URL: http://grafana:3000

services:
  engine:
    image: grafana/oncall:latest
    restart: always
    ports:
      - "8080:8080"
    command: sh -c "uwsgi --ini uwsgi.ini"
    environment:
      <<: *oncall-env
    depends_on:
      redis:
        condition: service_healthy
      oncall-migrate:
        condition: service_completed_successfully

  celery:
    image: grafana/oncall:latest
    restart: always
    command: sh -c "python manage.py start_celery"
    environment:
      <<: *oncall-env
    depends_on:
      redis:
        condition: service_healthy
      oncall-migrate:
        condition: service_completed_successfully

  oncall-migrate:
    image: grafana/oncall:latest
    command: sh -c "python manage.py migrate"
    environment:
      <<: *oncall-env
    depends_on:
      redis:
        condition: service_healthy

  redis:
    image: redis:7-alpine
    restart: always
    healthcheck:
      test: ["CMD", "redis-cli", "ping"]
      interval: 5s
      timeout: 3s
      retries: 5

  grafana:
    image: grafana/grafana:latest
    restart: always
    ports:
      - "3000:3000"
    environment:
      GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS: grafana-oncall-app
      GF_INSTALL_PLUGINS: grafana-oncall-app
    volumes:
      - grafana-data:/var/lib/grafana

volumes:
  grafana-data:

启动:

docker compose up -d
# 验证服务状态
docker compose ps
# 期望看到 engine/celery/redis/grafana 全部 running

Step 2: 在 Grafana 中启用 OnCall 插件并连接

# 1. 打开 Grafana: http://localhost:3000 (admin/admin)
# 2. 进入 Administration → Plugins → 搜索 "OnCall" → Enable
# 3. 配置 OnCall backend URL: http://engine:8080

连接后,在 Grafana 左侧菜单会出现 OnCall 入口。

Step 3: 配置 Integration + Escalation Chain

创建 Integration(接收 Alertmanager 告警):

在 OnCall → Integrations → New Integration → 选择 "Alertmanager",获取 Webhook URL:

http://oncall.example.com:8080/integrations/v1/alertmanager/<unique-id>/

配置 Alertmanager 将告警发送到 OnCall:

# alertmanager.yml
receivers:
  - name: 'grafana-oncall'
    webhook_configs:
      - url: 'http://oncall.example.com:8080/integrations/v1/alertmanager/<unique-id>/'
        send_resolved: true

route:
  receiver: 'grafana-oncall'
  group_by: ['alertname', 'namespace']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h

创建 Escalation Chain:

OnCall  Escalation Chains  New Chain: "Production Critical"
  Step 1: Notify users from on-call schedule "Primary"
  Step 2: Wait 5 minutes
  Step 3: Notify users from on-call schedule "Secondary"
  Step 4: Wait 10 minutes
  Step 5: Notify user group "SRE Managers"

Step 4: 配置值班轮转表

OnCall → Schedules → Create Schedule
  Name: "Primary On-Call"
  Type: Web-based (推荐,支持拖拽)

  Layer 1 - Primary:
    Rotation: Weekly
    Users: engineer-A → engineer-B → engineer-C
    Start: Monday 09:00 UTC

  Override Layer:
    用于临时换班、节假日覆盖

值班表支持导出 iCal 格式,工程师可订阅到自己的日历 App。

避坑指南

1. Celery Worker 队列必须完整

最常见的部署问题是 Celery 队列配置不全,导致通知发不出去:

# 错误:只配了 default 队列
CELERY_WORKER_QUEUE: "default"

# 正确:必须包含所有队列
CELERY_WORKER_QUEUE: "default,critical,long,slack,telegram,webhook,retry,celery,grafana"

排查方式:

docker compose logs celery | grep -i "error\|exception"
# 检查是否有 "Received unregistered task" 类报错

2. 时区问题导致值班错乱

OnCall Schedule 的时区设置影响轮转时间点。团队跨时区时,建议:

  • Schedule 统一用 UTC
  • 每个用户在 OnCall 个人设置中配好自己的时区
  • 通知消息中会自动转为用户本地时间
# 验证服务器时区
timedatectl
# 确保容器内 TZ 环境变量正确
docker exec oncall-engine date

3. 告警风暴导致通知轰炸

默认配置下,每条告警都会触发独立通知。必须配置 Grouping:

Integration  Advanced Settings:
  Grouping:  alertname + namespace 分组
  Auto-resolve: 启用(收到 resolved 状态自动关闭)

  # 或者用模板自定义分组键
  Grouping Template:
    {{ payload.labels.alertname }}-{{ payload.labels.cluster }}

同时在 Alertmanager 层做好 group_waitgroup_interval,避免上游就发出大量重复告警。

与 PagerDuty 功能对比

功能 Grafana OnCall (OSS) PagerDuty
值班轮转
升级策略
Slack/Telegram 集成
电话/短信通知 ⚠️ 需自配 Twilio ✅ 内置
移动 App ✅ Grafana App ✅ 专用 App
Grafana 原生集成 ✅ 零配置 ❌ 需插件
成本 (10人) $0 (自托管) ~$250/月
维护成本 中等(需自运维)
SLA 保障 自行保障 99.9%

总结

Grafana OnCall 适合以下场景:

  1. 已有 Grafana 栈 — 与 Grafana Alerting 无缝集成,告警从产生到通知一条链路
  2. 团队 5-30 人 — 规模足够需要正式值班管理,但不想付 SaaS 高额费用
  3. 对数据主权有要求 — 告警数据不出内网

不适合的场景:强依赖电话呼叫(Twilio 配置和可靠性需要额外投入)、需要企业级 SLA 保障、团队无人维护基础设施。

落地建议:先用 Docker Compose 在测试环境跑起来,配通 Slack/Telegram 通知 + 一条 Escalation Chain,验证告警从 Prometheus → Alertmanager → OnCall → 通知到人的全链路后,再考虑生产部署(生产环境建议将 SQLite 换为 PostgreSQL,Redis 用独立集群)。

您还没有登录,请登录后发表评论。