feat(obs): наблюдаемость Prometheus + Grafana под профилем observability
Раньше видимости в прод не было — только email-монитор (костыль). Добавлено без нагрузки по умолчанию (профиль не поднимается, пока не попросят): - API: /metrics через prometheus-fastapi-instrumentator (кол-во/латентность запросов по хендлерам); - Prometheus (infra/prometheus/prometheus.yml) скрейпит API и Flower — из Flower приходят метрики Celery (задачи, время, воркеры) вообще без доп. кода; - Grafana с автопровижном источника Prometheus (infra/grafana/provisioning), пароль через GRAFANA_ADMIN_PASSWORD; - docker-compose.prod.yml: сервисы prometheus/grafana под profiles:[observability] + volumes; .env.example и README пополнены. Запуск: docker compose --profile observability up -d prometheus grafana. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -39,3 +39,11 @@ SMTP_TLS_VERIFY=true
|
|||||||
# App
|
# App
|
||||||
APP_URL=https://academic.jze9.ru
|
APP_URL=https://academic.jze9.ru
|
||||||
ENVIRONMENT=development
|
ENVIRONMENT=development
|
||||||
|
|
||||||
|
# Векторный бэкенд (опционально): faiss (по умолчанию) или qdrant. См. README.
|
||||||
|
VECTOR_BACKEND=faiss
|
||||||
|
QDRANT_URL=http://qdrant:6333
|
||||||
|
QDRANT_COLLECTION=documents
|
||||||
|
|
||||||
|
# Наблюдаемость (профиль observability, опционально)
|
||||||
|
GRAFANA_ADMIN_PASSWORD=admin
|
||||||
|
|||||||
14
README.md
14
README.md
@@ -184,6 +184,20 @@ docker compose -f docker-compose.prod.yml exec worker-gpu python -m app.migrate_
|
|||||||
docker compose -f docker-compose.prod.yml up -d worker-gpu
|
docker compose -f docker-compose.prod.yml up -d worker-gpu
|
||||||
```
|
```
|
||||||
|
|
||||||
|
## Наблюдаемость (Prometheus + Grafana)
|
||||||
|
|
||||||
|
Опционально (профиль `observability`, по умолчанию не поднимается):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose -f docker-compose.prod.yml --profile observability up -d prometheus grafana
|
||||||
|
```
|
||||||
|
|
||||||
|
- API отдаёт HTTP-метрики на `/metrics` (кол-во и латентность запросов по хендлерам).
|
||||||
|
- Prometheus (`infra/prometheus/prometheus.yml`) скрейпит API и **Flower** — из
|
||||||
|
Flower приходят метрики Celery (задачи, время выполнения, воркеры) без доп. кода.
|
||||||
|
- Grafana с автоподключённым источником Prometheus (`infra/grafana/provisioning/`);
|
||||||
|
пароль admin — через `GRAFANA_ADMIN_PASSWORD` в `.env` (по умолчанию `admin`).
|
||||||
|
|
||||||
## Тестирование и качество кода
|
## Тестирование и качество кода
|
||||||
|
|
||||||
Перед деплоем CI (`.gitea/workflows/deploy.yml`, job `test`) прогоняет два гейта,
|
Перед деплоем CI (`.gitea/workflows/deploy.yml`, job `test`) прогоняет два гейта,
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ volumes:
|
|||||||
es_prod_data:
|
es_prod_data:
|
||||||
faiss_index_prod:
|
faiss_index_prod:
|
||||||
qdrant_prod_data:
|
qdrant_prod_data:
|
||||||
|
prometheus_data:
|
||||||
|
grafana_data:
|
||||||
|
|
||||||
x-app-env: &app-env
|
x-app-env: &app-env
|
||||||
env_file: .env
|
env_file: .env
|
||||||
@@ -65,6 +67,36 @@ services:
|
|||||||
- antiplagiator
|
- antiplagiator
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
|
|
||||||
|
# ─── Наблюдаемость (опционально; профиль observability) ────────────────────
|
||||||
|
# docker compose -f docker-compose.prod.yml --profile observability up -d prometheus grafana
|
||||||
|
# Prometheus скрейпит api:/metrics и flower:/metrics (метрики Celery).
|
||||||
|
prometheus:
|
||||||
|
image: prom/prometheus:v2.54.1
|
||||||
|
container_name: antiplagiator-prometheus
|
||||||
|
profiles: ["observability"]
|
||||||
|
volumes:
|
||||||
|
- ./infra/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml:ro
|
||||||
|
- prometheus_data:/prometheus
|
||||||
|
networks:
|
||||||
|
- antiplagiator
|
||||||
|
restart: unless-stopped
|
||||||
|
|
||||||
|
grafana:
|
||||||
|
image: grafana/grafana:11.2.0
|
||||||
|
container_name: antiplagiator-grafana
|
||||||
|
profiles: ["observability"]
|
||||||
|
environment:
|
||||||
|
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD:-admin}
|
||||||
|
- GF_USERS_ALLOW_SIGN_UP=false
|
||||||
|
volumes:
|
||||||
|
- ./infra/grafana/provisioning:/etc/grafana/provisioning:ro
|
||||||
|
- grafana_data:/var/lib/grafana
|
||||||
|
networks:
|
||||||
|
- antiplagiator
|
||||||
|
restart: unless-stopped
|
||||||
|
depends_on:
|
||||||
|
- prometheus
|
||||||
|
|
||||||
# ─── Приложение ────────────────────────────────────────────────────────────
|
# ─── Приложение ────────────────────────────────────────────────────────────
|
||||||
# RabbitMQ вынесен на отдельный сервер 192.168.20.82 (см. RABBITMQ_URL в .env)
|
# RabbitMQ вынесен на отдельный сервер 192.168.20.82 (см. RABBITMQ_URL в .env)
|
||||||
api:
|
api:
|
||||||
|
|||||||
10
infra/grafana/provisioning/datasources/prometheus.yml
Normal file
10
infra/grafana/provisioning/datasources/prometheus.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Автопровижн источника данных Grafana → Prometheus (профиль observability).
|
||||||
|
apiVersion: 1
|
||||||
|
|
||||||
|
datasources:
|
||||||
|
- name: Prometheus
|
||||||
|
type: prometheus
|
||||||
|
access: proxy
|
||||||
|
url: http://prometheus:9090
|
||||||
|
isDefault: true
|
||||||
|
editable: false
|
||||||
20
infra/prometheus/prometheus.yml
Normal file
20
infra/prometheus/prometheus.yml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
# Prometheus scrape-конфиг (профиль observability в docker-compose.prod.yml).
|
||||||
|
# Скрейпит HTTP-метрики API и Celery-метрики из Flower (Flower 2.0 отдаёт их сам).
|
||||||
|
global:
|
||||||
|
scrape_interval: 30s
|
||||||
|
evaluation_interval: 30s
|
||||||
|
|
||||||
|
scrape_configs:
|
||||||
|
- job_name: prometheus
|
||||||
|
static_configs:
|
||||||
|
- targets: ["localhost:9090"]
|
||||||
|
|
||||||
|
- job_name: api
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: ["api:8000"]
|
||||||
|
|
||||||
|
- job_name: flower # метрики Celery: задачи, время выполнения, воркеры
|
||||||
|
metrics_path: /metrics
|
||||||
|
static_configs:
|
||||||
|
- targets: ["flower:5555"]
|
||||||
@@ -7,6 +7,7 @@ from contextlib import asynccontextmanager
|
|||||||
from fastapi import Depends, FastAPI, WebSocket, WebSocketDisconnect
|
from fastapi import Depends, FastAPI, WebSocket, WebSocketDisconnect
|
||||||
from fastapi.middleware.cors import CORSMiddleware
|
from fastapi.middleware.cors import CORSMiddleware
|
||||||
from fastapi.responses import JSONResponse
|
from fastapi.responses import JSONResponse
|
||||||
|
from prometheus_fastapi_instrumentator import Instrumentator
|
||||||
|
|
||||||
from app.api import admin, auth, documents, reports, search, tasks
|
from app.api import admin, auth, documents, reports, search, tasks
|
||||||
from app.config import settings
|
from app.config import settings
|
||||||
@@ -80,6 +81,11 @@ app.include_router(documents.router, prefix="/api")
|
|||||||
app.include_router(reports.router, prefix="/api")
|
app.include_router(reports.router, prefix="/api")
|
||||||
app.include_router(admin.router, prefix="/api")
|
app.include_router(admin.router, prefix="/api")
|
||||||
|
|
||||||
|
# ─── Метрики Prometheus ───────────────────────────────────────────────────────
|
||||||
|
# HTTP-метрики (кол-во/латентность запросов по хендлерам) на /metrics.
|
||||||
|
# Prometheus скрейпит их (см. infra/prometheus/prometheus.yml, профиль observability).
|
||||||
|
Instrumentator().instrument(app).expose(app, endpoint="/metrics", include_in_schema=False)
|
||||||
|
|
||||||
|
|
||||||
# ─── WebSocket ────────────────────────────────────────────────────────────────
|
# ─── WebSocket ────────────────────────────────────────────────────────────────
|
||||||
@app.websocket("/ws/tasks/{public_id}")
|
@app.websocket("/ws/tasks/{public_id}")
|
||||||
|
|||||||
@@ -16,3 +16,4 @@ minio==7.2.7
|
|||||||
httpx==0.27.0
|
httpx==0.27.0
|
||||||
aiofiles==23.2.1
|
aiofiles==23.2.1
|
||||||
websockets==12.0
|
websockets==12.0
|
||||||
|
prometheus-fastapi-instrumentator==7.0.0 # /metrics для Prometheus (профиль observability)
|
||||||
|
|||||||
Reference in New Issue
Block a user