gendesign/ops/metrics/alertmanager/alertmanager.yml.tmpl
bot-backend 655652ae1c
All checks were successful
CI Trade-In / changes (pull_request) Successful in 11s
CI / changes (pull_request) Successful in 14s
CI Trade-In / backend-tests (pull_request) Has been skipped
CI Trade-In / browser-tests (pull_request) Has been skipped
CI Trade-In / frontend-checks (pull_request) Has been skipped
CI / backend-tests (pull_request) Has been skipped
CI / frontend-tests (pull_request) Has been skipped
CI / openapi-codegen-check (pull_request) Has been skipped
feat(ops): алерты уровня приложения и три слепые зоны мониторинга
- AppHighErrorRate / AppHighLatencyP95 (job="app", severity=critical,
  host="apps") — доля 5xx и p95 задержки по http_requests_total /
  http_request_duration_seconds_bucket теперь ловятся Prometheus'ом, а не
  только постфактум в GlitchTip. Пара critical+apps обязательна для
  маршрута telegram-clients в alertmanager.yml.tmpl.
- Inhibit по HostAgentDown больше не гасит critical того же хоста —
  target_matchers сужен до severity="warning" (падение node-exporter
  раньше молча забирало с собой PostgresLongTransactionCritical и
  critical-алерты cAdvisor).
- cAdvisor: keep-фильтр в alloy-infra.alloy резал у него `up` наравне с
  container_*-мусором — job "cadvisor" не публиковал свою же серию `up`.
  Пропущены up/scrape_samples_scraped, добавлен CadvisorDown.
- TradeInBackgroundContainerMissing по absent(container_last_seen) на
  tradein-tgbot/tradein-scraper — эти контейнеры не HTTP-сервисы и в
  up{} не участвуют вовсе; крэш без рестарта раньше не алертился.

Не закрыто: живой, но зависший процесс tgbot/scraper (container_last_seen
не про внутренний прогресс, а про то, что Docker видит контейнер running).

Refs #3471
2026-09-12 13:57:54 +03:00

