# Публикация образов на Docker Hub

Назначение — дать возможность любому развернуть окружение из готовых образов,
без клонирования исходников и сборки (`docker-compose.release.yml`).

## Что публикуется

| Репозиторий Docker Hub           | Содержимое                          |
|----------------------------------|-------------------------------------|
| `<user>/umni-ecosystem-backend`  | FastAPI-бэкенд (см. `umni-ecosystem-backend/Dockerfile`) |
| `<user>/umni-ecosystem-frontend` | Vue-фронтенд + nginx (см. `umni-ecosystem-frontend/Dockerfile`) |

Теги на каждый релиз: `vX.Y.Z` (имя git-тега) и `latest`. Сборка мультиархная:
`linux/amd64`, `linux/arm64`.

```
docker pull <user>/umni-ecosystem-backend:v1.0.0
```

## Способ 1. Ручная публикация

Секреты не нужны, достаточно учётки Docker Hub.

```powershell
cd C:\Develop\UMNI\Ecosystem

docker login                       # логин Docker Hub

# сборка обоих образов
docker compose build

# тегирование под ваш аккаунт
docker tag ecosystem-backend  <user>/umni-ecosystem-backend:v1.0.0
docker tag ecosystem-backend  <user>/umni-ecosystem-backend:latest
docker tag ecosystem-frontend <user>/umni-ecosystem-frontend:v1.0.0
docker tag ecosystem-frontend <user>/umni-ecosystem-frontend:latest

# публикация
docker push <user>/umni-ecosystem-backend:v1.0.0
docker push <user>/umni-ecosystem-backend:latest
docker push <user>/umni-ecosystem-frontend:v1.0.0
docker push <user>/umni-ecosystem-frontend:latest
```

### Мультиарх за один шаг (buildx)

```powershell
docker buildx build --platform linux/amd64,linux/arm64 `
  -t <user>/umni-ecosystem-backend:v1.0.0 -t <user>/umni-ecosystem-backend:latest `
  --push ./umni-ecosystem-backend

docker buildx build --platform linux/amd64,linux/arm64 `
  -t <user>/umni-ecosystem-frontend:v1.0.0 -t <user>/umni-ecosystem-frontend:latest `
  --push ./umni-ecosystem-frontend
```

## Способ 2. GitHub Actions (рекомендуется)

В каждом из репозиториев (`umni-ecosystem-backend`, `umni-ecosystem-frontend`) лежит
`.github/workflows/docker-publish.yml`.

### Что он делает

- Загружает код репозитория;
- поднимает QEMU + Buildx (сборка под `amd64` и `arm64`);
- логинится в Docker Hub по секретам;
- собирает и публикует образ репозитория с тегами `<имя тега>` и `latest`.

### Когда срабатывает

- **Пуш git-тега вида `v*`** (например `v1.0.0`). Обычные коммиты/пуши в ветки **не**
  отправляют образы.
- **По кнопке «Run workflow»** (вкладка Actions → ручной запуск).

### Настройка один раз

1. В Docker Hub создайте репозитории `umni-ecosystem-backend`, `umni-ecosystem-frontend`
   (публичные или приватные — как хотите).
2. В **обоих** GitHub-репозиториях добавьте секреты Settings → Secrets and variables → Actions:
   - `DOCKERHUB_USERNAME` — ваш логин;
   - `DOCKERHUB_TOKEN` — Access Token с правами `Read/Write` (Account Settings → Security → Tokens).
3. Создайте тег и запушьте его:

```bash
git tag v1.0.0
git push origin v1.0.0
```

Workflow соберёт и опубликует оба образа автоматически.

### Особенности

- Собирает **один репозиторий** (backend или frontend): build-context каждого — его каталог.
- Корень `C:\Develop\UMNI\Ecosystem` git-репозиторием не является, поэтому CI размещён
  в самих подрепозиториях; а compose-файлы и эта документация публикуются отдельно.

## Развёртывание пользователем из образов

### Минимальный набор файлов и структура каталогов

В любом каталоге на целевой машине (Windows/Linux/Docker Desktop/VM) достаточно:

```
deploy/                          <- любой каталог, где лежат файлы ниже
├── docker-compose.release.yml   # обязательно: запускает контейнеры из образов (host-режим)
├── nginx.host.conf              # обязательно: монтируется в frontend, без него контейнер не стартует
├── env_config/
│   └── .env                     # обязательно: БД + настройки backend (сюда пишется ENCRYPTION_KEY)
├── .env                         # опционально: интерполяция compose (WEB_PORT, DB_NAME, ...)
├── storage/                     # внутренние данные; создаётся автоматически
├── logs/                        # логи backend; создаётся автоматически
└── plugins/
    └── custom/                  # пользовательские плагины
```

