настройка self-hosted, часть 4: настройка алертинга через grafana

Содержание:

В первой статье мы сделали базовую настройку алертов со стороны провайдера DO. Они остаются - даже если Grafana упадет, они продолжат работать. Но эти алерты максимально простые и не позволяют настраивать специфичные условия и выбирать канал для отправки алерта.

В части 2 мы настроили метрики системы и сервисов, в части 3 - метрики HTTP-трафика. В этой статье добавим алерты в телеграм, если что-то идет не так.


Финальный чеклист

Telegram и contact point

Базовые алерты

Caddy

Внешний мониторинг

Проверка


Главное


1. Создаем Telegram-бота

В Telegram-чате с @BotFather -> /newbot, создаем бота. Сохраняем токен. В своем боте нажимаем Start - боты не умеют писать, пока общение не инициировано юзером.

Узнаем chat_id - например, через @userinfobot. Он нужен, чтобы Grafana знала, куда слать сообщения.

2. Contact point в Grafana

Contact point

В Grafana: Alerting -> Notification configuration -> New contact point:

{{ range .Alerts -}}
{{ if eq .Status "firing" }}🔴{{ else }}✅{{ end }} {{ .Labels.alertname }}
{{ if eq .Labels.severity "critical" }}🚨{{ else }}⚠️{{ end }} {{ .Labels.severity }}

{{ .Annotations.summary }}
{{ .Annotations.description }}
{{- end }}

Шаблон рисует алерты вида:

🔴 Disk almost full
⚠️ warning

Disk usage above 85%
Disk: 87.3%. Clean up: docker system prune -af, old logs, unused volumes.

---

✅ Disk almost full
⚠️ warning

Disk usage above 85%
Disk: 84.1%. Clean up: docker system prune -af, old logs, unused volumes.

Также в Optional Telegram settings нужно поправить два пункта:

Дальше Save contact point и Test. В Telegram должно прийти тестовое сообщение. Оно пока будет без контекста, сейчас важен только факт отправки:

🔴 TestAlert
⚠️ 

Notification test

3. Notification policy

Alerting -> Notification policies -> Default policy -> Edit.

Здесь есть опции, связанные с группами. Группа - это похожие алерты, объединенные каким-то лейблом. Все алерты группы шлются одним сообщением.

Notification policy

Поля, которые нужно настроить:

Сохраняем - Update policy.

Alerting -> Silence нужен для мьюта алертов. Что-то алертит - идем мьюить, чиним, потом убираем (или снимется само через duration).

4. Базовые алерты

Alerting -> Alert rules -> New alert rule. Форма создания правила разделена на шесть блоков. Сначала опишем, потом посмотрим на конкретных алертах. Но сперва - небольшое отступление про метрики, на которых строятся запросы.

Типы метрик Prometheus

Основных видов 3:

Структура алерта

Alerts

1. Enter alert rule name. По нему правило ищется в списке и подставляется в сообщение как лейбл alertname. Брать короткое и описательное, вроде Memory high, Container down и т.д.

2. Define query and alert condition. Условие срабатывания алерта:

3. Add folder and labels.

4. Set evaluation behavior.

5. Configure notifications.

6. Configure notification message.

Сохраняем, идем в Alert rules - алерт будет со статусом Normal или Firing.

Полный пример моих алертов:

4.1 Memory > 90% / 5m

4.2 Disk > 85% / 10m

4.3 CPU > 95% / 15m

Pending period: 15m - потому что короткие пики (docker build, пересборка блога, тяжелая cron-задача) - норма. Подозрительно только когда CPU держится выше 95% четверть часа.

Формула усредняет загрузку по всем CPU одного хоста. Сейчас Prometheus скрейпит только VPS, так что этого достаточно. Когда добавится второй хост (домашний сервер, см. конец статьи), оберни внутреннюю часть в avg by (instance)(...) - иначе CPU обеих машин сольется в одно среднее, и алерт потеряет смысл.

4.4 Container down

container_last_seen - метрика cAdvisor: когда контейнер последний раз был живой. time() - container_last_seen дает, сколько секунд назад его видели, а threshold IS ABOVE 60 ловит момент, когда cAdvisor перестал видеть контейнер.

Ставим Alert state if no data на Normal, потому что cAdvisor может временно не отдать метрики - запрос вернет пусто, и при дефолтном Alerting алерт ложно ушел бы в Firing. С Normal молчим, если данных нет.

4.5 Swap > 50% / 5m (опционально)

Если своп выделяется - значит RAM кончилась. Если памяти на сервере мало, может быть полезно знать.

5. Метрики Caddy per host

Дока Caddy по настройке метрик: https://caddyserver.com/docs/metrics

