Мониторинг: Prometheus + Grafana¶
Библиотечный backend отдаёт метрики Prometheus на GET /metrics (защищён токеном METRICS_TOKEN).
Что собирается¶
| Метрика | Описание |
|---|---|
http_requests_total |
Число HTTP-запросов (method, route, status_class) |
http_errors_total |
Ответы 4xx/5xx |
http_request_duration_ms |
Гистограмма латентности |
library_outbox_pending_events |
Необработанные события outbox (очередь бронирований) |
library_redis_up |
1 = Redis OK, 0 = down, -1 = не настроен |
library_redis_latency_ms |
Пинг Redis, мс (-1 если недоступен) |
library_database_up |
1 = PostgreSQL OK, 0 = down |
library_database_latency_ms |
Пинг БД, мс (-1 если недоступна) |
process_*, nodejs_* |
CPU, память, event loop Node.js (prom-client) |
Готовый дашборд Library System Overview (v2) — секции:
- Overview — Database, Redis, Outbox, Error rate %, DB latency, Node memory
- HTTP traffic — RPS, ошибки (4xx/5xx), error rate %, latency p50/p95/p99
- Infrastructure — outbox backlog, DB/Redis latency, Node CPU/memory
- Top routes — топ маршрутов по ошибкам и по RPS
Файл: monitoring/grafana/provisioning/dashboards/json/library-overview.json.
Алерты: monitoring/alerts.yml (Prometheus) и monitoring/grafana/provisioning/alerting/rules.yaml (Grafana).
Предварительные требования¶
В /opt/library_system/.env обязательно:
METRICS_TOKEN=<длинный_случайный_токен>
Проверка с хоста:
cd /opt/library_system
TOKEN=$(grep '^METRICS_TOKEN=' .env | cut -d= -f2-)
curl -s -o /dev/null -w "%{http_code}\n" \
-H "Authorization: Bearer $TOKEN" \
http://127.0.0.1:3001/metrics
Ожидается 200 и текст в формате Prometheus (# HELP http_requests_total ...).
Без METRICS_TOKEN эндпоинт возвращает 404.
Вариант A: У вас уже есть Grafana и Prometheus на сервере¶
Типичная ситуация: контейнеры grafana и prometheus на портах 3000 и 9090 (как на mail).
Шаг 1. Подключить контейнеры к сети библиотеки¶
Чтобы Prometheus видел backend:3001, а Grafana — prometheus:9090:
cd /opt/library_system
# имя сети смотрите так:
docker network ls | grep library
# обычно library_system_library-network
docker network connect library_system_library-network prometheus
docker network connect library_system_library-network grafana
Шаг 2. Настроить scrape в Prometheus¶
Найдите, где лежит конфиг:
docker inspect prometheus --format '{{range .Mounts}}{{.Source}} -> {{.Destination}}{{"\n"}}{{end}}'
Откройте prometheus.yml на хосте и добавьте в scrape_configs (пример — monitoring/prometheus-host-scrape.example.yml):
- job_name: library-backend
scrape_interval: 15s
metrics_path: /metrics
static_configs:
- targets: ['backend:3001']
labels:
service: library-backend
authorization:
type: Bearer
credentials: 'ВАШ_METRICS_TOKEN_ИЗ_.env'
Частая ошибка: target
library-backend:3001даётno such host. Вdocker-compose.ymlсервис называетсяbackend, DNS в сети —backend:3001. Проверка:docker exec prometheus wget -qO- --header="Authorization: Bearer $TOKEN" http://backend:3001/metrics | head.
Если не подключали сеть и backend только на 127.0.0.1:3001 хоста:
static_configs:
- targets: ['host.docker.internal:3001']
На Linux при старте Prometheus добавьте: --add-host=host.docker.internal:host-gateway
или используйте IP шлюза Docker: 172.17.0.1:3001.
Перезагрузка конфига без рестарта:
curl -X POST http://127.0.0.1:9090/-/reload
(нужен флаг --web.enable-lifecycle при запуске Prometheus)
Или перезапуск контейнера:
docker restart prometheus
Шаг 3. Проверить target¶
Откройте: http://ВАШ_СЕРВЕР:9090/targets
Job library-backend должен быть UP (зелёный).
Если DOWN — смотрите Error: чаще всего 401 (неверный токен) или connection refused (сеть/порт).
# диагностика из контейнера prometheus
docker exec prometheus wget -qO- \
--header="Authorization: Bearer $TOKEN" \
http://backend:3001/metrics | head
Шаг 4. Datasource в Grafana¶
- Откройте Grafana:
http://ВАШ_СЕРВЕР:3000 - Connections → Data sources → Add data source → Prometheus
- URL:
- если Grafana в сети
library-network:http://prometheus:9090 - иначе:
http://127.0.0.1:9090 - Save & test — должно быть зелёное «Successfully queried».
Шаг 5. Импорт дашборда¶
- Dashboards → New → Import
- Нажмите Upload JSON file (перетащите файл с ПК) — не вставляйте путь к файлу в поле «Find and import dashboards at grafana.com» (там нужен числовой ID с grafana.com).
- Файл:
monitoring/grafana/provisioning/dashboards/json/library-overview.jsonиз репозитория (скачайте на ПК черезscpили скопируйте содержимое в блок Import via dashboard JSON model). - Import (или Dashboard settings → JSON Model → Save для обновления уже импортированного)
После обновления репозитория переимпортируйте JSON или нажмите Overwrite при импорте с тем же uid
library-overview.
Дашборд покажет: - Статусы Database / Redis / Outbox / Error rate % - HTTP RPS, ошибки 4xx/5xx, latency p50/p95/p99 - Outbox backlog, DB и Redis latency - Node CPU и memory - Топ маршрутов по ошибкам и RPS
Шаг 6. Алерты (рекомендуется)¶
Prometheus на сервере (/opt/library_system/prometheus.yml):
- Смонтируйте правила в контейнер (добавьте volume при
docker runили пересоздайте контейнер):
-v /opt/library_system/monitoring/alerts.yml:/etc/prometheus/alerts.yml:ro
- В
prometheus.ymlдобавьте:
global:
evaluation_interval: 15s
rule_files:
- /etc/prometheus/alerts.yml
-
Перезапустите Prometheus:
docker restart prometheus -
Проверка:
http://СЕРВЕР:9090/alerts— правила в состоянии Inactive (норма) или Pending/Firing.
Правила в monitoring/alerts.yml:
| Алерт | Условие |
|---|---|
| DatabaseUnavailable | БД недоступна 1 мин |
| OutboxBacklogHigh | outbox > 50, 5 мин |
| RedisUnavailable | Redis down, 2 мин |
| HighHttpErrorRate | > 0.05 err/s, 5 мин |
| HighHttpErrorRatePercent | > 5% ошибок, 5 мин |
| HighNodeMemory | Node > 512 MB, 10 мин |
| DatabaseSlow | DB ping > 500 ms, 5 мин |
| SlowHttpResponses | p95 > 2s, 10 мин |
Grafana Alerting: Alerting → Alert rules → Import или вручную по выражениям из таблицы выше.
Уведомления в Telegram (встроенный profile):
TELEGRAM_BOT_TOKEN=...
TELEGRAM_CHAT_ID=...
Email:
GF_SMTP_ENABLED=true
GF_SMTP_HOST=smtp.example.com:587
GF_SMTP_USER=...
GF_SMTP_PASSWORD=...
ALERT_EMAIL_TO=ops@example.com
Вариант B: Встроенный monitoring profile (из docker-compose)¶
Отдельные контейнеры library-prometheus и library-grafana, порты только на localhost.
1. Переменные в .env¶
METRICS_TOKEN=<токен>
GRAFANA_ADMIN_PASSWORD=<надёжный_пароль>
# опционально:
GRAFANA_ROOT_URL=http://127.0.0.1:3000
TELEGRAM_BOT_TOKEN=
TELEGRAM_CHAT_ID=
ALERT_EMAIL_TO=
2. Запуск¶
cd /opt/library_system
docker compose --profile monitoring up -d prometheus grafana
Контейнеры: library-prometheus, library-grafana на 127.0.0.1:9090 и 127.0.0.1:3000.
Конфликт портов: если уже работают
prometheusиgrafanaна 9090/3000, остановите их или не используйте profile — см. вариант A.
3. Доступ с вашего ПК (SSH-туннель)¶
ssh -L 9090:127.0.0.1:9090 -L 3000:127.0.0.1:3000 root@mail
- Prometheus: http://127.0.0.1:9090
- Grafana: http://127.0.0.1:3000 (логин
admin, пароль изGRAFANA_ADMIN_PASSWORD)
Дашборд Library System Overview появится в папке Library автоматически.
4. Публикация Grafana наружу (опционально)¶
Рекомендуется не открывать :3000 в интернет. Если нужно:
- отдельный поддомен за nginx + basic auth + HTTPS
- или только VPN / SSH-туннель
Вариант C: Несколько реплик backend¶
При docker compose -f docker-compose.yml -f docker-compose.scale.yml up -d --scale backend=2:
PROMETHEUS_BACKEND_DNS_NAME=backend
Prometheus (profile monitoring) использует DNS SD Docker и собирает метрики со всех реплик.
Частые проблемы¶
| Симптом | Причина | Решение |
|---|---|---|
| Target DOWN, 401 | Неверный METRICS_TOKEN |
Синхронизировать токен в .env и prometheus.yml |
Target DOWN, no such host |
Неверное имя target (library-backend вместо backend) |
В prometheus.yml: targets: ['backend:3001'] |
| Target DOWN, connection refused | Prometheus не в сети library-network |
docker network connect ... |
/metrics 404 |
METRICS_TOKEN не задан в backend |
Добавить в .env, docker compose up -d backend |
| Grafana «No data» | Неверный URL datasource | http://prometheus:9090 или 127.0.0.1:9090 |
| Outbox pending растёт | outbox-worker не работает |
docker compose ps outbox-worker, REDIS_URL |
library_redis_up = 0 |
Redis недоступен | docker compose ps redis, REDIS_URL=redis://redis:6379 |
Полезные PromQL-запросы¶
# RPS всего API
sum(rate(http_requests_total[5m]))
# Ошибки в секунду
sum(rate(http_errors_total[5m]))
# p95 латентность
histogram_quantile(0.95, sum(rate(http_request_duration_ms_bucket[5m])) by (le))
# Топ маршрутов по ошибкам
topk(10, sum by (route) (rate(http_errors_total[15m])))
# Outbox backlog
max(library_outbox_pending_events)
Ссылки в репозитории¶
| Файл | Назначение |
|---|---|
monitoring/prometheus.yml.template |
Scrape через Docker DNS (backend:3001) |
monitoring/prometheus-host-scrape.example.yml |
Пример для внешнего Prometheus |
monitoring/alerts.yml |
Правила Prometheus |
monitoring/grafana/provisioning/ |
Datasource, дашборд, алерты Grafana |
docker-compose.yml (profile monitoring) |
Сервисы prometheus + grafana |
См. также: DEPLOYMENT.md, DOCKER.md.