Files

16 KiB
Raw Permalink Blame History

LLM-Zabbix

LLM-Zabbix — это связка из двух отдельных Python-проектов:

  • alert-receiver — принимает webhook из Zabbix, валидирует токен и пересылает событие дальше;
  • alert-processor — асинхронно обрабатывает события через Redis queue, делает enrichment, triage, correlation/RCA, remediation и доставку уведомлений.

В текущей схеме Ollama разворачивается отдельно от стека LLM-Zabbix. alert-processor обращается к нему по адресу хоста Docker, например:

LLM_BASE_URL=http://host.docker.internal:11434

Для Linux-хоста это работает при наличии в docker-compose.yml строки:

extra_hosts:
  - "host.docker.internal:host-gateway"

Архитектура

Поток обработки такой:

  1. Zabbix отправляет webhook в alert-receiver.
  2. alert-receiver проверяет WEBHOOK_TOKEN, нормализует payload и пересылает его в alert-processor.
  3. alert-processor-ingest кладет событие в Redis queue и сразу возвращает 202 Accepted.
  4. alert-processor-worker забирает событие из очереди и выполняет:
    • state tracking;
    • suppress / flap / recovery logic;
    • Zabbix API enrichment;
    • LLM triage для low severity;
    • deterministic correlation + LLM correlation fallback;
    • LLM remediation;
    • отправку уведомлений в Matrix / Mail;
    • audit logging.
  5. alert-worker-health показывает состояние worker и очередей.

Структура репозитория

LLM-Zabbix/
├── docker-compose.yml
├── alert-receiver/
│   ├── .env
│   ├── Dockerfile
│   ├── requirements.txt
│   └── app/
│       └── main.py
└── alert-processor/
    ├── .env
    ├── Dockerfile
    ├── requirements.txt
    ├── config/
    │   ├── event_kind_rules.yaml
    │   └── root_cause_map.yaml
    └── app/
        ├── main.py
        ├── worker.py
        └── worker_health.py

Требования

  • Docker Engine / Docker Compose plugin;
  • отдельный Redis в составе compose;
  • отдельно развернутый Ollama;
  • доступ alert-processor к:
    • Zabbix API;
    • Matrix homeserver / MAS;
    • SMTP relay;
    • Ollama API.

Как работает .env

В проекте два отдельных .env файла:

  • alert-receiver/.env
  • alert-processor/.env

Они не взаимозаменяемы: каждый управляет только своим приложением.


alert-receiver/.env

Назначение

Файл управляет входной точкой webhook из Zabbix и пересылкой события в alert-processor.

Что обычно находится в этом .env

Минимальный пример:

APP_NAME=alert-receiver
APP_HOST=0.0.0.0
APP_PORT=8080

WEBHOOK_TOKEN=change_me_webhook_token

FORWARD_ENABLED=true
PROCESSOR_URL=http://alert-processor-ingest:8081/internal/events
INTERNAL_API_TOKEN=change_internal_token
FORWARD_TIMEOUT_SECONDS=10

Если у вас в alert-receiver имена переменных отличаются, ориентируйтесь на фактический config.py этого проекта. По смыслу переменные должны отвечать именно за эти функции.

Назначение переменных

  • APP_NAME — имя сервиса в логах.
  • APP_HOST — адрес bind внутри контейнера.
  • APP_PORT — порт FastAPI/uvicorn внутри контейнера.
  • WEBHOOK_TOKEN — токен, который должен передать Zabbix в webhook. Обязателеен для минимальной настройки.
  • FORWARD_ENABLED — включена ли пересылка событий в alert-processor.
  • PROCESSOR_URL — endpoint ingest-сервиса alert-processor.
  • INTERNAL_API_TOKEN — токен, которым alert-receiver аутентифицируется перед alert-processor. Обязателеен для минимальной настройки.
  • FORWARD_TIMEOUT_SECONDS — timeout ожидания ответа от ingest.

Пример для Docker Compose

APP_NAME=alert-receiver
APP_HOST=0.0.0.0
APP_PORT=8080
WEBHOOK_TOKEN=super_webhook_token
FORWARD_ENABLED=true
PROCESSOR_URL=http://alert-processor-ingest:8081/internal/events
INTERNAL_API_TOKEN=super_internal_token
FORWARD_TIMEOUT_SECONDS=10

