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 перед сборкой/подъёмом
стека.
This commit is contained in:
2026-07-25 21:58:03 +03:00
parent 79003eb56c
commit 693db6e774
10 changed files with 63 additions and 39 deletions

View File

@@ -114,6 +114,17 @@ ensure_secret() {
fi
}
# Установить дефолт для НЕ-секретного ключа только если он ещё не задан —
# аналог ensure_secret, но без генерации случайного значения. Не трогает
# значение, уже заданное вручную (реальный домен/IP боевого сервера).
ensure_default() {
key="$1"
default="$2"
if [ -z "$(get_env_var "$key")" ]; then
set_env_var "$key" "$default"
fi
}
# ---------------------------------------------------------------------------
# Автодетект железа (ADR-004, таблица требований).
# ---------------------------------------------------------------------------
@@ -270,6 +281,16 @@ set_env_var HW_RAM_MB "$HW_RAM_MB"
set_env_var HW_GPU_NAME "$HW_GPU_NAME"
set_env_var HW_VRAM_MB "$HW_VRAM_MB"
# nginx/coturn/livekit — дефолты для локальной разработки (localhost/127.0.0.1),
# только если ещё не заданы. На боевом сервере ДО первого запуска install.sh
# задайте в .env реальные значения (домены, внешний IP) — ensure_default их
# не перезапишет.
ensure_default NGINX_SERVER_NAMES "localhost"
ensure_default NGINX_CERT_NAME "localhost"
ensure_default LIVEKIT_USE_EXTERNAL_IP "false"
ensure_default LIVEKIT_NODE_IP "127.0.0.1"
ensure_default TURN_EXTERNAL_IP "127.0.0.1"
# Профили compose и модели по пресету. GPU-профили — ТОЛЬКО для пресета 5
# (max): в текущей матрице уровней (backend/services/ai_tiers.py, ADR-004)
# уровень `medium` фиксированно CPU-only (GPU для него — ручная настройка
@@ -351,14 +372,17 @@ for _p in "${_profiles[@]}"; do
[ -n "$_p" ] && PROFILE_ARGS+=(--profile "$_p")
done
echo "[install] Рендерю coturn/livekit из шаблонов (deploy/render-templates.sh)"
"$SCRIPT_DIR/deploy/render-templates.sh"
echo "[install] docker compose pull (лучше сразу, но необязательный шаг — образы, которых нет в реестре под текущим тегом, пропускаются)"
docker compose -f "$COMPOSE_FILE" "${PROFILE_ARGS[@]}" pull --ignore-buildable 2>/dev/null || true
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "${PROFILE_ARGS[@]}" pull --ignore-buildable 2>/dev/null || true
echo "[install] docker compose build"
docker compose -f "$COMPOSE_FILE" "${PROFILE_ARGS[@]}" build
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "${PROFILE_ARGS[@]}" build
echo "[install] Поднимаю postgres/redis (--wait) — нужны для миграций до старта backend"
docker compose -f "$COMPOSE_FILE" up -d --wait postgres redis
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" up -d --wait postgres redis
# backend.lifespan бутстрапит instance_settings при КАЖДОМ старте приложения,
# поэтому миграции обязаны применяться ДО первого запуска backend/worker —
@@ -366,8 +390,8 @@ docker compose -f "$COMPOSE_FILE" up -d --wait postgres redis
# exist" и healthcheck (--wait) никогда не проходит. `compose run` запускает
# одноразовый контейнер с нужной командой, не поднимая uvicorn/lifespan.
echo "[install] Применяю миграции Alembic и seed (админ/справочники) — до старта backend"
docker compose -f "$COMPOSE_FILE" run --rm backend uv run alembic upgrade head
docker compose -f "$COMPOSE_FILE" run --rm backend uv run python -m scripts.seed
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" run --rm backend uv run alembic upgrade head
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" run --rm backend uv run python -m scripts.seed
echo "[install] docker compose up -d --wait (backend/worker/nginx и остальные сервисы профиля)"
# Первый старт backend/worker включает `uv run` (синхронизация окружения +
@@ -378,12 +402,12 @@ echo "[install] docker compose up -d --wait (backend/worker/nginx и остал
# уже стартующих контейнеров, ничего не пересоздавая.
UP_ATTEMPTS=3
for attempt in $(seq 1 "$UP_ATTEMPTS"); do
if docker compose -f "$COMPOSE_FILE" "${PROFILE_ARGS[@]}" up -d --wait; then
if docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" "${PROFILE_ARGS[@]}" up -d --wait; then
break
fi
if [ "$attempt" -eq "$UP_ATTEMPTS" ]; then
echo "[install] ОШИБКА: сервисы не стали healthy за $UP_ATTEMPTS попыток." >&2
echo "[install] Проверьте логи: docker compose -f $COMPOSE_FILE logs backend worker" >&2
echo "[install] Проверьте логи: docker compose -f $COMPOSE_FILE --env-file $ENV_FILE logs backend worker" >&2
exit 1
fi
echo "[install] Не все сервисы healthy (попытка $attempt/$UP_ATTEMPTS) — жду 10с и повторяю..."
@@ -413,7 +437,7 @@ if [ "$FRESH_ENV" != "1" ]; then
fi
if [ "$APPLY_PRESET_SETTINGS" = "1" ]; then
echo "[install] Применяю настройки модулей инстанса под пресет ${PRESET}"
docker compose -f "$COMPOSE_FILE" exec -T backend uv run python -m scripts.apply_preset_settings --force
docker compose -f "$COMPOSE_FILE" --env-file "$ENV_FILE" exec -T backend uv run python -m scripts.apply_preset_settings --force
else
echo "[install] Настройки модулей инстанса НЕ изменены — сохранены ручные правки администратора"
fi
@@ -436,7 +460,7 @@ cat <<EOF
Мониторинг (Grafana/Prometheus) — отдельный профиль compose, не входит
в базовые пресеты:
docker compose -f ${COMPOSE_FILE} --profile monitoring up -d
docker compose -f ${COMPOSE_FILE} --env-file ${ENV_FILE} --profile monitoring up -d
Grafana: http://localhost:3001 (${GRAFANA_USER:-admin} / см. .env GRAFANA_ADMIN_PASSWORD)
Настройки модулей инстанса (чат, уровень AI) синхронизированы под