From c152fafa706f1a1c755c8275a62b986492a999b1 Mon Sep 17 00:00:00 2001 From: jze9 Date: Thu, 27 Aug 2026 16:25:28 +0500 Subject: [PATCH] =?UTF-8?q?feat(deploy):=20=D0=BF=D0=B5=D1=80=D0=B5=D0=BA?= =?UTF-8?q?=D0=BB=D1=8E=D1=87=D0=B8=D1=82=D1=8C=20.env=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=BF=D1=80=D0=BE=D0=B4=D0=B5=20=D0=BD=D0=B0=20Infisical=20?= =?UTF-8?q?=D0=B2=D0=BC=D0=B5=D1=81=D1=82=D0=BE=20=D1=80=D1=83=D1=87=D0=BD?= =?UTF-8?q?=D0=BE=D0=B3=D0=BE=20=D1=84=D0=B0=D0=B9=D0=BB=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit deploy.sh теперь на каждом запуске логинится в Infisical (Machine Identity Universal Auth) и генерирует .env из окружения prod перед синком кода и поднятием контейнеров. Если Infisical недоступен или вернул подозрительно мало ключей — деплой падает раньше, не трогая рабочий .env на сервере. Добавлен шаг compose up -d без --build для всех бэкенд-сервисов после сборки изменившихся — иначе правка секрета без изменения кода не попадала бы в уже запущенные контейнеры (docker compose пересоздаёт только то, чей эффективный конфиг реально изменился, остальное не трогает). --- .gitea/workflows/deploy.yml | 2 ++ scripts/deploy.sh | 61 ++++++++++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 8 deletions(-) diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml index f8b6dc7..0e1d095 100644 --- a/.gitea/workflows/deploy.yml +++ b/.gitea/workflows/deploy.yml @@ -58,6 +58,8 @@ jobs: - name: Деплой (бэкенд 1.32 + фронтенд CT 102) env: PVE_PASSWORD: ${{ secrets.PVE_PASSWORD }} + INFISICAL_CLIENT_ID: ${{ secrets.INFISICAL_CLIENT_ID }} + INFISICAL_CLIENT_SECRET: ${{ secrets.INFISICAL_CLIENT_SECRET }} run: | set -euo pipefail cd "$SRC" diff --git a/scripts/deploy.sh b/scripts/deploy.sh index 74aeb98..2a6b55b 100755 --- a/scripts/deploy.sh +++ b/scripts/deploy.sh @@ -5,7 +5,10 @@ # Запускается Gitea Actions runner'ом в host-режиме прямо на app-хосте 1.32 # (см. .gitea/workflows/deploy.yml). Ожидает: # - cwd = ПОЛНЫЙ чекаут репозитория (нужен git-лог для diff); -# - переменную PVE_PASSWORD (секрет) для доступа к Proxmox-хосту → CT 102. +# - переменную PVE_PASSWORD (секрет) для доступа к Proxmox-хосту → CT 102; +# - INFISICAL_CLIENT_ID / INFISICAL_CLIENT_SECRET (Machine Identity +# "claude-ai", Universal Auth) — .env на проде теперь генерируется из +# Infisical (prod) на каждом деплое, а не правится руками на сервере. # # Пересобирается только то, чей код изменился с прошлого деплоя (маркер SHA в # $APP/.last_deploy_sha). Это критично: worker-gpu тянет torch/faiss (~2 ГБ), @@ -51,7 +54,41 @@ else fi REBUILD="$(echo "$REBUILD" | xargs || true)" -echo "==> [1/5] Синхронизация кода в $APP (сохраняя .env и compose)" +echo "==> [1/6] Секреты из Infisical (prod) → .env" +INFISICAL_BIN="$APP/.infisical-cli" +if [ ! -x "$INFISICAL_BIN" ]; then + echo " ставлю infisical CLI (разово)" + curl -sSL -o /tmp/infisical-cli.tar.gz \ + "https://github.com/Infisical/infisical/releases/download/infisical-cli%2Fv0.31.1/infisical_0.31.1_linux_amd64.tar.gz" + tar xzf /tmp/infisical-cli.tar.gz -C /tmp infisical + mv /tmp/infisical "$INFISICAL_BIN" + rm -f /tmp/infisical-cli.tar.gz +fi + +INFISICAL_DOMAIN=https://infisical.jze9.ru/api +INFISICAL_PROJECT_ID=a2e7505e-573f-43e9-872b-4ed7a6bed7b8 +INFISICAL_TOKEN="$("$INFISICAL_BIN" login --method=universal-auth \ + --client-id="${INFISICAL_CLIENT_ID:?INFISICAL_CLIENT_ID не задан}" \ + --client-secret="${INFISICAL_CLIENT_SECRET:?INFISICAL_CLIENT_SECRET не задан}" \ + --domain="$INFISICAL_DOMAIN" --plain --silent)" + +TMP_ENV="$(mktemp)" +"$INFISICAL_BIN" export --token="$INFISICAL_TOKEN" --domain="$INFISICAL_DOMAIN" \ + --projectId="$INFISICAL_PROJECT_ID" --env=prod --format=dotenv --expand=false \ + --silent > "$TMP_ENV" + +# Не затирать рабочий .env, если Infisical вернул мало строк (недоступен/пуст) — +# иначе следующий шаг раскатит прод с пустым конфигом. +ENV_LINES="$(grep -cE '^[A-Za-z_][A-Za-z0-9_]*=' "$TMP_ENV" || true)" +if [ "$ENV_LINES" -lt 20 ]; then + echo "ОШИБКА: Infisical export вернул только $ENV_LINES строк (ожидалось ~38) — сервис недоступен или пуст. Деплой прерван, .env на проде не тронут." + rm -f "$TMP_ENV" + exit 1 +fi +mv "$TMP_ENV" "$APP/.env" +echo " OK: $ENV_LINES секретов" + +echo "==> [2/6] Синхронизация кода в $APP (сохраняя .env и compose)" rsync -a \ --exclude='__pycache__/' --exclude='*.pyc' --exclude='.pytest_cache/' \ --exclude='node_modules/' --exclude='dist/' \ @@ -59,25 +96,33 @@ rsync -a \ cd "$APP" if [ -n "$REBUILD" ]; then - echo "==> [2/5] Пересборка и перезапуск: $REBUILD" + echo "==> [3/6] Пересборка и перезапуск: $REBUILD" # shellcheck disable=SC2086 $COMPOSE up -d --build $REBUILD else - echo "==> [2/5] Бэкенд-сервисы не менялись — пропуск сборки" + echo "==> [3/6] Бэкенд-сервисы не менялись — пропуск сборки" fi -echo "==> [3/5] Миграции БД (с ретраем)" +# Секреты в .env могли поменяться без изменения кода (правка в Infisical) — +# docker compose сам не пересоздаст контейнер, чей env_file изменился, если +# просто повторно не позвать up -d. Дёшево и идемпотентно: compose пересоздаёт +# только контейнеры с реально изменившимся конфигом, остальные не трогает. +echo "==> [4/6] Применение секретов к неизменившимся сервисам (если менялись)" +# shellcheck disable=SC2086 +$COMPOSE up -d $ALL_BACKEND + +echo "==> [5/6] Миграции БД (с ретраем)" for i in $(seq 1 10); do $COMPOSE exec -T api alembic upgrade head && break echo " api ещё не готов, повтор $i/10..."; sleep 5 done if [ "$FRONTEND_CHANGED" = 1 ]; then - echo "==> [4/5] Сборка фронтенда" + echo "==> [6/6] Сборка фронтенда" docker run --rm -v "$APP/services/frontend":/app -w /app node:20-slim \ sh -c "npm install --no-audit --no-fund --loglevel=error && npm run build" - echo "==> [5/5] Выкладка статики на CT 102 (через $PVE_HOST)" + echo "==> [6/6] Выкладка статики на CT 102 (через $PVE_HOST)" cd "$APP/services/frontend/dist" tar czf /tmp/academic-dist.tgz . export SSHPASS="${PVE_PASSWORD:?PVE_PASSWORD не задан}" @@ -102,7 +147,7 @@ rm -f /tmp/academic-dist.tgz REMOTE rm -f /tmp/academic-dist.tgz else - echo "==> [4-5/5] Фронтенд не менялся — пропуск сборки и выкладки" + echo "==> [6/6] Фронтенд не менялся — пропуск сборки и выкладки" fi echo "$CUR_SHA" > "$MARKER"