alert-processor/.env

Назначение

Файл управляет всей логикой асинхронной обработки: очередь, Redis, Matrix, Mail, Zabbix enrichment, LLM triage/remediation/correlation, audit, correlation YAML.

Ниже — рабочий пример.

APP_NAME=alert-processor
APP_HOST=0.0.0.0
APP_PORT=8081

INTERNAL_API_TOKEN=super_internal_token
REQUIRE_INTERNAL_API_TOKEN=true

REDIS_ENABLED=true
REDIS_URL=redis://redis:6379/0
REDIS_KEY_PREFIX=alert
REDIS_FINGERPRINT_TTL_SECONDS=86400
REDIS_EVENT_TTL_SECONDS=604800

SUPPRESS_ENABLED=true
SUPPRESS_WINDOW_SECONDS=900
SUPPRESS_APPLY_TO_AVERAGE=true

FLAP_ENABLED=true
FLAP_WINDOW_SECONDS=120
FLAP_THRESHOLD=4
FLAP_APPLY_TO_AVERAGE=true

CORRELATION_ENABLED=true
CORRELATION_WINDOW_SECONDS=180
CORRELATION_SUPPRESS_CHILDREN=true
CORRELATION_KIND_RULES_PATH=/app/config/event_kind_rules.yaml
CORRELATION_ROOT_CAUSE_PATH=/app/config/root_cause_map.yaml

MATRIX_ENABLED=true
MATRIX_HOMESERVER_URL=https://mr.example.org
MATRIX_ROOM_ID=!roomid:mr.example.org
MATRIX_ACCESS_TOKEN=initial_access_token
MATRIX_REFRESH_TOKEN=initial_refresh_token
MATRIX_OAUTH_TOKEN_ENDPOINT=https://ms.example.org/oauth2/token
MATRIX_OAUTH_CLIENT_ID=LLMZABBIX01
MATRIX_OAUTH_CLIENT_SECRET=
MATRIX_ACCESS_TOKEN_EXPIRES_IN_SECONDS=300
MATRIX_REFRESH_MARGIN_SECONDS=60
MATRIX_TOKEN_STATE_FILE=/app/.matrix_token_state.json
MATRIX_MESSAGE_TYPE=m.notice
MATRIX_REQUEST_TIMEOUT_SECONDS=10
MATRIX_VERIFY_TLS=true

MAIL_ENABLED=true
MAIL_SMTP_HOST=smtp.example.org
MAIL_SMTP_PORT=587
MAIL_SMTP_USERNAME=monitoring@example.org
MAIL_SMTP_PASSWORD=change_me
MAIL_FROM=monitoring@example.org
MAIL_TO=ops@example.org
MAIL_USE_STARTTLS=true
MAIL_USE_TLS=false
MAIL_TIMEOUT_SECONDS=15
MAIL_SUBJECT_PREFIX=[LLM-Zabbix]

ZABBIX_API_ENABLED=true
ZABBIX_API_URL=https://zb.example.org/api_jsonrpc.php
ZABBIX_API_TOKEN=change_me_zabbix_api_token
ZABBIX_WEB_URL=https://zb.example.org
ZABBIX_API_TIMEOUT_SECONDS=10
ZABBIX_API_VERIFY_TLS=true
ZABBIX_GRAPH_PERIOD_HOURS=1
ZABBIX_GRAPH_TIMEZONE=Europe/Moscow
ZABBIX_ENRICH_ONLY_NOTIFY=true

LLM_ENABLED=true
LLM_BASE_URL=http://host.docker.internal:11434
LLM_MODEL=qwen3.5:4b
LLM_TIMEOUT_SECONDS=45
LLM_VERIFY_TLS=true
LLM_TEMPERATURE=0.1
LLM_MAX_STEPS=4
LLM_MAX_COMMANDS=4

LLM_TRIAGE_ENABLED=true
LLM_TRIAGE_CACHE_TTL_SECONDS=3600

