From 93e9d9fed092689d6ec697643ddb2608ed37b3d5 Mon Sep 17 00:00:00 2001 From: emelinda Date: Wed, 22 Jul 2026 14:51:41 +0300 Subject: [PATCH] Add Nginx reverse proxy, infrastructure services (Postgres, Redis, RabbitMQ, MinIO), and application setup to `docker-compose.yaml` with updated `.env.example` and Nginx configuration --- .env.example | 17 ++++ docker-compose.yaml | 191 ++++++++++++++++++++++++++++++++++++++++++++ nginx/nginx.conf | 81 +++++++++++++++++++ 3 files changed, 289 insertions(+) create mode 100644 nginx/nginx.conf diff --git a/.env.example b/.env.example index 53852d8..559795b 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,20 @@ K3S_TOKEN=gVadzB0OtWGDAM9rmlZvHiwfITsP8bxo # Внешний адрес (IP или домен), по которому к kube-apiserver обращаются извне. # Попадёт в TLS-сертификат (--tls-san). Без него внешний kubectl упадёт на x509. K3S_API_HOST=10.0.0.10 + +# --- Инфраструктура для apps/django (sarex-backend) --- +# Должны совпадать со значениями, которые Django получает в k3s (Vault/Secret). +SAREX_POSTGRES_DB=sarex_db +SAREX_POSTGRES_USER=sarex +SAREX_POSTGRES_PASSWORD=sarex +SAREX_RABBITMQ_VHOST=api +SAREX_RABBITMQ_USER=rabbit +SAREX_RABBITMQ_PASSWORD=rabbit +SAREX_MINIO_ROOT_USER=minioadmin +SAREX_MINIO_ROOT_PASSWORD=minioadmin +SAREX_MINIO_BUCKET=sarex-media-storage +SAREX_MINIO_REGION=us-east-1 + +# Образы приложения (приватный реестр cr.yandex — нужен docker login) +SAREX_BACKEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/sarex-backend-dev:latest +SAREX_FRONTEND_IMAGE=cr.yandex/crp3ccidau046kdj8g9q/sarex-frontend-dev:latest diff --git a/docker-compose.yaml b/docker-compose.yaml index 3a721b0..697b67a 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -83,7 +83,198 @@ services: retries: 12 start_period: 20s + # --------------------------------------------------------------------------- + # Инфраструктурные зависимости apps/django (sarex-backend). + # Django деплоится в k3s и ходит сюда — про связность k3s→compose см. README. + # Креды/версии взяты из sarex-backend/docker-compose.yaml и apps/django/.env.example. + # --------------------------------------------------------------------------- + postgres: + image: postgres:12-alpine + container_name: postgres + restart: unless-stopped + environment: + POSTGRES_DB: ${SAREX_POSTGRES_DB:-sarex_db} + POSTGRES_USER: ${SAREX_POSTGRES_USER:-sarex} + POSTGRES_PASSWORD: ${SAREX_POSTGRES_PASSWORD:-sarex} + ports: + - "5432:5432" + volumes: + - sarex-postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U ${SAREX_POSTGRES_USER:-sarex} -d ${SAREX_POSTGRES_DB:-sarex_db}"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 10s + + redis: + image: redis:7-alpine + container_name: redis + restart: unless-stopped + command: ["redis-server", "--save", "60", "1", "--loglevel", "warning"] + ports: + - "6379:6379" + volumes: + - sarex-redis-data:/data + healthcheck: + test: ["CMD", "redis-cli", "ping"] + interval: 10s + timeout: 5s + retries: 12 + start_period: 5s + + rabbitmq: + image: bitnami/rabbitmq:3.11.23 + container_name: rabbitmq + restart: unless-stopped + environment: + RABBITMQ_VHOST: ${SAREX_RABBITMQ_VHOST:-api} + RABBITMQ_USERNAME: ${SAREX_RABBITMQ_USER:-rabbit} + RABBITMQ_PASSWORD: ${SAREX_RABBITMQ_PASSWORD:-rabbit} + RABBITMQ_DISK_FREE_ABSOLUTE_LIMIT: 200MB + ports: + - "5672:5672" # AMQP + - "15672:15672" # management UI + volumes: + - sarex-rabbitmq-data:/bitnami/rabbitmq/mnesia + healthcheck: + test: ["CMD", "rabbitmq-diagnostics", "-q", "ping"] + interval: 15s + timeout: 10s + retries: 12 + start_period: 30s + + minio: + image: minio/minio:latest + container_name: minio + restart: unless-stopped + command: ["server", "/data", "--console-address", ":9001"] + environment: + MINIO_ROOT_USER: ${SAREX_MINIO_ROOT_USER:-minioadmin} + MINIO_ROOT_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin} + ports: + - "9000:9000" # S3 API + - "9001:9001" # web console + volumes: + - sarex-minio-data:/data + + # Одноразовый init: ждёт MinIO и создаёт бакет sarex-media-storage + minio-init: + image: minio/mc:latest + depends_on: + - minio + entrypoint: + - /bin/sh + - -c + - | + until mc alias set local http://minio:9000 "$$MINIO_ROOT_USER" "$$MINIO_ROOT_PASSWORD"; do + echo 'waiting for minio...'; sleep 2; + done + mc mb -p "local/$$MINIO_BUCKET" + echo "bucket $$MINIO_BUCKET ready" + environment: + MINIO_ROOT_USER: ${SAREX_MINIO_ROOT_USER:-minioadmin} + MINIO_ROOT_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin} + MINIO_BUCKET: ${SAREX_MINIO_BUCKET:-sarex-media-storage} + restart: "no" + + # --------------------------------------------------------------------------- + # Приложение sarex (backend + celery + frontend). + # Образы приватные (cr.yandex) — нужен `docker login cr.yandex`. + # Для локальной сборки backend раскомментируй build (репозиторий — соседний). + # --------------------------------------------------------------------------- + backend: + image: ${SAREX_BACKEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/sarex-backend-dev:latest} + # build: + # context: ../../generic/sarex-backend + # dockerfile: Dockerfile + container_name: sarex-backend + restart: unless-stopped + environment: &sarex-backend-env + ALLOWED_HOSTS: "*" + DJANGO_SETTINGS_MODULE: config.settings.production + JWT_PRIVATE_KEY: "JWT" + JWT_PUBLIC_KEY: "JPK" + DJANGO_POSTGRES_HOST: postgres + DJANGO_POSTGRES_DATABASE: ${SAREX_POSTGRES_DB:-sarex_db} + DJANGO_POSTGRES_USER: ${SAREX_POSTGRES_USER:-sarex} + DJANGO_POSTGRES_PASSWORD: ${SAREX_POSTGRES_PASSWORD:-sarex} + DJANGO_REDIS_HOST: redis + DJANGO_RABBIT_HOSTNAME: rabbitmq + DJANGO_RABBIT_USER: ${SAREX_RABBITMQ_USER:-rabbit} + DJANGO_RABBIT_PASS: ${SAREX_RABBITMQ_PASSWORD:-rabbit} + DJANGO_RABBIT_VHOST: ${SAREX_RABBITMQ_VHOST:-api} + # S3 / объектное хранилище → MinIO (сервис minio) + S3_HOST: http://minio:9000 + AWS_S3_ENDPOINT_URL: http://minio:9000 + S3_LOGIN: ${SAREX_MINIO_ROOT_USER:-minioadmin} + S3_PASSWORD: ${SAREX_MINIO_ROOT_PASSWORD:-minioadmin} + S3_BUCKET: ${SAREX_MINIO_BUCKET:-sarex-media-storage} + S3_REGION: ${SAREX_MINIO_REGION:-us-east-1} + tty: true + ports: + - "8000:8000" # HTTP API (uWSGI), migrate выполняется в entrypoint + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + rabbitmq: + condition: service_healthy + minio-init: + condition: service_completed_successfully + + celery: + image: ${SAREX_BACKEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/sarex-backend-dev:latest} + container_name: sarex-celery + restart: unless-stopped + entrypoint: celery -A config worker -l info -E -Q default -n default_worker.%h --concurrency=1 -B + environment: + <<: *sarex-backend-env + depends_on: + postgres: + condition: service_healthy + redis: + condition: service_healthy + rabbitmq: + condition: service_healthy + minio-init: + condition: service_completed_successfully + + frontend: + image: ${SAREX_FRONTEND_IMAGE:-cr.yandex/crp3ccidau046kdj8g9q/sarex-frontend-dev:latest} + container_name: sarex-frontend + restart: unless-stopped + ports: + - "8080:80" # web UI + depends_on: + - backend + + # Верхний reverse-proxy: единая точка входа → backend / frontend / minio + nginx: + image: nginx:1.27-alpine + container_name: sarex-nginx + restart: unless-stopped + ports: + - "9080:80" # 80/443 заняты k3s + volumes: + - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro,z # :z — SELinux label для RedOS + depends_on: + - backend + - frontend + - minio + healthcheck: + test: ["CMD", "wget", "-qO-", "http://localhost/healthz"] + interval: 10s + timeout: 5s + retries: 6 + start_period: 10s + volumes: k3s-server-data: k3s-worker-data: gitea-data: + sarex-postgres-data: + sarex-redis-data: + sarex-rabbitmq-data: + sarex-minio-data: diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..3e95cdb --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,81 @@ +worker_processes auto; +pid /var/run/nginx.pid; + +events { + worker_connections 1024; + use epoll; +} + +http { + include /etc/nginx/mime.types; + default_type application/octet-stream; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 300; + large_client_header_buffers 8 128k; + client_max_body_size 5000M; # крупные загрузки (снимки, облака точек) + + gzip on; + gzip_vary on; + gzip_proxied any; + gzip_comp_level 6; + gzip_types text/plain text/css application/json application/javascript text/xml application/xml; + + access_log /var/log/nginx/access.log; + error_log /var/log/nginx/error.log; + + # корректная поддержка websocket/keep-alive для upstream'ов + map $http_upgrade $connection_upgrade { + default upgrade; + '' close; + } + + upstream backend { server backend:8000; } + upstream frontend { server frontend:80; } + upstream minio_s3 { server minio:9000; } + + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + server { + listen 80; + listen [::]:80; + + # healthcheck самого nginx + location = /healthz { + access_log off; + add_header Content-Type text/plain; + return 200 "ok\n"; + } + + # --- Django backend: REST API + админка --- + location /api/ { + proxy_pass http://backend; + } + location /admin/ { + proxy_pass http://backend; + } + + # --- MinIO: объекты бакета --- + # Путь НЕ переписываем — иначе ломается подпись SigV4. Чтобы медиа + # открывались из браузера, задай backend'у S3_HOST = http://<хост>:9080 + # (сейчас в compose там http://minio:9000, внутренний адрес). + location /sarex-media-storage/ { + proxy_http_version 1.1; + proxy_set_header Connection ""; + proxy_pass http://minio_s3; + } + + # --- Frontend SPA (host-приложение само отдаёт статику и роутинг) --- + location / { + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection $connection_upgrade; + proxy_pass http://frontend; + } + } +}