Uptime Kuma Discord Webhook: алерты из Grafana и Alertmanager
Алерты мониторинга в Discord: настройка Uptime Kuma discord webhook, contact point в Grafana, discord_configs в Alertmanager и cron-проверка на bash.
На этой странице
- Зачем слать алерты мониторинга в Discord
- Uptime Kuma Discord webhook
- Grafana Discord webhook (contact point)
- Alertmanager: receiver для Discord
- Cron-проверка на bash
- Цветные embed для up и down
- Как не устроить шторм алертов
- Частые ошибки
- FAQ
- Нужен ли Uptime Kuma бот Discord для отправки алертов?
- Какая версия Alertmanager поддерживает discord_configs?
- Можно ли отправлять алерты Grafana или Alertmanager в тред?
- Как перестать получать сообщение каждую минуту, пока сервис лежит?
- Что дальше
Зачем слать алерты мониторинга в Discord
Падение, которое прилетело в #alerts, заметят за секунды; то же падение в почте увидят после обеда. Вебхуки делают это почти бесплатно: без бота, без OAuth, без серверного кода. Создаёте вебхук в «Настройки сервера → Интеграции → Вебхуки», копируете URL — и любой инструмент из этой статьи сможет в него постить.
Четыре варианта, по возрастанию трудозатрат:
- Uptime Kuma — встроенный тип уведомления Discord: вставили URL и готово.
- Grafana Alerting — contact point типа Discord.
- Prometheus Alertmanager — receiver
discord_configs, доступен начиная с Alertmanager 0.25. - Cron — короткий bash-скрипт для сервера, на котором ничего из перечисленного нет.
Дальше — цветовая кодировка embed, чтобы красная карточка читалась как «упало» без вчитывания, и защита от штормов, когда одна плохая ночь превращается в четыреста пингов.
Заведите отдельный вебхук под канал алертов (как получить URL) и относитесь к нему как к паролю: любой, у кого есть URL, может писать в канал, а единственное лечение — удалить вебхук и создать новый.
Uptime Kuma Discord webhook
В Uptime Kuma Discord — полноценный тип уведомления, никаких «generic webhook» с ручным маппингом полей.
- Откройте Settings → Notifications → Setup Notification.
- В Notification Type выберите Discord.
- Вставьте URL в поле Discord Webhook URL.
- По желанию задайте Bot Display Name (это подмена
username, поэтому в нём не должно быть слов «discord» и «clyde») и Prefix Custom Message. - Нажмите Test, затем Save. Поставьте галочку Apply on all existing monitors либо подключите уведомление точечно на странице редактирования монитора.
Формат карточки фиксированный: при DOWN — красный embed с заголовком «❌ Your service name went down. ❌» и полями Service Name, Service URL, Time и Error; при UP — зелёный embed, где вместо ошибки поле Ping. JSON вы не пишете; имя и префикс — единственные ручки оформления.
Префикс — место для пинга роли. Uptime Kuma отправляет его как content сообщения, так что <@&ROLE_ID> там упомянет дежурную роль над embed. Если пинг отрисовался обычным текстом — id неверный (скопируйте его в режиме разработчика: правый клик по роли → «Копировать ID роли»); как allowed_mentions решает, кого пинговать, — в статье про упоминания через вебхук.
Защита от шторма настраивается на каждом мониторе: Retries (сколько проверок подряд должно упасть, прежде чем монитор перейдёт в DOWN), Heartbeat Retry Interval и Resend Notification if Down X times consecutively (оставьте 0, чтобы получить ровно одно DOWN-сообщение).
Grafana Discord webhook (contact point)
В Grafana Alerting интеграция с Discord есть из коробки:
- Alerting → Contact points → Create contact point.
- Integration: Discord. Вставьте URL вебхука.
- Title и Message content оставьте по умолчанию (
{{ template "default.title" . }}и{{ template "default.message" . }}). - Test, затем Save.
- Alerting → Notification policies: направьте на этот contact point политику по умолчанию или дочернюю политику с матчерами по лейблам. Иначе contact point существует, но в него ничего не маршрутизируется.
Grafana отправляет сообщение текстом над embed; сам embed — красный, пока группа алертов горит, и зелёный после resolve, — несёт заголовок и ссылку обратно в Grafana. Заголовок и сообщение обрезаются под лимиты Discord (256 и 2000 символов), так что правило с тремя десятками лейблов не приведёт к 400.
То же самое в виде provisioning-YAML:
# provisioning/alerting/discord.yaml
apiVersion: 1
contactPoints:
- orgId: 1
name: discord-ops
receivers:
- uid: discord-ops
type: discord
settings:
url: https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN
title: '{{ template "default.title" . }}'
message: '{{ template "default.message" . }}'
use_discord_username: false
policies:
- orgId: 1
receiver: discord-ops
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
Три поля с таймингами — и есть ваш контроль шторма: group_wait собирает алерты, пришедшие в первые 30 секунд, в одно сообщение; group_interval ограничивает, как часто группа присылает обновления; repeat_interval задаёт, как часто повторно отправлять всё ещё горящий алерт. С четырёхчасовым повтором падение на выходных даст несколько сообщений, а не сотни.
Alertmanager: receiver для Discord
Начиная с Alertmanager 0.25 интеграция с Discord встроенная; раньше приходилось ставить мост или заворачивать generic-webhook в прокси, который переформатировал payload, и если у вас до сих пор так — обновиться быстрее, чем чинить.
# alertmanager.yml
global:
resolve_timeout: 5m
route:
receiver: discord
group_by: ['alertname', 'job']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- matchers:
- severity = critical
receiver: discord-critical
repeat_interval: 1h
receivers:
- name: discord
discord_configs:
- webhook_url: https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN
send_resolved: true
- name: discord-critical
discord_configs:
- webhook_url: https://discord.com/api/webhooks/OTHER_ID/OTHER_TOKEN
send_resolved: true
title: '{{ template "discord.default.title" . }}'
message: '{{ template "discord.default.message" . }}'
inhibit_rules:
- source_matchers:
- severity = critical
target_matchers:
- severity = warning
equal: ['alertname', 'instance']
Alertmanager отправляет один embed на уведомление: красный для firing, зелёный для resolved, описание рендерится из message и обрезается под лимит embed. Проверить конфиг и перечитать его без рестарта:
amtool check-config alertmanager.yml
curl -X POST http://localhost:9093/-/reload
Не коммитьте webhook_url (в новых релизах есть webhook_url_file; сверьтесь с документацией своей версии) и помните, что первая линия обороны — for: в правиле Prometheus: с for: 5m алерт не дойдёт даже до Alertmanager, пока условие не продержится пять минут.
Cron-проверка на bash
Для VPS без стека мониторинга — скрипт, который запускается раз в минуту и пишет в Discord только при смене состояния:
#!/usr/bin/env bash
# /usr/local/bin/healthcheck.sh
set -u
WEBHOOK_URL="${DISCORD_WEBHOOK_URL:?set DISCORD_WEBHOOK_URL}"
TARGET="https://example.com/health"
STATE_FILE="/var/tmp/healthcheck.state"
FAIL_THRESHOLD=3
# при ошибке соединения curl печатает 000
code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 10 "$TARGET")
prev=$(cat "$STATE_FILE" 2>/dev/null || echo "up:0")
prev_status=${prev%%:*}
fails=${prev##*:}
if [[ "$code" == "200" ]]; then
status=up; fails=0
else
status=down; fails=$((fails + 1))
# порог ещё не набран: оставляем прежнее состояние, молчим
[[ $fails -lt $FAIL_THRESHOLD ]] && status=$prev_status
fi
echo "$status:$fails" > "$STATE_FILE"
[[ "$status" == "$prev_status" ]] && exit 0
if [[ "$status" == "down" ]]; then
color=15548997; title="🔴 $TARGET упал"
else
color=5763719; title="🟢 $TARGET снова доступен"
fi
now=$(date -u +%Y-%m-%dT%H:%M:%SZ)
curl -s -o /dev/null -w 'discord: %{http_code}\n' --max-time 10 \
-H "Content-Type: application/json" \
-d @- "$WEBHOOK_URL" <<EOF
{
"embeds": [{
"title": "$title",
"color": $color,
"fields": [
{"name": "HTTP-статус", "value": "$code", "inline": true},
{"name": "Откуда проверяли", "value": "$(hostname)", "inline": true}
],
"timestamp": "$now"
}]
}
EOF
В файле состояния лежит up:0 или down:N. Три не-200 ответа подряд переводят его в down и отправляют одну красную карточку; первый 200 после этого отправляет одну зелёную; всё между ними — тишина. Ставится через chmod +x и запись в crontab:
DISCORD_WEBHOOK_URL=https://discord.com/api/webhooks/YOUR_ID/YOUR_TOKEN
* * * * * /usr/local/bin/healthcheck.sh >> /var/log/healthcheck.log 2>&1
Чтобы восстановление обновляло красную карточку, а не добавляло зелёную рядом, отправьте DOWN-сообщение с ?wait=true, сохраните id из ответа в файл состояния и сделайте PATCH на /messages/{id}, когда сервис вернётся (редактирование и удаление сообщений вебхука).
Цветные embed для up и down
Держите палитру крошечной и никогда не меняйте, что какой цвет значит:
| Состояние | Цвет | Значение color |
|---|---|---|
| Down, firing | красный #ED4245 | 15548997 |
| Up, resolved | зелёный #57F287 | 5763719 |
| Деградация, warning | жёлтый #FEE75C | 16705372 |
| Обслуживание, info | blurple #5865F2 | 5793266 |
Правила, которые работают для любого инструмента:
color— десятичное целое. Hex-строка вроде"#ED4245"отклоняется с 400.- Дублируйте состояние в заголовке: push-уведомление на телефоне показывает только текст, и не все различают красный с зелёным.
- Передавайте
timestampв ISO 8601 по UTC — Discord покажет его в часовом поясе читателя. - Когда собираете payload сами, держитесь лимитов embed (256 символов на заголовок, 4096 на описание, 25 полей); Grafana и Alertmanager обрежут за вас, bash-скрипт — нет.
- Ещё десятичные значения — в гайде по цветам embed.
Как не устроить шторм алертов
Канал, который стреляет без остановки, замьютят, а замьюченный канал хуже, чем никакого.
- Никогда не алертить по одной упавшей проверке. Retries в Uptime Kuma,
for:в правилах Prometheus, pending period в Grafana,FAIL_THRESHOLDв скрипте. - Группировать. Одно сообщение со списком из двенадцати хостов лучше двенадцати сообщений; для этого и нужны
group_byиgroup_wait. - Повторять раз в часы, а не в минуты.
repeat_interval: 4hдля warning,1hдля critical. - Подавлять. Inhibit-правило выше глушит warning, пока горит critical с теми же лейблами, — чтобы упавший хост не рапортовал заодно о двадцати упавших сервисах.
- Слать resolved в том же стиле. Зелёная карточка под каждой красной превращает канал в пары «упало — поднялось».
- Разводить severity на два вебхука. Критичное — в канал, который нельзя замьютить; информационное — в тот, который можно.
- Уважать rate limit. Пятьдесят мониторов, переключившихся разом, — это пятьдесят POST в одну секунду, и на часть из них Discord ответит 429. Повторяет ли инструмент отправку — зависит от инструмента; ваши скрипты обязаны соблюдать
retry_after(rate limits вебхуков).
Частые ошибки
{"message":"Unknown Webhook","code":10015} на каждой отправке. URL обрезан (токены длинные, их легко потерять при вставке) или вебхук удалён. Создайте заново и обновите настройки инструмента.
Кнопка Test работает, а реальные алерты не приходят. Уведомление не привязано к монитору (Uptime Kuma), ни одна политика не ведёт на contact point (Grafana), receiver не упомянут в route (Alertmanager) или cron не получил переменную окружения (скрипт). Тестовый путь обходит все четыре проверки.
400 Bad Request от самописного payload. Неэкранированная кавычка или перенос строки в переменной, hex-строка вместо числа в color или поле сверх лимита. Проверьте через jq . или собирайте payload через jq -n --arg; полный список — в статье про ошибки вебхуков.
Alertmanager не стартует из-за неизвестного поля discord_configs. Бинарник старше 0.25. Обновитесь или временно вернитесь к webhook_configs с прокси.
429 Too Many Requests во время инцидента. Слишком много мониторов сработали в одно окно. Группируйте, поднимайте порог retries, соблюдайте retry_after.
Упоминание роли отображается текстом, а не пингом. Неверный id роли или роль с другого сервера. Скопируйте id в режиме разработчика (правый клик по роли → «Копировать ID роли»).
FAQ
Нужен ли Uptime Kuma бот Discord для отправки алертов?
Нет. Типу уведомления Discord нужен только URL вебхука; бот понадобится лишь для того, что вебхук не умеет, — например, для интерактивной кнопки «принял в работу».
Какая версия Alertmanager поддерживает discord_configs?
Alertmanager 0.25.0 и новее. Более старые версии отклоняют поле при загрузке конфига; обновитесь или заверните через generic webhook receiver и небольшой прокси.
Можно ли отправлять алерты Grafana или Alertmanager в тред?
Да. Оба инструмента делают POST ровно на тот URL, который вы указали, так что допишите ?thread_id=<id существующего треда> к URL вебхука. Форум-каналам нужен thread_name в теле запроса, а эти инструменты его не ставят.
Как перестать получать сообщение каждую минуту, пока сервис лежит?
Алертите по смене состояния, а не по каждой проверке. Uptime Kuma по умолчанию шлёт один DOWN и один UP; в Grafana и Alertmanager ставьте repeat_interval в часах; в cron-скрипте храните последнее состояние в файле и пишите только когда оно изменилось.
Что дальше
Начните с инструмента, который у вас уже крутится, ограничьте палитру красным, зелёным и жёлтым и настройте группировку до первого настоящего инцидента, а не после. Если нужна карточка красивее дефолтной — соберите JSON в конструкторе Discord Webhook и вставьте в скрипт.
Похожие статьи:
- Уведомления через Discord Webhook для автоматизации — паттерны для деплоев, бэкапов и CI.
- Ошибки Discord Webhook и как их чинить — что значит каждый 4xx-ответ.
- Rate limits Discord Webhook — как устроен 429 и как правильно выдерживать паузу перед повтором.