130 lines
8.2 KiB
Cheetah
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Шаблон конфигурации Alertmanager. Боевой файл собирается на хосте при деплое
# (`envsubst` в deploy-metrics.yml) и в репозиторий не попадает — токен бота и
# идентификатор чата живут в окружении хоста, а не в git.
#
# ПОЧЕМУ TELEGRAM НАПРЯМУЮ, А НЕ ЧЕРЕЗ БЭКЕНД МЕРЫ. У МЕРЫ уже есть рабочий путь
# доставки (вебхук GlitchTip → бот), и соблазн переиспользовать его велик. Но тогда
# сообщение о том, что лёг Poincare, шло бы через сервис НА Poincare. Алерт обязан
# уметь уйти без участия хоста, про который он написан.
#
# Telegram с Beget работает — проверено серией замеров 25.08: TLS-рукопожатие
# 18 из 20, getMe 4 из 4. Ломается только длинный long-poll (30 с), а отправка
# сообщения — короткий запрос.
#
# ПОЧЕМУ ДВЕ ТЕМЫ, А НЕ ОДНА (#3163). Форум держит тему «алерты» (158,
# клиентские инциденты МЕРЫ) и тему «метрики» (245, инфраструктурный шум —
# диск, память, просевший экспортер). Инфраструктурный шум и клиентский
# инцидент не равны по срочности, а смешанные в одной теме они обучают
# пролистывать обе. Поэтому `telegram` и `telegram-heartbeat` ниже адресуют
# ИНФРАСТРУКТУРНУЮ тему (`METRICS_TELEGRAM_INFRA_TOPIC_LINE`). Получателя
# `telegram-clients` в этом списке нет: он не шлёт в Telegram напрямую, а
# вебхуком уходит в alert-ack, и тему адресует сам, своей переменной
# METRICS_TELEGRAM_TOPIC_ID.
global:
resolve_timeout: 5m
route:
receiver: telegram
# Группируем по алерту и хосту: пятнадцать контейнеров одного хоста, упавших
# разом, — это одно событие, а не пятнадцать сообщений.
group_by: ["alertname", "host"]
group_wait: 45s
group_interval: 5m
# Повтор раз в 6 часов. Чаще — приучает игнорировать, реже — можно проспать.
repeat_interval: 6h
routes:
# Watchdog не должен смешиваться с настоящими алертами и не должен молчать:
# это «сторож сторожа», он горит всегда и подтверждает, что канал доставки жив.
- receiver: telegram-heartbeat
matchers:
- alertname = "Watchdog"
group_wait: 0s
group_interval: 12h
repeat_interval: 12h
# Клиентский инцидент. host="apps" — это продуктовая машина: если на ней
# критично, значит МЕРА и Site Finder недоступны людям, а не «где-то в
# инфраструктуре тесно». Такое зовём поимённо и напоминаем часто.
#
# Почему отдельный маршрут, а не общий critical: 27.08 продукты лежали
# 10 часов, и разницы между «диск на 86 %» и «клиенты не могут открыть
# сайт» в канале не было никакой. Разный текст и разная настойчивость —
# это и есть разница.
#
# repeat_interval 30m против 3h у прочего критичного: пока инцидент не
# погашен, напоминание должно быть неудобным. Заглушить его — осознанное
# действие через Alertmanager, и оно же служит отметкой «принято».
- receiver: telegram-clients
matchers:
- severity = "critical"
- host = "apps"
group_wait: 10s
repeat_interval: 30m
# Прочее критичное — инфраструктура, клиенты пока не затронуты.
- receiver: telegram
matchers:
- severity = "critical"
group_wait: 10s
repeat_interval: 3h
inhibit_rules:
# Если хост целиком недоступен, не сыпать отдельно про каждый его
# warning-сервис. `target_matchers` НАМЕРЕННО ограничен одним warning
# (#3471): раньше сюда попадал и critical, и падение node-exporter молча
# гасило заодно PostgresLongTransactionCritical и все critical cAdvisor-
# алерты того же хоста — самое важное сообщение исчезало вместе с шумом,
# который оно должно было подавить. Warning того же хоста подавлять по-
# прежнему стоит (диск/память/своп неотличимы от «нет данных»), а critical
# обязан пережить это подавление и дойти до дежурного отдельно.
- source_matchers: [alertname = "HostAgentDown"]
target_matchers: [severity = "warning"]
equal: ["host"]
receivers:
- name: telegram
telegram_configs:
- bot_token: "${METRICS_TELEGRAM_BOT_TOKEN}"
chat_id: ${METRICS_TELEGRAM_CHAT_ID}
${METRICS_TELEGRAM_INFRA_TOPIC_LINE}
api_url: "https://api.telegram.org"
parse_mode: HTML
send_resolved: true
message: |
{{ if eq .Status "firing" }}🔴{{ else }}🟢{{ end }} <b>{{ .CommonLabels.alertname }}</b>{{ if .CommonLabels.host }} · {{ .CommonLabels.host }}{{ end }}
{{ range .Alerts }}
{{ .Annotations.summary }}
{{ if .Annotations.description }}{{ .Annotations.description }}{{ end }}
{{ end }}
# Клиентский инцидент уходит В СЕРВИС, а не напрямую в Telegram.
#
# Alertmanager инлайн-клавиатуру не умеет, а без кнопки нет обратной связи
# «человек увидел и взял в работу». Сервис alert-ack (тот же хост, рядом)
# формирует сообщение с упоминанием дежурного и кнопкой подтверждения, а по
# нажатию отвечает в ту же тему «принято, кто, во сколько».
#
# ЧТО ПРОИСХОДИТ, ЕСЛИ СЕРВИС ЛЁГ. Alertmanager считает доставку неудачной и
# повторяет; плюс сам инцидент остаётся активным и переуведомляется каждые
# 30 минут (repeat_interval маршрута выше). То есть алерт задерживается, но
# не теряется. Это сознательный размен: дублировать то же сообщение вторым,
# прямым каналом означало бы два уведомления на каждый инцидент, а шум в
# канале тревог опаснее, чем задержка.
- name: telegram-clients
webhook_configs:
- url: "http://alert-ack:8080/alertmanager"
send_resolved: true
- name: telegram-heartbeat
telegram_configs:
- bot_token: "${METRICS_TELEGRAM_BOT_TOKEN}"
chat_id: ${METRICS_TELEGRAM_CHAT_ID}
${METRICS_TELEGRAM_INFRA_TOPIC_LINE}
api_url: "https://api.telegram.org"
parse_mode: HTML
send_resolved: false
message: |
⚪ <b>Мониторинг жив</b> — сторож отчитался, канал доставки работает.
Если это сообщение перестало приходить дважды подряд, замолчал сам мониторинг.