Files
vidconf/docs/deploy/install.md
Max Ronzhin 693db6e774 install.sh, docs: pass --env-file explicitly to docker compose
docker compose определяет .env для подстановки ${VAR} по каталогу
compose-файла (deploy/), а не по текущей директории — repo-root .env,
который использует install.sh и вся документация, молча не подхватывался.
Это и была причина "WARN: LIVEKIT_API_KEY not set" на боевом сервере:
секреты были в .env, но compose их не видел и подставлял небезопасные
дефолты (см. таблицу разведки сервера).

Теперь ставшие обязательными ${VAR:?} в docker-compose.yml (см. предыдущий
коммит) без этого немедленно проваливали бы конфиг на любой из
документированных команд. Добавлен `--env-file .env`/"$ENV_FILE" ко всем
вызовам docker compose в install.sh и в командах из README/docs.

install.sh дополнительно: ensure_default (аналог ensure_secret без генерации
секрета) для новых не-секретных параметров nginx/coturn/livekit
(NGINX_SERVER_NAMES, NGINX_CERT_NAME, LIVEKIT_USE_EXTERNAL_IP,
LIVEKIT_NODE_IP, TURN_EXTERNAL_IP) — дефолты только для локальной
разработки, не перезаписывают значения, заданные вручную на боевом
сервере. Плюс вызов deploy/render-templates.sh перед сборкой/подъёмом
стека.
2026-07-25 21:58:03 +03:00

