Красивые дашборды нравятся всем, пока сервер работает. Как только ночью падает база или диск заполняется на 95 процентов, выясняется неприятная правда: графики молча рисуют проблему, но никого не будят. Между "видеть метрику" и "узнать о сбое вовремя" лежит отдельный механизм доставки алертов, и в связке с Grafana его обычно закрывает Alertmanager. Статья собирает рабочую конфигурацию целиком: правила в Grafana, доставка в Telegram и на email, группировка потоков уведомлений и проверка всей цепочки тестовым срабатыванием.
Как устроена цепочка доставки алертов от сбоя до уведомления
Механизм состоит из трёх независимых ролей. Правила алертов решают, что считать проблемой: они смотрят на метрики и переводят числа в события с текстом и метками. Служба доставки принимает события, группирует их, гасит повторы и выбирает маршрут: кому, каким каналом и с каким приоритетом. Приёмники - это конечные точки, например чат в Telegram или почтовый ящик администратора.
Возникает вопрос: зачем Grafana отдельная служба доставки, если уведомления можно слать прямо из правил. Ответ в поведении при реальном сбое. Упавший маршрутизатор генерирует десятки событий сразу: недоступность узла, потеря метрик, срабатывание проверок на всех серверах за ним. Без промежуточного звена администратор получает лавину одинаковых сообщений вместо одного понятного. Alertmanager собирает поток в компактные группы, ждёт короткую паузу на случай соседних событий, подавляет следствия при наличии более серьёзной причины и повторяет напоминание не чаще заданного интервала. В спокойном режиме эти детали не видны, в аварийном они экономят часы.
У события есть жизненный цикл из двух состояний. Пока нарушено условие, но выдержка по времени не истекла, событие числится pending и никуда не отправляется: краткий всплеск загрузки не должен будить никого. После истечения выдержки событие становится firing и попадает в службу доставки. К нему приложены метки вроде severity и instance, по которым строится маршрутизация, и аннотации с человеческим текстом. Понимание этих двух состояний экономит много времени при отладке: событие "висит, но не приходит" почти всегда означает, что правило просто не дозрело.
Установка Alertmanager рядом с Prometheus и разбор базового файла конфигурации
В Ubuntu 24.04 служба ставится из репозитория пакетом prometheus-alertmanager и сразу регистрируется в системе инициализации. В ручном варианте скачивают официальный архив, распаковывают в /opt и пишут юнит на пять строк - оба пути дают одинаковый результат, различие только в удобстве будущих обновлений. После запуска служба слушает порт 9093, и этот порт не открывают наружу без веской причины: веб-интерфейс умеет ставить паузы, но не умеет защищать себя всерьёз.
Здоровье установки проверяется тремя командами подряд.
sudo apt install prometheus-alertmanager
sudo systemctl enable --now prometheus-alertmanager
curl -s localhost:9093/-/ready
Ответ ready от последней команды означает, что служба прочитала конфигурацию и готова принимать события. Если Prometheus уже развёрнут, ему указывают адрес соседа в его собственном конфигурационном файле секцией alerting, и с этой секунды все сработавшие правила потекут в службу доставки автоматически.
Ключевой файл - /etc/prometheus/alertmanager.yml, и в минимальном рабочем виде он описывает две вещи: параметры отправки и маршруты. Пример конфигурации с почтой и Telegram выглядит так.
global:
resolve_timeout: 5m
smtp_smarthost: "mail.example.com:587"
smtp_from: "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. "
smtp_auth_username: "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. "
smtp_auth_password: "пароль-ящика"
route:
receiver: email-all
group_by: ["alertname", "instance"]
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers:
- severity="critical"
receiver: telegram-admin
- matchers:
- severity="warning"
receiver: email-all
receivers:
- name: email-all
email_configs:
- to: "Адрес электронной почты защищен от спам-ботов. Для просмотра адреса в браузере должен быть включен Javascript. "
send_resolved: true
- name: telegram-admin
telegram_configs:
- bot_token: "токен-бота"
chat_id: 123456789
send_resolved: true
parse_mode: "HTML"
Смысл маршрутизации читается сверху вниз. Событие с меткой severity уровня critical уходит в Telegram, прочие предупреждения собираются в почтовые письма. Поле group_wait в 30 секунд даёт соседним событиям шанс приехать вместе, group_interval ограничивает частоту пополнений группы, repeat_interval заставляет службу напоминать о невылеченной проблеме каждые четыре часа. Флаг send_resolved отправляет сообщение о восстановлении, и по опыту это половина ценности алертов: знать, когда стало спокойно, не менее важно, чем знать о факте сбоя.
Регистрация бота в Telegram и получение идентификатора чата для отправки
Доставка в мессенджер идёт через бота, и бот создаётся за пару минут. В поиске Telegram находят штатного служебного бота платформы, командой /newbot регистрируют нового, задают отображаемое имя и короткий идентификатор. В ответ приходит длинный токен вида цифры и буквы через двоеточие - он единственный секрет, который нужен для отправки, и хранить его стоит с правами 600 там же, где пароли сервера.
Идентификатор чата добывается технически. Боту отправляют любое сообщение из нужного чата, затем вызывают метод API сбора обновлений и читают поле chat.id в ответе.
curl -s https://api.telegram.org/botТОКЕН/getUpdates | jq '.result[0].message.chat.id'
Для личных чатов идентификатор положительный, для групповых начинается с минуса, и отсутствие знака в конфигурации - самая частая причина, по которой сообщения тихо не доходят. Проверить отправку руками можно тем же curl методом sendMessage, подставив идентификатор и текст. Полезная привычка - отдельный чат для алертов и отдельный бот на каждый контур: продакшен и тестовая площадка не должны смешивать потоки, иначе среди учебных срабатываний теряется настоящее.
Токен ведёт себя как пароль с одной кнопкой отключения. Утёкший в репозиторий или скриншот токен отзывается через того же служебного бота командой ревокации, после чего доставка остановится у всех, включая законного владельца, и токен придётся вписывать заново. Поэтому конфигурацию с токеном не хранят в открытых репозиториях, а на сервере файлу выставляют права 600 и владельца из-под которого работает служба.
Правила алертов в Grafana и связка с контактами доставки
Grafana строит правила в разделе алертов и умеет доставлять уведомления двумя способами. Первый - контактные точки самой Grafana, где среди типов доступен и Alertmanager, и мессенджер напрямую. Второй - правила Prometheus, а Grafana остаётся витриной. Практика контуров небольшого размера выбирает единые правила в Grafana и точку доставки типа Alertmanager: вся маршрутизация живёт в одном файле, а панели служат источником выражений.
Типовое правило для загрузки процессора формулируется выражением на языке запросов и порогом. Например, событие срабатывает, когда средняя загрузка узла держится выше 90 процентов пять минут подряд. К правилу добавляются метки severity и team, по ним маршрутизатор и раскладывает события по приёмникам. Набор здравых порогов для начала выглядит скромно и покрывает большинство ночных историй: процессор 90 процентов на 5 минут, доступная память ниже 10 процентов, свободное место на разделе меньше 15 процентов, служба или контейнер недоступен 2 минуты. Список расширяется по мере знакомства с характером конкретной инфраструктуры, и первая ошибка начинающих - десятки правил с порогами на грани шумов.
Какие пороги выбрать для правил и как оформить текст уведомления
Выражения для базового набора проверок выглядят компактно и читаются как обычная арифметика.
# процессор: средняя загрузка выше 90 процентов на пятиминутном окне
(1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) > 0.90
# память: доступно меньше 10 процентов от общего объёма
(node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes) < 0.10
# диск: свободно меньше 15 процентов на корневом разделе
(node_filesystem_avail_bytes{mountpoint="/"} / node_filesystem_size_bytes{mountpoint="/"}) < 0.15
Если правила живут в Prometheus, а Grafana подключена к нему как витрина, тот же порог оформляется файлом правил с выдержкой времени и аннотациями.
groups:
- name: host
rules:
- alert: HighCPU
expr: (1 - avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) > 0.90
for: 5m
labels:
severity: warning
annotations:
summary: "Загрузка процессора выше 90 процентов"
description: "Узел держит высокую загрузку дольше пяти минут"
Текст уведомления оформляют по правилу первой строки: сразу кто, что и насколько. Хороший шаблон начинается с имени узла и метрики, продолжает конкретной цифрой и заканчивается ссылкой на панель. Сравните "проблемы на сервере" и "web-1, свободно 9 процентов на разделе /var, порог 15 процентов": вторая формулировка позволяет начинать действовать до открытия дашборда. Эмоциональные обороты в алертах не работают, конкретные числа работают всегда.
Группировка, подавление и паузы в правилах маршрутизации
Кроме группировки маршрутный файл поддерживает подавление следствий. Классическая пара: событие "узел недоступен" уровня critical подавляет все предупреждения с этого же узла, потому что они не самостоятельные проблемы, а эхо. Правило описывается в секции inhibit_rules и экономит администратору десятки сообщений при падении одной машины.
inhibit_rules:
- source_matchers:
- severity="critical"
target_matchers:
- severity="warning"
equal: ["instance"]
Паузы закрывают третью бытовую ситуацию: плановые работы. Кнопка Silence в веб-интерфейсе на 9093 глушит события по фильтрам на заданное время, например на два часа обслуживания базы. У пауз есть инструмент командной строки amtool, им ставят и снимают паузы из скриптов, а заодно проверяют синтаксис файла конфигурации командой amtool check-config - она ловит ошибку в YAML до перезапуска службы, что при удалённом администрировании стоит дорого.
Дисциплина работы с паузами - отдельная часть культуры дежурства. Хорошая пауза имеет автора, причину и конечный срок, а бесконечных пауз не существует: сочетание фильтров, отключённое на месяц, превращается в тихую дыру, через которую уходит настоящий сбой. Раз в месяц список активных пауз пересматривают целиком и вычищают забытые записи, это занимает пять минут и защищает от слепых зон лучше любого нового правила.
Проверка цепочки тестовым алертом и типичные ошибки интеграции
Собранную связку проверяют по шагам, и каждый шаг отсекает свой класс ошибок. Порядок выглядит так:
- amtool check-config подтверждает, что файл маршрутизации читается без синтаксических ошибок;
- в веб-интерфейсе 9093 отправляется тестовое событие и фиксируется приход в оба приёмника;
- в Grafana создаётся заведомо срабатывающее правило, например порог загрузки в 1 процент;
- после доставки тестовое правило гасится до нормальных порогов, а история событий сверяется в списке алертов.
Диагностика идёт по цепочке от источника к приёмнику. Журнал службы показывает очередь отправок и ошибки доставки, читается он командой journalctl с ключом -u для юнита prometheus-alertmanager и -f для слежения в реальном времени. Список активных событий с метками показывает amtool alerts, а веб-интерфейс хранит историю с фильтрами по приёмникам. Если событие есть в списке, но сообщения нет, проблема в конфигурации приёмника; если события нет вовсе - смотрят правило и метрики на шаг раньше.
Из повторяющихся граблей стоит помнить четыре. Идентификатор группового чата без минуса, из-за чего доставка молчит при валидном токене. Почта через порт 25, который у большинства провайдеров закрыт исходяще - решением служит 587 с авторизацией и шифрованием. Токен бота в YAML без кавычек, где двоеточие внутри ломает структуру файла. Открытый наружу порт 9093 как единственная защита веб-интерфейса - при доступе из интернета паузы ставит кто угодно, поэтому интерфейс прячут за обратный прокси или туннель администратора. Рабочая связка Grafana, Alertmanager, Telegram и почты собирается за вечер, после чего мониторинг начинает разговаривать с администратором сам, а не наоборот.