Привет, хабровчане!
Не так давно я публиковал статью про alertmanager-jira — плагин для интеграции алертов Alertmanager (из Prometheus или VictoriaMetrics) с Jira. В конце той статьи анонсировал, что готовлю аналогичное решение для EvaTeam — отечественного трекера задач, на который мы у себя перешли. Обещал — делаю. Встречайте: alertmanager-evateam.
Уже порядка полугода гоняем в продакшене — полёт нормальный.
Зачем это нужно
Если коротко: когда Alertmanager стреляет алерт, хочется автоматически получать задачу в трекере, а не перекладывать эту работу на дежурного инженера вручную. При разрешении проблемы — задача закрывается и комментируется - описывается причина, решение. Без подобной связки проблемы не отслеживаются комплексно, нет возможности оценивать проблемы на горизонте больше недели.
Jira — понятная история, под неё есть несколько готовых решений (в том числе alertmanager-jira). С EvaTeam ситуация до недавнего времени была хуже: интеграций нет, документации немного. Но мы очень хотели, и спешу поделиться с надеждой что это будет интересно кому-то ещё.
Как это работает
Схема предельно простая:
Prometheus(илиVictoriaMetrics) собирает метрикиAlertmanagerпроверяет настроенные пороги и правила, обнаруживает проблему и формирует алерт. Затем отправляет его в настроенные каналы и плагины.Alertmanagerпоwebhook_configпересылаетJSONс данными алерта наHTTP-endpointalertmanager-evateam.Он, в свою очередь, создаёт задачу в
EvaTeam(или комментирует существующую, если задача уже есть и это настроено).Когда алерт разрешается (
send_resolved: true), плагин это обрабатывает — добавляет комментарий или меняет статус (опять же, если настроено, по умолчанию не закрывается).
Проект реализован на Java + Quarkus с нативной сборкой через GraalVM для скорости выполнения и экономии ресурсов.
Установка и настройка
Docker / Podman
Готовые к использованию образы доступны на Docker Hub: hubbitus/alertmanager-evateam. Собираются автоматически на CI.
Быстрый запуск:
podman run -it --rm --name alertmanager-evateam \ -p 8080:8080 \ hubbitus/alertmanager-evateam:latest
В репозитории есть готовый пример полного стека prometheus + alertmanager + grafana для локального запуска через podman-compose (или docker-compose) — смотрите директорию _DEV.scripts/prometheus-alertmanager-grafana.
Конфигурация
Подключение в Alertmanager
receivers: - name: 'data-evateam' webhook_configs: - url: 'https://alertmanager-evateam.your.domain' send_resolved: true
Управляющие поля eva__
Основная идея: параметры создаваемой задачи задаются прямо в labels и annotations алерта через префикс eva__. Это позволяет гибко настраивать поведение на уровне каждого правила, не трогая конфигурацию плагина.
Пример правила:
- name: DATA rules: - alert: DataTest0 expr: 'promhttp_metric_handler_requests_total > 1' labels: severity: warning eva__field__severity: High annotations: eva__project: data-alerts eva__field__issue_type_name: Task eva__field__cf_env: PROD summary: DataTest0 summary description: | Some description VALUE: {{$value}}
Ключевые поля:
eva__project— проект вEvaTeam, куда создавать задачи (например,data-alerts).eva__field__issue_type_name— тип задачи (например,Task).eva__field__<имя_поля>— любые поля задачи:eva__field__assignee,eva__field__priorityи т.д.eva__identification_field_name— поле для идентификации уже существующей задачи (по умолчаниюcf_alert_id). Рекомендуется создать отдельное строковое поле вEvaTeamи использовать его. Не вдаваясь в подробности, черезtags(аналогlabelsвJira) работает значительно медленнее.eva__identification_field_value— шаблон для вычисления идентификатора (по умолчанию${context.alert.hashCode()}). По этому идентификатору будет искаться имеется ли уже задача для данного алерта (например для дополнения сообщением что проблема ещё актуальна, или автоматического закрытия)eva__bql_to_find_issue_for_update—BQL-запрос (аналогJQLвJira) для поиска существующей задачи при повторном срабатывании алерта.eva__comment_in_present_issues— шаблон комментария к уже существующей задаче.
Чтобы не дублировать общие значения в каждом правиле, удобно использовать alert_relabel_configs:
alerting: alert_relabel_configs: - target_label: eva__project replacement: data-alerts - target_label: eva__field__issue_type_name replacement: Task
Имена полей со спецсимволами
Из-за ограничений схемы Alertmanager и labels, и annotations должны быть валидными идентификаторами. Если нужно передать поле с именем вроде Component/s или Итоговый результат, используется форма с парами:
annotations: eva__field__name__1: 'Component/s' eva__field__value__1: 'DQ-issues+alerts, DevOps+infrastructure' eva__field__name__result: 'Итоговый результат' eva__field__value__result: 'Some result description'
Значение
<n>в пареeva__field__name__<n>/eva__field__value__<n>может быть произвольной строкой — главное, чтобы она совпадала для имени и значения и была уникальной среди остальных пар.
Шаблонизация значений
Значения полей поддерживают шаблоны через объект context. Например, можно подставить severity из labels прямо в тег:
annotations: eva__field__tags: '["severity:${context.field("severity")}"]'
Полный список доступных переменных — в классе AlertContext.
Про API EvaTeam — удобство и подводные камни
Нельзя не сказать пару слов про сам API EvaTeam, потому что здесь есть важная особенность, которая напрямую влияет на то, как нужно подходить к настройке.
Хорошая новость: API весьма гибкий и удобный. Большинство полей принимаются в виде свободных kwargs-параметров (EvaTeam написана на Python) — это позволяет передавать произвольные атрибуты без жёсткой привязки к конкретной схеме. Документации, правда, немного, но с живым API разбираться вполне можно.
Плохая новость: обратная сторона этой гибкости — фактически отсутствует нормальная валидация на этапе биндинга параметров. На стороне клиента нет DTO-объектов, серверная валидация тоже весьма слабая. На практике это означает: если вы допустили опечатку в имени поля или передали несуществующее значение — EvaTeam, как правило, просто проигнорирует это молча, без каких-либо ошибок.
К сожалению, на моей стороне эту проблему надёжно не решить — она на стороне API. Вывод один: всё, что настраивается, необходимо тщательно тестировать перед выводом в продакшен. Убедитесь, что задачи создаются с нужными полями, а не только что плагин «не упал».
Если хотите разрабатывать
Сборка из исходников
./gradlew build java -jar build/quarkus-app/quarkus-run.jar
Для нативной сборки (для запуска без JVM):
./gradlew build -Dquarkus.native.enabled=true \ -Dquarkus.package.jar.enabled=false \ -Dquarkus.native.container-build=true
Запуск тестов
Стоит отметить что писать ПО без тестов уже давно не просто мода, а необходимость. В проекте есть юнит тесты и интеграционные.
Внимание! Мок-объектов для
EvaTeamнет. Для запуска интеграционных тестов нужен живой экземплярEvaTeamс соответствующей конфигурацией окружения. Тут опять же, замечу, это не то чтобы здорво, но система проприетарная, и я пока не вижу хорошего способа поднять на момент тестов реальный инстанс, скажем в качествеtestcontainers. Просто учитывайте это, если решите дорабатывать и предложить пулл-реквесты.
./gradlew test --info
Для нативного режима:
./gradlew testNative --info
Итого
Если вы используете EvaTeam в качестве трекера и хотите замкнуть цикл мониторинга от Prometheus (или VictoriaMetrics) до задачи в трекере — alertmanager-evateam решает эту задачу. Проект в активной эксплуатации, работает стабильно. И если для реализации Alertmanager-jira я сравнивал его с существующим решением jiralert, то полагаю для EvaTeam моё решение пока уникально.
Буду очень рад, если хоть кому-то поможет!
Любой фидбек горячо приветствуется — пишите в комментариях или открывайте issue в репозитории. Если есть пожелания по новым фичам или обнаружили баг — тем более.