135 lines
10 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Инсталлятор (`install.sh`, релиз v0.0.1)
Один скрипт в корне репозитория — автодетект железа, опросник из 5
пресетов поставки, идемпотентная запись `.env`, сборка образов, миграции и
seed, подъём стека. По завершении `http://localhost/` отдаёт рабочий
фронтенд-SPA (React + Vite; статика вкомпилирована в образ nginx,
`frontend/Dockerfile`) — во ВСЕХ пресетах. Источник истины по
моделям/квантам/требованиям железа — ADR-004
(`docs/architecture/adr/004-ai-tier-matrix.md`); по пресетам поставки —
сам `install.sh` (см. таблицу ниже).
## Пресеты
| # | Состав | Профили compose | Модели |
|---|---|---|---|
| 1 | MVP-ядро (лобби, конференции, календарь, закреплённые, гости) | `media` | — |
| 2 | 1 + чат | `media` | — |
| 3 | 2 + AI «мин» (CPU) | `media,transcribe,llm` | faster-whisper `small` + Qwen3.5-4B |
| 4 | 2 + AI «средний» (CPU) | `media,transcribe,llm` | faster-whisper `medium` + Qwen3.5-9B |
| 5 | 2 + AI «макс» (GPU обязателен) | `media,transcribe-gpu,llm-gpu` | faster-whisper `large-v3` + Qwen3.5-35B-A3B |
Чат (2) и уровень AI (3/4/5) — переключатели плагинов в админке
(`instance_settings`, БД); `install.sh` поднимает НЕОБХОДИМЫЕ для
выбранного пресета контейнеры/модели И синхронизирует настройки инстанса
в соответствии с матрицей пресета (см. раздел «Синхронизация настроек
модулей»). Уровень `medium` в текущей матрице (`backend/services/ai_tiers.py`)
CPU-only — отдельного GPU-варианта профилей для пресета 4 нет (GPU для
`medium` — ручная настройка администратора вне детекта).
Запись конференций НЕ входит в пресеты (появится в v0.1.0) — вопрос
про неё инсталлятор не задаёт.
## Синхронизация настроек модулей (бутстрап)
При **первом старте** backend (lifespan) применяет пресет настроек через
три env-переменные `BOOTSTRAP_*`:
- `BOOTSTRAP_CHAT_ENABLED` (`true` | `false`) — включить чат в конференциях
- `BOOTSTRAP_TRANSCRIPTION_ENABLED` (`true` | `false`) — включить транскрибацию и суммаризацию
- `BOOTSTRAP_AI_LEVEL` (`min` | `medium` | `max`) — уровень AI (игнорируется, если транскрибация выключена)
**Матрица пресет → настройки модулей:**
| Пресет | Чат | AI | Уровень | `BOOTSTRAP_CHAT_ENABLED` | `BOOTSTRAP_TRANSCRIPTION_ENABLED` | `BOOTSTRAP_AI_LEVEL` |
|--------|-----|-----|---------|:---:|:---:|---|
| 1 (MVP-ядро) | — | — | — | `false` | `false` | `min` |
| 2 (+чат) | ✓ | — | — | `true` | `false` | `min` |
| 3 (+AI мин) | ✓ | ✓ | мин | `true` | `true` | `min` |
| 4 (+AI средний) | ✓ | ✓ | средний | `true` | `true` | `medium` |
| 5 (+AI макс) | ✓ | ✓ | макс | `true` | `true` | `max` |
Бутстрап **идемпотентен** при первом старте: дефолты из `config/plugins.yaml`
(всё `enabled: true`) переопределяются переменными `BOOTSTRAP_*` только если
БД ещё не содержит ключи настроек инстанса (проверка `INSERT ... ON CONFLICT DO NOTHING`).
Повторное включение контейнера backend не перетирает существующие настройки.
**При повторном запуске** инсталлятора на живой инсталляции:
```bash
./install.sh --preset 3 # спросит: обновить настройки? [Y/n]
./install.sh --preset 3 --yes # без подтверждения, применит пресет 3
```
Поведение:
- **Дефолт (Enter):** применяет матрицу выбранного пресета к настройкам БД
(defs: `docker compose exec -T backend uv run python -m scripts.apply_preset_settings --force`)
- **Отказ (`n`):** сохраняет ручные правки админа; переменные `BOOTSTRAP_*` в `.env`
обновляются, но скрипт применения настроек НЕ запускается
- **Флаг `--yes`:** автоматически применяет пресет без вопроса (для CI/CD)
Скрипт обновления: upsert четырёх ключей в `instance_settings` БД:
`chat` (`enabled`), `transcriber` (`enabled`), `summarizer` (`enabled`), `ai_level`.
## Использование
```bash
./install.sh # интерактивный опросник + рекомендация по железу
./install.sh --preset 3 # неинтерактивно
./install.sh --preset 3 --yes # без подтверждений (скрипты/CI, пресет 5 без GPU)
```
Повторный запуск с другим `--preset` — апгрейд/даунгрейд на месте: модели
уровня докачиваются (старые с диска не удаляются — занимают место, но не
мешают), `COMPOSE_PROFILES`/`WHISPER_MODEL`/`LLM_MODEL_*` в `.env`
обновляются точечно, секреты (JWT/БД/TURN/LiveKit/Grafana) и любые
пользовательские правки `.env` — сохраняются (генерация только при полном
отсутствии значения, см. `ensure_secret` в `install.sh`).
## Что делает скрипт
1. Автодетект `nproc`/`free -m` (или `sysctl` на macOS)/`nvidia-smi`
пишет `HW_CPUS`/`HW_RAM_MB`/`HW_GPU_NAME`/`HW_VRAM_MB` в `.env` — их
читает `backend/services/ai_levels.py` (детект доступности уровней AI в
админке, причины недоступности).
2. Точечно обновляет `.env` (создаёт из `.env.example` при первом запуске,
на первом запуске сразу генерирует РЕАЛЬНЫЕ секреты вместо
плейсхолдеров `change-me...` из шаблона в git).
3. Собирает флаги `--profile` из `COMPOSE_PROFILES` в `.env` (эта версия
docker compose НЕ подхватывает `COMPOSE_PROFILES` автоматически при `up`,
поэтому профили media/transcribe/llm передаются командам явно) и собирает
образы: `docker compose pull --ignore-buildable` (best-effort) →
`docker compose build` (backend, worker и nginx — образ nginx multi-stage
собирает фронтенд-SPA и вкомпилирует статику, `frontend/Dockerfile`).
4. Поднимает `postgres`/`redis` (`up -d --wait`) и применяет **до старта
backend** миграции и seed одноразовыми контейнерами:
`docker compose run --rm backend uv run alembic upgrade head` +
`... python -m scripts.seed`. Порядок критичен: `backend.lifespan`
бутстрапит `instance_settings` при каждом старте приложения, поэтому на
чистой БД таблицы обязаны существовать до первого запуска backend — иначе
healthcheck (`--wait`) никогда не проходит. Seed идемпотентен (админ;
справочник `teams` и ключи `instance_settings`, включая
`registration_team_choice`/`registration_email_domain`, бутстрапятся
backend'ом при старте, `INSERT ... ON CONFLICT DO NOTHING` — существующие
настройки инстанса не перетираются).
5. Поднимает остальной стек: `docker compose <--profile ...> up -d --wait`
(backend, worker, nginx с фронтом + сервисы активных профилей). Команда
идемпотентна и обёрнута в ретрай (до 3 попыток): первый старт backend/worker
включает `uv run` (синхронизация окружения + компиляция байткода), и на
слабой/загруженной машине healthcheck может не успеть за отведённые
retries — повтор лишь дожидается уже стартующих контейнеров.
6. Печатает сводку: URL фронтенда/бэкенда, учётные данные администратора,
команда для `--profile monitoring`.
## Проверка
- Чистая установка (пресеты 1 и 3) на пустом `.env`/чистых volume.
- Апгрейд 1 → 3 (повторный запуск с другим `--preset`, секреты сохранены).
- Рекомендация детекта соответствует реальному железу текущей машины.
- `bash -n install.sh`, `docker compose -f deploy/docker-compose.yml --env-file .env config -q`
для всех сочетаний профилей — минимальная валидация без реального подъёма.
Полную установку на чистой машине/VM гоняют вручную (использование сети
для скачивания GGUF-моделей ~2,620,5 ГБ, GPU-хост для пресета 5) — вне
рамок автоматической проверки.