Задача клиента: алерты уходят в пустоту
В январе 2026 года к нам в АйТи Фреш обратилась компания «КлаудБейс» из Казани — провайдер облачной платформы, обслуживающий 50 корпоративных клиентов. Платформа работала на базе Proxmox с Ceph-хранилищем, а за мониторинг отвечали Zabbix и Prometheus + Alertmanager. Проблема была не в мониторинге как таковом — алерты генерировались исправно. Проблема была в людях, которые должны были на них реагировать.
Дежурный инженер получал уведомления в общий Telegram-чат команды из 6 человек. Ночью алерты тонули среди сотен сообщений. Три раза за последний квартал критические инциденты оставались без реакции более 40 минут — при SLA, гарантирующем реакцию за 15 минут. Один из инцидентов — падение Ceph OSD на 2 часа ночью — привёл к деградации хранилища для 12 клиентов.
«У нас нет проблем с мониторингом — у нас проблема с тем, что конкретный человек должен взять на себя инцидент прямо сейчас. Алерт в общем чате — это алерт ничей» — технический директор «КлаудБейс».
Аудит текущей системы оповещений
Мы подключились к инфраструктуре и задокументировали текущее состояние:
- Alertmanager — настроен, отправлял все алерты в один Telegram-чат через webhook
- Zabbix 6.4 — генерировал триггеры на хост-уровне (CPU, RAM, диск), но actions были настроены только на email
- Дежурства — велись в Google Sheets, инженеры забывали проверять расписание
- Эскалации — отсутствовали: если дежурный не реагировал, инцидент просто висел
- Постмортемы — не велись, причины повторяющихся инцидентов не анализировались
Статистика за последние 3 месяца:
# Выгрузка из Alertmanager: среднее время реакции
curl -s http://alertmanager:9093/api/v2/alerts | \
jq '[.[] | select(.status.state=="active") |
.startsAt] | length'
# Результат: 847 алертов за 90 дней
# Из них 23% — ночные (00:00-07:00)
# Среднее время реакции ночью: 47 минут
# SLA нарушен: 14 раз из 50 критических инцидентов
Почему Grafana OnCall
Мы рассмотрели три решения для управления инцидентами:
| Решение | Плюсы | Минусы |
|---|
| PagerDuty | Лидер рынка, мощный | От $21/user/мес, данные в US, зависимость от SaaS |
| Opsgenie (Atlassian) | Интеграция с Jira | От $9/user/мес, ограничения free-плана |
| Grafana OnCall (OSS) | Бесплатный, self-hosted, нативная интеграция с Grafana | Требует инфраструктуры для деплоя |
Grafana OnCall победил: у «КлаудБейс» уже работал Grafana-стек для дашбордов, команда знала интерфейс, а self-hosted решение гарантировало контроль над данными и отсутствие абонентской платы. При 6 инженерах PagerDuty обошёлся бы в $1 500+/год — за эти деньги мы покрыли всё внедрение.
Установка Grafana OnCall
Grafana OnCall разворачивается как набор микросервисов. Мы выбрали Docker Compose для развёртывания — инфраструктура «КлаудБейс» уже использовала Docker на серверах мониторинга. Целевой сервер: Ubuntu 22.04, 4 vCPU, 8 ГБ RAM.
Docker Compose для Grafana OnCall
Создаём файл docker-compose.yml с полным стеком:
# /opt/grafana-oncall/docker-compose.yml
version: '3.8'
services:
# Основной движок OnCall
oncall-engine:
image: grafana/oncall:v1.9.11
restart: always
environment:
- DATABASE_TYPE=postgresql
- DATABASE_HOST=oncall-db
- DATABASE_PORT=5432
- DATABASE_NAME=oncall
- DATABASE_USER=oncall
- DATABASE_PASSWORD=${DB_PASSWORD}
- RABBITMQ_USERNAME=oncall
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
- RABBITMQ_HOST=oncall-rabbitmq
- RABBITMQ_PORT=5672
- REDIS_URI=redis://oncall-redis:6379/0
- SECRET_KEY=${SECRET_KEY}
- BASE_URL=https://oncall.cloudbase.local
- GRAFANA_API_URL=http://grafana:3000
depends_on:
- oncall-db
- oncall-redis
- oncall-rabbitmq
ports:
- "8080:8080"
# Celery worker для фоновых задач
oncall-celery:
image: grafana/oncall:v1.9.11
restart: always
command: celery_worker
environment:
- DATABASE_TYPE=postgresql
- DATABASE_HOST=oncall-db
- DATABASE_PORT=5432
- DATABASE_NAME=oncall
- DATABASE_USER=oncall
- DATABASE_PASSWORD=${DB_PASSWORD}
- RABBITMQ_USERNAME=oncall
- RABBITMQ_PASSWORD=${RABBITMQ_PASSWORD}
- RABBITMQ_HOST=oncall-rabbitmq
- REDIS_URI=redis://oncall-redis:6379/0
- SECRET_KEY=${SECRET_KEY}
depends_on:
- oncall-db
- oncall-redis
- oncall-rabbitmq
# PostgreSQL для хранения данных OnCall
oncall-db:
image: postgres:15-alpine
restart: always
environment:
- POSTGRES_DB=oncall
- POSTGRES_USER=oncall
- POSTGRES_PASSWORD=${DB_PASSWORD}
volumes:
- oncall-db-data:/var/lib/postgresql/data
# Redis для кеширования и очередей
oncall-redis:
image: redis:7-alpine
restart: always
volumes:
- oncall-redis-data:/data
# RabbitMQ для Celery
oncall-rabbitmq:
image: rabbitmq:3.12-alpine
restart: always
environment:
- RABBITMQ_DEFAULT_USER=oncall
- RABBITMQ_DEFAULT_PASS=${RABBITMQ_PASSWORD}
volumes:
- oncall-rabbitmq-data:/var/lib/rabbitmq
# Grafana с плагином OnCall
grafana:
image: grafana/grafana:10.3.1
restart: always
environment:
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_PASSWORD}
- GF_INSTALL_PLUGINS=grafana-oncall-app
ports:
- "3000:3000"
volumes:
- grafana-data:/var/lib/grafana
volumes:
oncall-db-data:
oncall-redis-data:
oncall-rabbitmq-data:
grafana-data:
Создаём файл переменных и запускаем:
# Генерируем секреты
cat > /opt/grafana-oncall/.env <<EOF
DB_PASSWORD=$(openssl rand -base64 24)
RABBITMQ_PASSWORD=$(openssl rand -base64 24)
SECRET_KEY=$(openssl rand -base64 32)
GRAFANA_PASSWORD=CloudBase!Gr4f4n4
EOF
# Запускаем стек
cd /opt/grafana-oncall
docker compose up -d
# Проверяем, что все контейнеры запустились
docker compose ps
# NAME STATUS
# oncall-engine Up (healthy)
# oncall-celery Up
# oncall-db Up (healthy)
# oncall-redis Up (healthy)
# oncall-rabbitmq Up (healthy)
# grafana Up (healthy)
Подключение плагина OnCall в Grafana
После запуска активируем плагин в Grafana и связываем его с backend-сервером OnCall:
# Включаем плагин через API
curl -X POST http://admin:${GRAFANA_PASSWORD}@localhost:3000/api/plugins/grafana-oncall-app/settings \
-H 'Content-Type: application/json' \
-d '{
"enabled": true,
"jsonData": {
"onCallApiUrl": "http://oncall-engine:8080"
}
}'
# Генерируем API-ключ для OnCall
curl -X POST http://admin:${GRAFANA_PASSWORD}@localhost:3000/api/auth/keys \
-H 'Content-Type: application/json' \
-d '{"name": "oncall-api-key", "role": "Admin"}'
# {"id":1,"name":"oncall-api-key","key":"eyJrIjoi..."}
Теперь в интерфейсе Grafana в боковом меню появился раздел OnCall с вкладками: Alert Groups, Integrations, Escalation Chains, Schedules, Users.
Интеграция с Alertmanager и Zabbix
Основная ценность Grafana OnCall — это единая точка входа для алертов из разных систем мониторинга. У «КлаудБейс» алерты приходили из двух источников, и нам нужно было свести их в единый поток.
Настройка интеграции с Alertmanager
В Grafana OnCall создаём интеграцию типа Alertmanager. Система генерирует уникальный webhook URL, который мы указываем в конфиге Alertmanager:
# /etc/alertmanager/alertmanager.yml
global:
resolve_timeout: 5m
route:
receiver: 'grafana-oncall'
group_by: ['alertname', 'cluster', 'service']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
# Критические алерты — немедленно
- match:
severity: critical
receiver: 'grafana-oncall'
group_wait: 10s
repeat_interval: 1h
# Warning — группируем больше
- match:
severity: warning
receiver: 'grafana-oncall'
group_wait: 1m
repeat_interval: 6h
receivers:
- name: 'grafana-oncall'
webhook_configs:
- url: 'https://oncall.cloudbase.local/integrations/v1/alertmanager/abc123def456/'
send_resolved: true
http_config:
tls_config:
insecure_skip_verify: false
Перезагружаем Alertmanager:
# Проверяем конфиг
amtool check-config /etc/alertmanager/alertmanager.yml
# Checking '/etc/alertmanager/alertmanager.yml' SUCCESS
# Перезагружаем
systemctl reload prometheus-alertmanager
# Тестируем отправку алерта
curl -X POST https://oncall.cloudbase.local/integrations/v1/alertmanager/abc123def456/ \
-H 'Content-Type: application/json' \
-d '[{
"status": "firing",
"labels": {
"alertname": "TestAlert",
"severity": "critical",
"instance": "node-01:9090"
},
"annotations": {
"summary": "Test alert from CLI"
}
}]'
Настройка интеграции с Zabbix
Для Zabbix создаём отдельную интеграцию типа Webhook. Grafana OnCall генерирует URL, а в Zabbix настраиваем Media Type:
# Zabbix: Administration → Media Types → Create
# Name: Grafana OnCall
# Type: Webhook
# Parameters:
# URL: https://oncall.cloudbase.local/integrations/v1/webhook/xyz789abc012/
# HTTPProxy: (пусто)
# To: {ALERT.SENDTO}
# Subject: {ALERT.SUBJECT}
# Message: {ALERT.MESSAGE}
# Script в Media Type:
var params = JSON.parse(value);
var req = new HttpRequest();
req.addHeader('Content-Type: application/json');
var payload = {
"alert_uid": "{EVENT.ID}",
"title": "{HOST.NAME}: {TRIGGER.NAME}",
"message": "{TRIGGER.DESCRIPTION}",
"severity": "{TRIGGER.SEVERITY}",
"status": "{TRIGGER.STATUS}",
"host": "{HOST.NAME}",
"host_ip": "{HOST.IP}",
"trigger_id": "{TRIGGER.ID}",
"event_id": "{EVENT.ID}",
"event_time": "{EVENT.TIME}",
"event_date": "{EVENT.DATE}"
};
var resp = req.post(params.URL, JSON.stringify(payload));
if (req.getStatus() !== 200) {
throw 'OnCall returned HTTP ' + req.getStatus();
}
return 'OK';
Далее создаём Action в Zabbix:
# Configuration → Actions → Trigger actions → Create
# Name: Send to Grafana OnCall
# Conditions:
# Trigger severity >= Warning
# Operations:
# Send to User groups: All engineers
# Send only to: Grafana OnCall (Media Type)
Теперь алерты из обоих систем — Alertmanager (для Prometheus-метрик) и Zabbix (для хостовых проверок) — приходят в единый интерфейс Grafana OnCall.
Политики эскалации и расписание дежурств
Ключевой функционал Grafana OnCall — это Escalation Chains (цепочки эскалации) и Schedules (расписания дежурств). Именно здесь решается проблема «алерт ничей» — каждый алерт привязывается к конкретному дежурному, а если он не реагирует, алерт автоматически уходит дальше по цепочке.
Создание расписания дежурств с ротацией
У «КлаудБейс» 6 инженеров. Мы создали два расписания: дневное и ночное/выходное:
# Через OnCall API создаём расписание
# Дневное дежурство: будни 09:00–21:00, ротация каждый день
curl -X POST https://oncall.cloudbase.local/api/v1/schedules/ \
-H 'Authorization: Bearer ${ONCALL_API_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Дневная смена",
"type": "web",
"team_id": null,
"time_zone": "Europe/Moscow",
"shifts": [
{
"name": "Day shift rotation",
"type": "rolling_users",
"start": "2026-01-13T09:00:00",
"duration": 43200,
"frequency": "daily",
"interval": 1,
"rolling_users": [
["user_id_1"],
["user_id_2"],
["user_id_3"]
],
"by_day": ["MO", "TU", "WE", "TH", "FR"]
}
]
}'
# Ночное дежурство: будни 21:00–09:00 + выходные целиком
# Ротация каждые 3 дня среди оставшихся 3 инженеров
curl -X POST https://oncall.cloudbase.local/api/v1/schedules/ \
-H 'Authorization: Bearer ${ONCALL_API_KEY}' \
-H 'Content-Type: application/json' \
-d '{
"name": "Ночная смена и выходные",
"type": "web",
"time_zone": "Europe/Moscow",
"shifts": [
{
"name": "Night shift rotation",
"type": "rolling_users",
"start": "2026-01-13T21:00:00",
"duration": 43200,
"frequency": "daily",
"interval": 1,
"rolling_users": [
["user_id_4"],
["user_id_5"],
["user_id_6"]
],
"by_day": ["MO", "TU", "WE", "TH", "FR"]
},
{
"name": "Weekend rotation",
"type": "rolling_users",
"start": "2026-01-18T00:00:00",
"duration": 86400,
"frequency": "weekly",
"rolling_users": [
["user_id_4"],
["user_id_5"],
["user_id_6"]
],
"by_day": ["SA", "SU"]
}
]
}'
Каждый инженер видит своё расписание в интерфейсе Grafana и получает напоминание в Telegram за 12 часов до начала дежурства.
Настройка цепочек эскалации
Создаём три цепочки эскалации для разных уровней критичности:
# Цепочка для критических алертов (P1)
# Шаг 1: Уведомить текущего дежурного (Telegram + SMS + звонок)
# Шаг 2: Если нет ACK через 5 минут → уведомить следующего по ротации
# Шаг 3: Если нет ACK через 10 минут → уведомить тимлида
# Шаг 4: Если нет ACK через 15 минут → уведомить CTO
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_chains/ \
-H 'Authorization: Bearer ${ONCALL_API_KEY}' \
-H 'Content-Type: application/json' \
-d '{"name": "Critical (P1)"}'
# Добавляем шаги эскалации
# Шаг 1: Уведомить дежурного из расписания
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "notify_on_call_from_schedule",
"notify_on_call_from_schedule": "SCHEDULE_ID",
"position": 0
}'
# Шаг 2: Ждём 5 минут
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "wait",
"duration": 300,
"position": 1
}'
# Шаг 3: Уведомить следующего из ротации
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "notify_on_call_from_schedule",
"notify_on_call_from_schedule": "SCHEDULE_ID",
"important": true,
"position": 2
}'
# Шаг 4: Ждём ещё 5 минут, затем уведомляем тимлида
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "wait",
"duration": 300,
"position": 3
}'
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "notify_persons",
"persons_to_notify": ["TEAM_LEAD_USER_ID"],
"important": true,
"position": 4
}'
# Шаг 5: Ещё 5 минут — эскалация на CTO
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "wait",
"duration": 300,
"position": 5
}'
curl -X POST https://oncall.cloudbase.local/api/v1/escalation_policies/ \
-d '{
"escalation_chain_id": "CHAIN_P1_ID",
"type": "notify_persons",
"persons_to_notify": ["CTO_USER_ID"],
"important": true,
"position": 6
}'
Для Warning-алертов (P2) цепочка проще: уведомление дежурного, ожидание 15 минут, эскалация на тимлида. Для Info-алертов (P3) — только уведомление в Telegram без эскалации.
Маршрутизация алертов по критичности
В каждой интеграции (Alertmanager, Zabbix) настраиваем Routes — правила, которые направляют алерты в нужную цепочку эскалации:
# В интерфейсе Grafana OnCall:
# Integrations → Alertmanager → Routes
# Route 1: severity == critical → Escalation Chain "Critical (P1)"
# Condition: {{ payload.commonLabels.severity == "critical" }}
# Escalation Chain: Critical (P1)
# Route 2: severity == warning → Escalation Chain "Warning (P2)"
# Condition: {{ payload.commonLabels.severity == "warning" }}
# Escalation Chain: Warning (P2)
# Default Route → Escalation Chain "Info (P3)"
# Для Zabbix-интеграции аналогично:
# Route 1: severity содержит "Disaster" или "High" → P1
# Condition: {{ payload.severity in ["Disaster", "High"] }}
# Route 2: severity == "Average" → P2
# Default → P3
Дополнительно настроили шаблоны группировки — алерты с одного хоста группируются в один инцидент, чтобы дежурный не получал 20 отдельных уведомлений, когда падает один сервер:
# Grouping Template для Alertmanager-интеграции:
{{ payload.commonLabels.alertname }}_{{ payload.commonLabels.instance }}
# Grafana OnCall сгруппирует:
# NodeDown_node-03:9100 — все алерты с node-03 в одну группу
# CephOSDDown_ceph-01:9283 — все алерты Ceph в другую
Каналы уведомлений: Telegram, SMS, голосовые звонки
Алерт бесполезен, если дежурный его не увидел. Мы настроили три канала уведомлений с разным уровнем «назойливости» для разных приоритетов.
Telegram-бот для уведомлений
Создаём Telegram-бота и подключаем к OnCall:
# 1. Создаём бота через @BotFather:
# /newbot → CloudBase OnCall Bot → @cloudbase_oncall_bot
# Получаем токен: 7123456789:AAH...
# 2. В Grafana OnCall → Settings → Chat Ops → Telegram
# Указываем токен бота
# Бот автоматически создаёт deep-link для верификации
# 3. Каждый инженер в Telegram пишет боту /start
# и получает код верификации, который вводит в Grafana
# 4. Настройка персональных уведомлений (каждый инженер):
# OnCall → Users → Notification Rules:
# Default notifications:
# Step 1: Notify by Telegram
# Important notifications:
# Step 1: Notify by Telegram
# Step 2: Wait 1 minute
# Step 3: Notify by Phone Call
# Step 4: Wait 2 minutes
# Step 5: Notify by SMS
Telegram-уведомления содержат кнопки для быстрых действий: Acknowledge (принять инцидент), Resolve (закрыть), Silence (приглушить на время). Дежурный может управлять инцидентом прямо из мессенджера, не открывая браузер.
SMS и голосовые звонки для критических алертов
Для SMS и звонков используем Twilio — Grafana OnCall имеет встроенную интеграцию. Однако для российских номеров мы настроили альтернативный канал через SMS-центр:
# /opt/grafana-oncall/custom_notify.py
# Кастомный webhook для SMS через smsc.ru API
import requests
import os
from flask import Flask, request
app = Flask(__name__)
SMSC_LOGIN = os.environ['SMSC_LOGIN']
SMSC_PASSWORD = os.environ['SMSC_PASSWORD']
@app.route('/sms', methods=['POST'])
def send_sms():
data = request.json
phone = data.get('phone')
message = data.get('message', 'OnCall Alert')
resp = requests.get('https://smsc.ru/sys/send.php', params={
'login': SMSC_LOGIN,
'psw': SMSC_PASSWORD,
'phones': phone,
'mes': message[:160],
'charset': 'utf-8'
})
return {'status': 'sent', 'response': resp.text}
@app.route('/call', methods=['POST'])
def make_call():
data = request.json
phone = data.get('phone')
message = data.get('message', 'Критический алерт. Проверьте Grafana OnCall.')
resp = requests.get('https://smsc.ru/sys/send.php', params={
'login': SMSC_LOGIN,
'psw': SMSC_PASSWORD,
'phones': phone,
'mes': f'voice={message}',
'call': 1,
'charset': 'utf-8'
})
return {'status': 'called', 'response': resp.text}
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9099)
В Grafana OnCall подключаем кастомный webhook как канал уведомлений через Outgoing Webhooks. Теперь при Important-уведомлениях дежурный получает: Telegram → ожидание 1 мин → голосовой звонок → ожидание 2 мин → SMS. Не заметить невозможно.
Incident Timeline и Postmortem Workflow
Управление инцидентами не заканчивается на оповещении. Grafana OnCall ведёт полную хронологию каждого инцидента и позволяет проводить постмортемы — разбор причин, чтобы инцидент не повторился.
Автоматический timeline инцидента
Каждый инцидент в Grafana OnCall автоматически собирает timeline — цепочку событий с точными таймстемпами:
# Пример timeline инцидента #47:
# [2026-01-21 02:14:32 MSK] Alert received from Alertmanager
# → CephOSDDown on ceph-02, severity: critical
# [2026-01-21 02:14:33 MSK] Escalation started: Critical (P1)
# [2026-01-21 02:14:34 MSK] Telegram sent to: Иванов А.С. (on-call)
# [2026-01-21 02:19:34 MSK] No ACK after 5 min → escalating
# [2026-01-21 02:19:35 MSK] Phone call to: Иванов А.С.
# [2026-01-21 02:21:12 MSK] Acknowledged by: Иванов А.С.
# → Response time: 6 min 40 sec
# [2026-01-21 02:21:45 MSK] Note added: "Проверяю Ceph status"
# [2026-01-21 02:35:00 MSK] Note added: "OSD.4 упал из-за диска,
# запустил ceph osd repair"
# [2026-01-21 03:12:00 MSK] Resolved by: Иванов А.С.
# → Resolution time: 57 min 28 sec
Вся эта информация сохраняется автоматически и доступна для анализа. Инженеры добавляют заметки в реальном времени через Telegram или интерфейс — это формирует базу знаний.
Postmortem workflow
Для каждого критического инцидента (P1) мы настроили обязательный постмортем. Grafana OnCall создаёт шаблон, который инженер заполняет после resolve:
# Шаблон постмортема (Markdown):
# Автоматически заполняется из timeline
## Postmortem: Incident #47 — CephOSDDown
**Date:** 2026-01-21
**Duration:** 57 min
**Severity:** P1 — Critical
**On-call:** Иванов А.С.
**Response time:** 6 min 40 sec (SLA: 15 min ✅)
### Timeline
(автозаполнение из OnCall)
### Root Cause
(заполняет инженер)
Диск /dev/sdd на ceph-02 начал возвращать ошибки ввода/вывода.
SMART показывал Reallocated_Sector_Ct = 148 (порог 140).
Мониторинг SMART-атрибутов отсутствовал.
### Impact
- 12 клиентов испытывали деградацию storage I/O
- Кластер работал на 2 OSD из 3 (66% capacity)
### Action Items
- [ ] Добавить мониторинг SMART через node_exporter
- [ ] Заказать SSD на замену для ceph-02
- [ ] Настроить предиктивный алерт на SMART degradation
Постмортемы хранятся в Grafana OnCall и экспортируются в Confluence через webhook. Раз в месяц команда проводит разбор всех постмортемов и выполняет action items.
SLA-трекинг и дашборды мониторинга
Внедрение Grafana OnCall позволило «КлаудБейс» не просто реагировать на инциденты, но и измерять качество своей работы. Мы создали дашборды для отслеживания SLA и метрик команды.
Метрики Grafana OnCall в Prometheus
Grafana OnCall экспортирует метрики в формате Prometheus. Настраиваем scrape:
# /etc/prometheus/prometheus.yml — добавляем job
scrape_configs:
- job_name: 'grafana-oncall'
scrape_interval: 30s
static_configs:
- targets: ['oncall-engine:8080']
metrics_path: '/metrics'
# Ключевые метрики:
# oncall_alert_groups_total — общее количество инцидентов
# oncall_alert_groups_response_time_seconds — время реакции
# oncall_alert_groups_resolution_time_seconds — время решения
# oncall_escalations_total — количество эскалаций
# oncall_notifications_sent_total — отправленные уведомления
На основе этих метрик создаём Grafana-дашборд:
# Grafana Dashboard JSON (ключевые панели):
# Panel 1: SLA Compliance (Stat)
# Query:
# (count(oncall_alert_groups_response_time_seconds{severity="critical"} < 900)
# / count(oncall_alert_groups_response_time_seconds{severity="critical"})) * 100
# Threshold: Green > 95%, Yellow > 90%, Red < 90%
# Panel 2: MTTR — Mean Time to Resolve (Gauge)
# Query:
# avg(oncall_alert_groups_resolution_time_seconds{severity="critical"}) / 60
# Unit: minutes
# Panel 3: Escalation Rate (Time Series)
# Query:
# rate(oncall_escalations_total[7d])
# Описание: Чем ниже — тем лучше. Значит дежурные реагируют без эскалации.
# Panel 4: On-Call Load by Engineer (Bar Gauge)
# Query:
# sum by (user) (oncall_alert_groups_total{acknowledged_by!=""})
# Показывает, кто обработал больше всего инцидентов
Результаты внедрения
Через 2 месяца после внедрения Grafana OnCall мы собрали статистику и сравнили с показателями до:
| Метрика | До внедрения | После внедрения |
|---|
| Среднее время реакции (P1) | 47 минут | 4 минуты 20 секунд |
| SLA compliance (15 мин на P1) | 72% | 98.5% |
| Пропущенные ночные алерты | 23% (не замечены) | 0% |
| MTTR (P1 инциденты) | 2 ч 15 мин | 38 минут |
| Количество эскалаций на тимлида | N/A | 8% инцидентов |
| Повторяющиеся инциденты | 34% (без анализа) | 12% (постмортемы) |
Ключевой результат: за 2 месяца ни одного нарушения SLA по критическим инцидентам. Дежурный инженер всегда знает, что он дежурный, и всегда получает уведомление лично — по Telegram, звонком или SMS. Алерт больше не может остаться «ничьим».
«КлаудБейс» использовала улучшение SLA как маркетинговый аргумент — обновила SLA-гарантии для клиентов с 99.5% до 99.9%, что привлекло 7 новых корпоративных клиентов в первый же квартал.