# Докер-сборка UMNI Ecosystem Развёртывание в Docker: БД (PostgreSQL), бэкенд (FastAPI) и фронтенд (Vue → nginx). Документ описывает локальную сборку и запуск. Публикация образов — в [DOCKER_PUBLISH.md](DOCKER_PUBLISH.md). ## Архитектура ``` Браузер ──> nginx (frontend, порт 80) │ /api/* → backend:8000/* (с префикса срезается /api) └ / → статика SPA backend (8000) ──> postgres (5432) ``` - `backend` доступен наружу **только** через nginx (`expose: 8000`), отдельного хост-порта нет. - REST-роуты живут без префикса `/api` (auth, cameras, storages, ...), фронтенд обращается по `/api/...`, nginx срезает префикс. ## Быстрый старт (сборка из исходников) Требуется: Docker Desktop (или Docker Engine с Compose v2). ```powershell cd C:\Develop\UMNI\Ecosystem # 1. Базовые значения для docker compose (имя БД, порт, уровень логов и т.п.) Copy-Item .env.example .env # 2. Конфигурация backend — положите/поправьте env_config\.env # (уже присутствует; при желании смените пароли). ВАЖНО: значения DB_* должны # совпадать с .env в корне. # 3. Сборка и запуск docker compose build docker compose up -d # 4. Откройте http://localhost и пройдите мастер установки ``` Проверка: ```powershell docker compose ps # все три контейнера Healthy Invoke-RestMethod http://localhost/api/health # {"status":"healthy","shutting_down":false,"stream_state":"running"} ``` Остановка: `docker compose down` (данные БД сохраняются в томе `postgres_data`). Полная очистка вместе с БД: `docker compose down -v`. ## Переменные окружения Интерполяция compose берёт значения из корневого `.env` (файл создаётся из `.env.example`). Этот файл **не передаётся в контейнеры** и не влияет на pydantic-парсинг backend. Конфигурация самого backend — `env_config/.env` (монтируется в `/app/env_config`). | Переменная (корневой .env) | Назначение | По умолчанию | |----------------------------|-----------------------------------------|--------------| | `DB_USER` / `DB_PASSWORD` | Учётка Postgres | `postgres` / `postgres` | | `DB_NAME` | Имя создаваемой БД | `umni` (в `.env` — `ecosystem`) | | `DB_PORT` | Порт БД в сети compose | `5432` | | `WEB_PORT` | Порт наружу для веб-интерфейса | `80` | | `LOG_LEVEL` | Уровень логов backend (`INFO`/`DEBUG`) | `INFO` | | `STORAGE_HOST_BASE` | Корень монтирования дисков хоста | `/host` | В `env_config/.env` также задаются `APP_MODE`, `DEBUG_MODE`, `ENCRYPTION_KEY` (генерируется автоматически при первом старте, если пусто). ## Тома | Монтирование | Назначение | |--------------|------------| | `./logs` → `/app/logs` | Логи backend | | `./env_config` → `/app/env_config` | `.env` бэкенда (на запись: авто-сохранение ключа) | | `./storage` → `/app/storage` | Внутреннее хранилище (схемы устройств, сессии telegram) | | `./plugins/custom` → `/app/plugins/custom` | Пользовательские плагины | | `./nginx.conf` → `/etc/nginx/nginx.conf` (ro) | Конфиг nginx | | хост-хранилища (см. ниже) | Записи/скриншоты с камер | ## Хранилища: хостовые пути в Docker Путь хранилища задаётся в UI **как на хосте** — одинаково для Windows, Linux и Docker: - Windows: `D:\CameraData` - Linux: `/mnt/rec` Backend переводит путь, только если это нужно (одна и та же логика во всех окружениях): 1. Если путь вида `X:\...` / `X:/...`, и внутри контейнера доступен `//` — используется он (`/host/D/CameraData`). 2. Если нет — путь используется как есть (нативный Windows: `D:\CameraData` валиден). 3. Любой другой путь (Linux-абсолютный или относительный) не меняется. В БД и в UI всегда остаётся хостовый путь, введённый пользователем. ### Обязательное условие: диск хоста должен быть смонтирован в compose Смонтируйте диск/папку **до** добавления хранилища. Пример для `docker-compose.yml` (и `docker-compose.release.yml`): ```yaml # Windows-хост (Docker Desktop): весь диск D: доступен как /host/D volumes: - ./logs:/app/logs - ./env_config:/app/env_config - ./storage:/app/storage - ./plugins/custom:/app/plugins/custom - type: bind source: 'D:\' target: /host/D ``` ```yaml # Linux-хост: путь в storages задаётся контейнерный, совпадающий с маунтом - type: bind source: /mnt/rec target: /mnt/rec ``` Если диск не смонтирован, добавление хранилища вернёт 404 «Path not found» — это ожидаемое поведение. Запись видео/скриншотов идёт по адресу `<диск>//...` на хосте. ## Troubleshooting - **`pip`/`apt` падает при сборке (UTF-16 requirements):** файл `requirements.txt` должен быть в UTF-8. Если он повреждён (BOM `FF FE`), пересохраните: в VS Code «Save with Encoding → UTF-8». - **`apt-get: Unable to connect to deb.debian.org`:** сеть BuildKit/прокси. Проверьте доступность сети из контейнера: `docker run --rm python:3.11-slim apt-get update`. - **Live-просмотр камер (WebRTC) не работает за bridge-сетью:** в мосту aiortc отдаёт ICE host-кандидаты с внутренним IP (172.x), недоступным с хоста. Варианты: `network_mode: host` для backend (тогда `DB_HOST` → `localhost`), либо TURN-сервер и `WEBRTC_STUN_URLS`. - **Linux-хост: права на bind-каталоги:** контейнер работает от UID 1000 (`appuser`). На Linux хосте каталоги `./logs`, `./env_config`, `./storage` должны быть `chown 1000:1000` (в Docker Desktop/Windows проблем нет). - **БД не найдена (database "ecosystem" does not exist):** см. раздел «Переменные окружения» — имя БД в корневом `.env` (`DB_NAME`) и в `env_config/.env` должны совпадать; после изменения пересоздайте: `docker compose down -v && docker compose up -d`. - **Backend не стартует из-за CORS:** CORS-миддлварь отключён намеренно — всё ходит через один nginx-same-origin.