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"
Архитектура
Поток обработки такой:
- Zabbix отправляет webhook в
alert-receiver. alert-receiverпроверяетWEBHOOK_TOKEN, нормализует payload и пересылает его вalert-processor.alert-processor-ingestкладет событие в Redis queue и сразу возвращает202 Accepted.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.
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/.envalert-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_*— 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.yamlalert-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 автоматически.
Пример безопасной последовательности запуска
- Поднять отдельно Ollama с загруженной языковой моделью.
- Проверить, что хост отвечает на
http://127.0.0.1:11434/api/tags. - Заполнить
alert-receiver/.env. - Заполнить
alert-processor/.env. - Убедиться, что:
LLM_BASE_URL=http://host.docker.internal:11434- в compose есть
extra_hosts: ["host.docker.internal:host-gateway"]
- Запустить:
docker compose up -d --build - Проверить
8080/health,8081/health,8082/health. - Отправить тестовый alert.
- Проверить
audit/recent. - Только потом переключать production webhook Zabbix.
Что хранить в backup
Минимально:
alert-receiver/.envalert-processor/.envalert-processor/config/*.yamlalert-processor/.matrix_token_state.jsonredis-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:11434extra_hosts: ["host.docker.internal:host-gateway"]
- При недоступности языковой модели алерты обрабатываются базовым функционалом, но теряется remidiation