LLM_CORRELATION_ENABLED=true
LLM_CORRELATION_MIN_CONFIDENCE=medium

QUEUE_ENABLED=true
QUEUE_NAME=alert:queue:events
QUEUE_PROCESSING_NAME=alert:queue:processing
QUEUE_DEADLETTER_NAME=alert:queue:deadletter
QUEUE_BLOCK_TIMEOUT_SECONDS=5
QUEUE_MAX_ATTEMPTS=3
QUEUE_DEDUP_TTL_SECONDS=86400
QUEUE_REQUEUE_PROCESSING_ON_STARTUP=true

AUDIT_ENABLED=true
AUDIT_KEY_PREFIX=alert:audit
AUDIT_TTL_SECONDS=604800
AUDIT_MAX_STAGE_RECORDS=200

Блоки переменных и из назначение

Общие

  • APP_NAME, APP_HOST, APP_PORT — базовые параметры FastAPI ingest.
  • INTERNAL_API_TOKEN — токен для запросов от alert-receiver. Обязателеен для минимальной настройки, должен совпадать с alert-receiver.
  • REQUIRE_INTERNAL_API_TOKEN — обязательность токена.

Redis / state

  • REDIS_URL — подключение к Redis.
  • REDIS_KEY_PREFIX — префикс ключей.
  • REDIS_FINGERPRINT_TTL_SECONDS — TTL fingerprint state.
  • REDIS_EVENT_TTL_SECONDS — TTL снапшотов событий.

Suppress / flap

  • SUPPRESS_* — антиспам по повторяющимся событиям.
  • FLAP_* — подавление флаппинга.

Correlation / RCA

  • CORRELATION_ENABLED — включает корреляцию.
  • CORRELATION_WINDOW_SECONDS — временное окно для поиска связанных событий.
  • CORRELATION_SUPPRESS_CHILDREN — suppress дочерних low/average событий.
  • CORRELATION_KIND_RULES_PATH — YAML классификации event kinds.
  • CORRELATION_ROOT_CAUSE_PATH — YAML root-cause mapping.

Matrix

  • MATRIX_* — доставка уведомлений в Matrix и refresh токенов через MAS.
  • MATRIX_TOKEN_STATE_FILE — файл хранения актуальных rotated токенов.

Mail

  • MAIL_* — SMTP-доставка email уведомлений.

Zabbix enrichment

  • ZABBIX_API_* — подключение к Zabbix API.
  • ZABBIX_WEB_URL — базовый URL Zabbix Web UI для ссылок.
  • ZABBIX_GRAPH_* — генерация графиков.
  • ZABBIX_ENRICH_ONLY_NOTIFY — enrich только для реально отправляемых событий.

LLM

  • LLM_BASE_URL — адрес Ollama. В текущей схеме Ollama развернут отдельно и доступен через host.docker.internal.
  • LLM_MODEL — имя локальной модели.
  • LLM_TIMEOUT_SECONDS — timeout запросов к LLM.
  • LLM_TEMPERATURE — temperature для triage/remediation/correlation.
  • LLM_MAX_STEPS, LLM_MAX_COMMANDS — ограничение размера remediation.

LLM triage

  • LLM_TRIAGE_ENABLED — включает triage low-severity событий.
  • LLM_TRIAGE_CACHE_TTL_SECONDS — TTL кэша triage verdicts.

LLM correlation fallback

  • LLM_CORRELATION_ENABLED — включает fallback-корреляцию через LLM, если deterministic correlation не дал результата.
  • LLM_CORRELATION_MIN_CONFIDENCE — минимальная уверенность LLM (low, medium, high).

Queue

  • QUEUE_* — параметры Redis queue и deadletter.

Audit

  • AUDIT_* — аудит обработки и хранение event journal.

YAML для корреляции

Файлы лежат в alert-processor/config/.

event_kind_rules.yaml

Определяет, как событие классифицируется в kind.

Пример:

event_kind_rules:
  - kind: postgresql_unavailable
    trigger_patterns:
      - "postgresql.+unavailable"
      - "postgres.+unavailable"

  - kind: mssql_unavailable
    trigger_patterns:
      - "mssql.+unavailable"
      - "sql server.+unavailable"
    scope_in:
      - "host_os"

