Files

535 lines
16 KiB
Markdown
Raw Permalink 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.
# LLM-Zabbix
LLM-Zabbix — это связка из двух отдельных Python-проектов:
- `alert-receiver` — принимает webhook из Zabbix, валидирует токен и пересылает событие дальше;
- `alert-processor` — асинхронно обрабатывает события через Redis queue, делает enrichment, triage, correlation/RCA, remediation и доставку уведомлений.
В текущей схеме **Ollama разворачивается отдельно** от стека LLM-Zabbix. `alert-processor` обращается к нему по адресу хоста Docker, например:
```env
LLM_BASE_URL=http://host.docker.internal:11434
```
Для Linux-хоста это работает при наличии в `docker-compose.yml` строки:
```yaml
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 и очередей.
---
## Структура репозитория
```text
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`
Минимальный пример:
```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
```env
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.
Ниже — рабочий пример.
```env
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`.
Пример:
```yaml
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`.
Пример:
```yaml
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:
```yaml
services:
ollama:
image: ollama/ollama:latest
container_name: ollama
restart: unless-stopped
ports:
- "11434:11434"
volumes:
- ./ollama-data:/root/.ollama
```
Затем внутри Ollama нужно загрузить модель:
```bash
docker exec -it ollama ollama pull qwen3.5:4b
```
Проверка:
```bash
curl http://127.0.0.1:11434/api/tags
```
---
## Подготовка каталогов
Перед первым запуском из корня репозитория:
```bash
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
Из корня репозитория:
```bash
docker compose up -d --build
```
Проверить контейнеры:
```bash
docker compose ps
```
Посмотреть логи worker:
```bash
docker compose logs -f alert-processor-worker
```
---
## Health-check и полезные endpoints
### Receiver
```bash
curl http://127.0.0.1:8080/health
```
### Processor ingest
```bash
curl http://127.0.0.1:8081/health
```
### Worker health
```bash
curl http://127.0.0.1:8082/health
```
### Audit recent
```bash
curl http://127.0.0.1:8081/audit/recent?limit=5
```
### Audit by correlation_id
```bash
curl http://127.0.0.1:8081/audit/events/<correlation_id>
```
### Audit by event_id
```bash
curl http://127.0.0.1:8081/audit/by-event/<event_id>
```
---
## Как подключить Zabbix
В Zabbix Media Type / webhook используйте URL `alert-receiver`, а не `alert-processor`.
Пример макросов:
```text
{$ALERT_RECEIVER_URL} = http://<ip-or-dns>:8080/webhook/zabbix
{$ALERT_RECEIVER_TOKEN} = <WEBHOOK_TOKEN>
```
То есть Zabbix отправляет только в:
```text
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. Запустить:
```bash
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