OpenRouter отдаёт 403 с российских IP (подтверждено вживую). Добавлен sing-box как отдельный сервис (VLESS+WS+TLS до ноды вне РФ) — только для исходящих запросов к OpenRouter из ollama_client.py, остальной трафик (Postgres/RabbitMQ/MinIO/Ollama) идёт напрямую. Реальный конфиг с UUID — только на проде (см. config.json.example), в git не попадает.
193 lines
6.9 KiB
YAML
193 lines
6.9 KiB
YAML
# ═══════════════════════════════════════════════════════════════════════════════
|
||
# ПРОД стек: локально — nginx (static+proxy), api, воркеры, elasticsearch.
|
||
# Удалённо (через .env) — postgres, redis, minio, ollama, rabbitmq.
|
||
# Тот же принцип, что и docker-compose.test.yml (не дублировать общую инфру),
|
||
# но без bind-mount'ов исходников, без --reload, с собранным фронтендом и nginx/TLS.
|
||
# Запуск: docker compose -f docker-compose.prod.yml up -d --build
|
||
# ═══════════════════════════════════════════════════════════════════════════════
|
||
|
||
networks:
|
||
antiplagiator:
|
||
driver: bridge
|
||
|
||
volumes:
|
||
es_prod_data:
|
||
faiss_index_prod:
|
||
qdrant_prod_data:
|
||
prometheus_data:
|
||
grafana_data:
|
||
|
||
x-app-env: &app-env
|
||
env_file: .env
|
||
networks:
|
||
- antiplagiator
|
||
restart: unless-stopped
|
||
|
||
services:
|
||
|
||
# ─── Локальная инфраструктура ──────────────────────────────────────────────
|
||
elasticsearch:
|
||
image: elasticsearch:8.13.0
|
||
container_name: antiplagiator-elasticsearch
|
||
environment:
|
||
- discovery.type=single-node
|
||
- xpack.security.enabled=false
|
||
- xpack.ml.enabled=false
|
||
- ES_JAVA_OPTS=-Xms2g -Xmx2g
|
||
- bootstrap.memory_lock=true
|
||
- cluster.name=antiplagiator-prod
|
||
ulimits:
|
||
memlock:
|
||
soft: -1
|
||
hard: -1
|
||
volumes:
|
||
- es_prod_data:/usr/share/elasticsearch/data
|
||
networks:
|
||
- antiplagiator
|
||
restart: unless-stopped
|
||
healthcheck:
|
||
test: ["CMD-SHELL", "curl -s http://localhost:9200/_cluster/health | grep -qv '\"status\":\"red\"'"]
|
||
interval: 15s
|
||
timeout: 10s
|
||
retries: 10
|
||
start_period: 60s
|
||
|
||
# Qdrant — альтернативный векторный бэкенд (снимает SPOF файлового FAISS).
|
||
# Опционален: поднимается только с профилем и активируется VECTOR_BACKEND=qdrant.
|
||
# docker compose -f docker-compose.prod.yml --profile qdrant up -d qdrant
|
||
# docker compose -f docker-compose.prod.yml exec worker-gpu python -m app.migrate_faiss_to_qdrant
|
||
# Тег сервера при необходимости поднять до версии клиента (qdrant-client 1.19).
|
||
qdrant:
|
||
image: qdrant/qdrant:v1.12.4
|
||
container_name: antiplagiator-qdrant
|
||
profiles: ["qdrant"]
|
||
volumes:
|
||
- qdrant_prod_data:/qdrant/storage
|
||
networks:
|
||
- antiplagiator
|
||
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)
|
||
api:
|
||
build:
|
||
context: ./services/api
|
||
dockerfile: Dockerfile
|
||
container_name: antiplagiator-api
|
||
<<: *app-env
|
||
depends_on:
|
||
elasticsearch:
|
||
condition: service_healthy
|
||
|
||
# SOCKS5-прокси (sing-box → VLESS-нода вне РФ) — OpenRouter недоступен
|
||
# напрямую из России, только для этого и нужен. Остальной трафик
|
||
# worker-gpu (Postgres/RabbitMQ/MinIO/Ollama) идёт напрямую, не через него.
|
||
singbox-proxy:
|
||
image: ghcr.io/sagernet/sing-box:v1.10.0
|
||
container_name: antiplagiator-singbox-proxy
|
||
command: run -c /etc/sing-box/config.json
|
||
volumes:
|
||
- ./infra/singbox/config.json:/etc/sing-box/config.json:ro
|
||
networks:
|
||
- antiplagiator
|
||
restart: unless-stopped
|
||
|
||
worker-gpu:
|
||
build:
|
||
context: ./services/worker-gpu
|
||
dockerfile: Dockerfile
|
||
container_name: antiplagiator-worker-gpu
|
||
<<: *app-env
|
||
volumes:
|
||
- faiss_index_prod:/data/index
|
||
depends_on:
|
||
elasticsearch:
|
||
condition: service_healthy
|
||
singbox-proxy:
|
||
condition: service_started
|
||
|
||
worker-indexer:
|
||
build:
|
||
context: ./services/worker-indexer
|
||
dockerfile: Dockerfile
|
||
container_name: antiplagiator-worker-indexer
|
||
<<: *app-env
|
||
volumes:
|
||
- ./scripts/parsers:/parsers:ro
|
||
depends_on:
|
||
elasticsearch:
|
||
condition: service_healthy
|
||
|
||
worker-notifier:
|
||
build:
|
||
context: ./services/worker-notifier
|
||
dockerfile: Dockerfile
|
||
container_name: antiplagiator-worker-notifier
|
||
<<: *app-env
|
||
|
||
worker-gost:
|
||
build:
|
||
context: ./services/worker-gost
|
||
dockerfile: Dockerfile
|
||
container_name: antiplagiator-worker-gost
|
||
<<: *app-env
|
||
|
||
flower:
|
||
image: mher/flower:2.0
|
||
container_name: antiplagiator-flower
|
||
command: celery --broker=${RABBITMQ_URL} flower --port=5555
|
||
environment:
|
||
CELERY_BROKER_URL: ${RABBITMQ_URL}
|
||
CELERY_RESULT_BACKEND: ${REDIS_URL}
|
||
networks:
|
||
- antiplagiator
|
||
restart: unless-stopped
|
||
# Flower не публикуется наружу напрямую — доступ через ssh-туннель при необходимости
|
||
|
||
# ─── Nginx: собранный фронтенд (static) + proxy /api, /ws → api:8000, TLS ──
|
||
nginx:
|
||
build:
|
||
context: .
|
||
dockerfile: infra/nginx/Dockerfile
|
||
container_name: antiplagiator-nginx
|
||
networks:
|
||
- antiplagiator
|
||
ports:
|
||
- "80:80"
|
||
- "443:443"
|
||
volumes:
|
||
- /etc/letsencrypt:/etc/letsencrypt:ro
|
||
depends_on:
|
||
- api
|
||
restart: unless-stopped
|