| Файл | Назначение |
|------|------------|
| `docker-compose.release.yml` | Поднимает `postgres`, `backend`, `frontend` из Docker Hub (без сборки). `backend` и `frontend` работают в `network_mode: host`, `postgres` — на bridge `app-network`. |
| `nginx.host.conf` | Раздаёт SPA и проксирует `/api/*` на `127.0.0.1:8000` (backend в сети хоста). Обязателен как bind-mount. |
| `env_config/.env` | Параметры БД и backend. Монтируется в `/app/env_config` **на запись** — сюда backend сам сохраняет `ENCRYPTION_KEY`. |
| `.env` (в корне) | Значения для интерполяции compose: `DB_NAME`, `DB_USER`, `DB_PASSWORD`, `DB_PORT`, `LOG_LEVEL`, `STORAGE_HOST_BASE`. В release (host-режим) `WEB_PORT` не используется: nginx слушает 80 на хосте. Если хватает значений по умолчанию — можно не создавать. |
| `storage/`, `logs/`, `plugins/custom/` | Bind-каталоги; при отсутствии Docker создаёт их пустыми. |

### Шаги на Linux-VM

```bash
# 1. Подготовить каталог и файлы (см. таблицу выше)
mkdir -p env_config storage logs plugins/custom
cp nginx.host.conf . ; cp docker-compose.release.yml .
# положить env_config/.env  (примеры ключей — в DOCKER.md)

# 2. ПРАВА: контейнер backend работает от UID 1000 (appuser).
#    Без этого он не сможет писать логи и обновлять ENCRYPTION_KEY в .env.
sudo chown -R 1000:1000 env_config logs storage plugins

# 3. (опционально) Интернет-медиа: устройства шлют syslog на UDP 514 и находят
#    сервис ``_umni_api._tcp.local.`` (mDNS) по multicast. Backend в host-режиме
#    видит LAN напрямую, но не-root-процессу (UID 1000) нужен низкий порт 514:
echo 'net.ipv4.ip_unprivileged_port_start=0' | sudo tee /etc/sysctl.d/99-umni.conf
sudo sysctl --system

# 4. Запуск
docker compose -f docker-compose.release.yml pull      # подтянуть образы (рекомендуется)
docker compose -f docker-compose.release.yml up -d
docker compose -f docker-compose.release.yml ps        # все три контейнера Healthy
```

Откройте `http://<ip_виртуалки>` и пройдите мастер установки (nginx слушает порт 80 на хосте —
проверьте, что он открыт в фаерволе VM). Проверка API: `GET http://<ip_виртуалки>/api/health` →
`{"status":"healthy", ...}`.

Проверка mDNS из host-сети (backend в host-режиме = сеть хоста):

```bash
docker exec umni_backend python -c "import socket;s=socket.socket(socket.AF_INET,socket.SOCK_DGRAM);s.setsockopt(socket.IPPROTO_IP,socket.IP_MULTICAST_TTL,2);s.sendto(b't',('224.0.0.251',5353));print('mcast ok')"
```

Нюансы host-режима:
- backend (`uvicorn`) слушает только `127.0.0.1:8000` — API наружу светится только через nginx на 80.
- `postgres` публикуется на `127.0.0.1:5432` (в LAN не торчит); `DB_HOST=127.0.0.1` в `docker-compose.release.yml`.
- Устройства должны быть в одном L2-сегменте с VM (mDNS не ходит через маршруты).
- Если на VM работает `avahi-daemon`, он держит порт 5353 — при конфликте: `sudo systemctl stop avahi-daemon`.

Синхронизация значений БД: имя/пользователь/пароль в корневом `.env` (`DB_NAME`, `DB_USER`,
`DB_PASSWORD`) должны совпадать с `env_config/.env`. При чистой установке `ENCRYPTION_KEY` можно
оставить пустым (сгенерируется и сохранится сам); при переносе существующей БД — ключ должен совпадать
со старым, иначе пароли камер расшифровать не удастся.

### Запуск на Windows/Docker Desktop

> ВНИМАНИЕ: `docker-compose.release.yml` — host-режим (`network_mode: host`) и рассчитан на Linux-VM.
> На Docker Desktop (WSL2) host-сеть — это сеть WSL2-VM, multicast до LAN Windows она не отдаёт.
> Для локальной разработки на Windows используйте `docker-compose.yml` (bridge-режим).

```powershell
Copy-Item .env.example .env
# положить env_config/.env, скопировать docker-compose.release.yml и nginx.host.conf
docker compose -f docker-compose.release.yml pull
docker compose -f docker-compose.release.yml up -d
```

По умолчанию образы берутся как `sazanof/umni-ecosystem-*:latest`. Другой аккаунт/версию задайте
переменными окружения (`IMAGE_OWNER`, `IMAGE_TAG`) — см. шапку `docker-compose.release.yml`.

### Обновление и бэкап

Команда:

```powershell
docker compose -f docker-compose.release.yml pull
docker compose -f docker-compose.release.yml up -d
```

Данные БД переживают обновление (том `postgres_data`); бэкап БД — `pg_dump`.

Хранилища на хосте подключаются маунтами — подробнее в [DOCKER.md](DOCKER.md#хранилища-хостовые-пути-в-docker).