feat(deploy): переключить .env на проде на Infisical вместо ручного файла
All checks were successful
Deploy / test (push) Successful in 3m23s
Deploy / deploy (push) Successful in 13s

deploy.sh теперь на каждом запуске логинится в Infisical (Machine Identity
Universal Auth) и генерирует .env из окружения prod перед синком кода и
поднятием контейнеров. Если Infisical недоступен или вернул подозрительно
мало ключей — деплой падает раньше, не трогая рабочий .env на сервере.

Добавлен шаг compose up -d без --build для всех бэкенд-сервисов после
сборки изменившихся — иначе правка секрета без изменения кода не попадала
бы в уже запущенные контейнеры (docker compose пересоздаёт только то, чей
эффективный конфиг реально изменился, остальное не трогает).
This commit is contained in:
jze9
2026-08-27 16:25:28 +05:00
parent 1dd3f1569f
commit c152fafa70
2 changed files with 55 additions and 8 deletions

View File

@@ -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"

View File

@@ -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"