По умолчанию Caddy не добавляет лейбл host в Prometheus-метрики. Без него insomnia.cat и grafana.insomnia.cat попадают в одну кучу, и алерт на latency срабатывает из-за Grafana, а не из-за реальной проблемы с блогом.

Фикс - блок metrics на верхнем уровне глобального блока /etc/caddy/Caddyfile:

{
    email your@email.com
    metrics {
        per_host
    }
}

Если в конфиге есть servers { metrics } - нужно его убрать, т.к. глобальный metrics заменяет его полностью. Без этого конфиг будет невалидный.

Валидируем и перезапускаем:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl restart caddy

Именно restart, не reload. reload делает перезагрузку конфига, но не сбрасывает метрики (как я выяснил на практике). Старые метрики без лейбла host продолжают жить, и фильтр по хосту не находит ничего. После полного рестарта метрики начинают собираться заново с per_host.

После применения в метриках появится лейбл host, и запросы можно фильтровать: {host="insomnia.cat"} - только блог, {host="grafana.insomnia.cat"} - только Grafana.

6. Алерты на Caddy

Эти алерты работают только если выполнен гайд из части 3 - метрики Caddy должны быть в Prometheus.

6.1 5xx rate > 5 запросов / 5m

Caddy экспортирует гистограмму caddy_http_request_duration_seconds. Счетчик с суффиксом _count считает запросы с теми же лейблами (включая code), поэтому используем его.

or vector(0) - заглушка, нужна потому, что Caddy не создает лейблы для кодов, которых еще не было. Если пятисотых ответов не было ни разу - метрики с code=~"5.." нет в TSDB, sum() возвращает пусто, Grafana будет ложно алертить. С or vector(0) запрос всегда возвращает число: 0 когда чисто, реальный счетчик когда нет.

Пороги алерта зависят от профиля нагрузки конкретного сервиса - подбирайте под свой трафик.

6.2 p99 latency > 1s / 10m

Фильтр {host="insomnia.cat"} изолирует блог от Grafana. Статика должна укладываться быстро, поэтому я поставил условием > 1s.

7. BetterStack для мониторинга самой Grafana

Если Grafana или весь VPS упадет - мы не получим алерт. Поэтому нам нужен мониторинг для мониторинга.

Я использую бесплатный BetterStack, но есть и другие - StatusCake, Uptime Kuma и т.д. Регаемся на https://betterstack.com, выбираем Uptime monitoring -> Grafana -> URL.

Переходим в созданный монитор -> Alert us when -> URL returns HTTP status other than -> 401 -> Save changes. Алерт будет идти письмом на почту.

Если монитор будет получать 401, то Grafana можно считать живой.

betterstack

8. Тестим алерты

Проще всего временно занизить порог одного из реальных алертов и подождать.

Memory сейчас (на свежей VPS под нагрузкой Prometheus + Grafana + cadvisor) обычно держится в районе 60-80%. Меняем threshold алерта 4.1 с 90 на 50, ждем 5-7 минут (Pending period: 5m). В Telegram должно прилететь сообщение. После теста возвращаем порог обратно.

Альтернатива для проверки Container down - поднять одноразовый контейнер, дать cAdvisor его заметить, затем остановить:

docker run -d --name testnginx nginx
# подождать ~минуту, чтобы cAdvisor увидел контейнер
docker stop testnginx

Через 2-3 минуты должен прийти Container down (name=testnginx). После теста - docker rm testnginx.

Сам cadvisor для этого теста останавливать нельзя: он источник метрики container_last_seen. Если убить cadvisor, Prometheus пометит его серии stale, запрос уйдет в no-data, а для Container down у нас стоит Alert state if no data = Normal (раздел 4.4) - алерт промолчит, а не сработает. По той же причине не трогаем prometheus (хранилище метрик) и grafana (движок алертинга).

Что еще можно добавить

Сейчас алерты покрывают только верхнеуровневые характеристики (память, CPU, диск, контейнеры, Caddy).

Кандидаты на алерты: node_exporter (хост)

cadvisor (контейнеры)

fail2ban

Для него нужен отдельный экспортер, например https://github.com/hctrdev/fail2ban-prometheus-exporter. (Может, добавлю в одной из будущих статей)

Алерты:

headscale (нативные метрики)

В одной из будущих статей будет headscale, так что на будущее.

tailscale-exporter (бизнес-метрики headscale)

Домашний сервер (связь через tailnet)

После подключения к tailnet Prometheus на VPS будет скрейпить его по MagicDNS (http://mio.insomnia.internal:9100).

node_exporter поддерживает метрики здоровья батареи, что может быть ценным для домашнего сервера на старом ноуте. Помимо основных node_exporter метрик, можно взять следующие две:


Что дальше

Скорее всего, в следующей статье будет настройка домашнего сервера и headscale для связи. VPS в таком случае начнет выступать просто как прокси, вся реальная работа сервисов может происходить на домашнем сервере.