Files
vidconf/docs/deploy/install.md
Max Ronzhin 7a5e9d2d8a
Some checks failed
CI / backend (push) Has been cancelled
CI / frontend (push) Has been cancelled
perf(deploy): не пересобирать окружение uv в рантайме контейнеров
Образ собран с `uv sync --frozen --no-dev`, но `uv run` перед каждым запуском
заново синхронизирует venv и подтягивает dev-группу. В логах старта
vidconf-backend-1 и vidconf-worker-1 на проде это видно как «Downloading ruff /
mypy / pygments» и «Installed 12 packages». Хуже всего healthcheck'и: они
выполняют ту же синхронизацию каждые 15 секунд всю жизнь контейнера.

Проверено на локально собранном образе, одна и та же команда:

  uv run             — качает 12 пакетов, venv 456 → 574 МБ
  uv run --no-sync   — не качает ничего, venv остаётся 456 МБ

Флаг добавлен во все вызовы в прод-путях: CMD образа, command/entrypoint/
healthcheck всех сервисов compose, миграции и seed в install.sh, те же команды
в docs/deploy. Локальная разработка (dev-setup.md, backend/README.md, CI) не
затронута — там dev-зависимости нужны. Заодно убрано устаревшее объяснение
ретрая `up -d --wait`: первый старт больше не синхронизирует окружение.

Версия uv в образе — 0.11.33, `--no-sync` поддерживается.
2026-07-28 23:25:56 +03:00

11 KiB
Raw Permalink Blame History

Инсталлятор (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 не перетирает существующие настройки.

При повторном запуске инсталлятора на живой инсталляции:

./install.sh --preset 3                  # спросит: обновить настройки? [Y/n]
./install.sh --preset 3 --yes            # без подтверждения, применит пресет 3

Поведение:

  • Дефолт (Enter): применяет матрицу выбранного пресета к настройкам БД (defs: docker compose exec -T backend uv run --no-sync python -m scripts.apply_preset_settings --force)
  • Отказ (n): сохраняет ручные правки админа; переменные BOOTSTRAP_* в .env обновляются, но скрипт применения настроек НЕ запускается
  • Флаг --yes: автоматически применяет пресет без вопроса (для CI/CD)

Скрипт обновления: upsert четырёх ключей в instance_settings БД: chat (enabled), transcriber (enabled), summarizer (enabled), ai_level.

Использование

./install.sh                    # интерактивный опросник + рекомендация по железу
./install.sh --preset 3         # неинтерактивно
./install.sh --preset 3 --yes   # без подтверждений (скрипты/CI, пресет 5 без GPU)
./install.sh --preset 2 --monitoring --yes  # + профиль monitoring (Grafana/Prometheus)

Флаг --monitoring дописывает профиль monitoring к COMPOSE_PROFILES (иначе set_env_var при выборе пресета перезаписывает это значение целиком и Grafana/Prometheus не поднимаются автоматически — см. .forcc/deploy/SESSION4-FINDINGS.md, ГРАБЛИ 2, во внутренних заметках сессии деплоя). Без флага мониторинг поднимается отдельной командой — см. docs/deploy/monitoring.md.

Повторный запуск с другим --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 --no-sync 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 попыток): на слабой/загруженной машине 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) — вне рамок автоматической проверки.