root_cause_map.yaml

Определяет, какие kind могут объяснять другие kind.

Пример:

root_cause_map:
  postgresql_unavailable:
    explains:
      - service_unavailable
      - db_connection_error

  mssql_unavailable:
    explains:
      - service_unavailable
      - db_connection_error

После изменения YAML нужно перезапустить worker.


Отдельный Ollama

Ollama в текущей схеме не входит в compose LLM-Zabbix.

Он разворачивается отдельно и должен быть доступен с Docker host на 11434.

Пример compose для Ollama:

services:
  ollama:
    image: ollama/ollama:latest
    container_name: ollama
    restart: unless-stopped
    ports:
      - "11434:11434"
    volumes:
      - ./ollama-data:/root/.ollama

Затем внутри Ollama нужно загрузить модель:

docker exec -it ollama ollama pull qwen3.5:4b

Проверка:

curl http://127.0.0.1:11434/api/tags

Подготовка каталогов

Перед первым запуском из корня репозитория:

mkdir -p alert-processor/config
mkdir -p alert-processor/.graph_images
mkdir -p redis-data

touch alert-processor/.matrix_token_state.json

Если YAML уже лежат в репозитории, просто убедитесь, что файлы на месте:

  • alert-processor/config/event_kind_rules.yaml
  • alert-processor/config/root_cause_map.yaml

Запуск через Docker Compose

Из корня репозитория:

docker compose up -d --build

Проверить контейнеры:

docker compose ps

Посмотреть логи worker:

docker compose logs -f alert-processor-worker

Health-check и полезные endpoints

Receiver

curl http://127.0.0.1:8080/health

Processor ingest

curl http://127.0.0.1:8081/health

Worker health

curl http://127.0.0.1:8082/health

Audit recent

curl http://127.0.0.1:8081/audit/recent?limit=5

Audit by correlation_id

curl http://127.0.0.1:8081/audit/events/<correlation_id>

Audit by event_id

curl http://127.0.0.1:8081/audit/by-event/<event_id>

Как подключить Zabbix

В Zabbix Media Type / webhook используйте URL alert-receiver, а не alert-processor.

Пример макросов:

{$ALERT_RECEIVER_URL}   = http://<ip-or-dns>:8080/webhook/zabbix
{$ALERT_RECEIVER_TOKEN} = <WEBHOOK_TOKEN>

То есть Zabbix отправляет только в:

http://<host>:8080/webhook/zabbix

Дальше маршрутизация происходит внутри LLM-Zabbix автоматически.


Пример безопасной последовательности запуска

  1. Поднять отдельно Ollama с загруженной языковой моделью.
  2. Проверить, что хост отвечает на http://127.0.0.1:11434/api/tags.
  3. Заполнить alert-receiver/.env.
  4. Заполнить alert-processor/.env.
  5. Убедиться, что:
    • LLM_BASE_URL=http://host.docker.internal:11434
    • в compose есть extra_hosts: ["host.docker.internal:host-gateway"]
  6. Запустить:
    docker compose up -d --build
    
  7. Проверить 8080/health, 8081/health, 8082/health.
  8. Отправить тестовый alert.
  9. Проверить audit/recent.
  10. Только потом переключать production webhook Zabbix.

Что хранить в backup

Минимально:

  • alert-receiver/.env
  • alert-processor/.env
  • alert-processor/config/*.yaml
  • alert-processor/.matrix_token_state.json
  • redis-data/
  • .graph_images/ — по желанию

Примечания

  • alert-processor-ingest быстро отвечает 202, вся тяжелая логика выполняется в worker.
  • Если LLM correlation в audit имеет статус skipped, это значит, что fallback вызвался, но его результат не был применен.
  • Если correlation_source=deterministic, значит LLM fallback не понадобился.
  • Для Linux доступ к отдельно развернутому Ollama из контейнера реализован через:
    • LLM_BASE_URL=http://host.docker.internal:11434
    • extra_hosts: ["host.docker.internal:host-gateway"]
  • При недоступности языковой модели алерты обрабатываются базовым функционалом, но теряется remidiation