Files
deploy/README.md
T

18 KiB
Raw Permalink Blame History

WealthLedger deploy

Установка и обновление одного Linux-сервера с Docker Compose и SQLite:

./deploy.sh vX.Y.Z

vX.Y.Z — Git-тег этого репозитория. Его release.env закрепляет полные адреса frontend и backend. Версии компонентов могут различаться. Скрипт получает тег из origin и выполняет код и Compose выбранного commit; изменения рабочего checkout не подменяют содержимое релиза.

Образы загружаются из nexus.personal.ksv741.ru/docker-hosted/wealthledger/. Комплект v0.1.7 закрепляет frontend 1.2.1 и backend 2.3.1. Комплект v0.1.6 закрепляет backend 2.3.0, образ которого не был опубликован. Работа новой пары на сервере не проверялась перед публикацией комплекта.

Совместимость OpenAPI frontend 1.2.1 и backend 2.3.1, а также наличие новых миграций не проверялись. Штатный deploy.sh выполняет остановку backend, backup и prisma migrate deploy; существующие данные, JWT_SECRET и TOKEN_ENCRYPTION_KEY сохраняются.

Подготовка сервера

Выполняется один раз. Автоматическая установка Docker, настройка DNS, HTTPS, firewall и registry в скрипт не входят.

  1. Установите Git, Bash, Docker Engine с Compose plugin (2.24.4 или новее), flock из util-linux и стандартные tar, cp, mktemp. Используется локальный Docker daemon через Unix socket, не удалённый context.

  2. Настройте внешний HTTPS reverse proxy: весь домен направляется на 127.0.0.1:8080. Отдельный upstream /api не нужен. Порт можно поменять через FRONTEND_PORT; FRONTEND_ORIGIN должен совпадать с HTTPS origin.

  3. Выберите одного оператора с доступом к Docker, Git origin, ключам и данным. Скрипту нужны права читать всю БД и создавать копии. Процесс backend работает с UID/GID 1000:1000; при другом UID оператора настройте доступ заранее. Запускайте команды из одной и той же учётной записи, чтобы Git и Docker использовали подготовленные SSH-ключи и registry credentials.

  4. Войдите в Nexus, вводя пароль интерактивно, без записи в shell history:

    docker login nexus.personal.ksv741.ru --username wealthledger-ci
    
  5. Разместите checkout отдельно от постоянных ресурсов. Пример:

    /opt/wealthledger/
    ├── deploy/              # этот Git checkout
    │   ├── compose.yaml
    │   ├── deploy.sh
    │   ├── release.env      # версии frontend и backend
    │   ├── .env.example
    │   └── README.md
    ├── production.env       # секреты и настройки, chmod 600
    ├── certs/tbank-ca.pem    # CA для подключения к T-Bank, не HTTPS сайта
    ├── data/wealthledger.db
    ├── backups/             # согласованные копии, без автоочистки
    └── .deploy/             # lock, current и при сбое pending
    
    git clone ssh://git@git.personal.ksv741.ru:2222/WealthLedger/deploy.git /opt/wealthledger/deploy
    cd /opt/wealthledger/deploy
    install -m 600 .env.example ../production.env
    

    Последнюю команду выполняйте только при отсутствии production.env: существующий файл с ключами не перезаписывайте.

  6. Заполните настройки защищённым редактором. DATA_DIRECTORY и TBANK_CA_CERT_FILE — существующие абсолютные пути, не внутри checkout. TBANK_CA_CERT_PATH — путь внутри контейнера; сертификат монтируется read-only. Каталог данных должен быть доступен для записи UID 1000, сертификат — для чтения. Не отключайте проверку TLS вместо установки корректного CA.

  7. Проверьте доступ к образам, свободное место под полную копию data и существующую схему HTTPS. Сохраните ключ шифрования отдельно от локальных backups.

Не храните рабочие секреты в Git, не выполняйте source production.env и не печатайте полный docker compose config с реальными ключами.

Подключение существующей установки

Сохраните её Compose и текущие image references до перехода. Заполните production.env прежними JWT_SECRET и TOKEN_ENCRYPTION_KEY и укажите действующий data directory и сертификат. Не копируйте один .db из работающего приложения и не создавайте новые ключи: старые подключения должны расшифровываться.

Проект Compose должен называться wealthledger, сервисы — backend, frontend и migration, база — wealthledger.db. Оператор должен исключить другие процессы записи в этот каталог; старый и новый способы запуска параллельно не используются. Скрипт откажется менять data mount или действующие ключи.

cd /opt/wealthledger/deploy
./deploy.sh vX.Y.Z

Первый переход всегда выполняет полный цикл с backup, поскольку ещё нет подтверждённого baseline комплекта. Данные не переносятся и не переименовываются. --init для действующей установки не применяется.

Новая установка

Только для нового пустого data directory подготовьте UID/GID 1000:1000, permissions 0700 и новые ключи: JWT secret не короче 32 символов и отдельный 32-byte encryption key в base64. Например, openssl rand -hex 32 и openssl rand -base64 32 в защищённом терминале; значения перенесите в env. Предварительно установите сертификат T-Bank.

./deploy.sh vX.Y.Z --init

Отсутствие файла БД без --init считается ошибкой, а не разрешением создать пустую базу. --init отклоняется при наличии прежних контейнеров, успешной установки или непустого data directory. Для первой пустой базы backup не нужен.

Если env расположен иначе, используйте --env-file /absolute/path/production.env. Backups и .deploy всегда находятся рядом с фактическим data directory, поэтому другой env-файл не создаёт отдельную блокировку для той же базы.

Обновление

После публикации нового тега комплекта достаточно той же команды:

./deploy.sh vX.Y.Z
  1. Проверка тега, настроек, данных и CA; загрузка образов и проверка прав runtime user. Ошибка до остановки сохраняет работающие сервисы.
  2. Stop backend → копия всего data directory с WAL/SHM → migration → backend readiness. Только для --init пустой базы backup не требуется.
  3. Запуск frontend после готовности backend. Каждый вызов выполняет этот путь, включая повтор того же тега и frontend-only update. No-op/change detection отсутствуют; приняты короткий простой API и дополнительный backup.
  4. Успех записывается в .deploy/current только после проверки запуска. Краткий простой допустим. После обновления проверьте через HTTPS deep link, login/refresh, существующие карты и чтение зашифрованного подключения.

Проверка сертификата/прав запускает кратковременный контейнер с Node validation, не второй API. Контейнерная готовность не заменяет browser smoke.

Ошибка или прерывание

Скрипт возвращает ненулевой код, этап ошибки, предыдущие images и расположение готовой копии. Он не печатает raw application logs или секреты. После начала изменений .deploy/pending сохраняет безопасные сведения для восстановления; следующая команда остановится, пока оператор не разберёт инцидент.

  • Ошибка backup: миграции не запускались, backend остановлен. Скрытые каталоги backups/.partial-* — незавершённые копии, использовать их для restore нельзя.
  • Ошибка migration: новый backend не запускается. Не применяйте migrate reset или автоматический resolve; сначала выясните состояние схемы.
  • Ошибка готовности backend: неисправный backend останавливается. Старый image автоматически не запускается — он может быть несовместим с новой схемой.
  • Ошибка frontend: исправный backend остаётся работающим, БД не восстанавливается.
  • После жёсткого прерывания migration может ещё работать: перед любым копированием или восстановлением проверьте контейнеры и остановите писателей.

Посмотрите docker ps -a и .deploy/pending. Для диагностики соответствующего контейнера используйте локально docker logs <container>; перед передачей логов убедитесь, что в них нет чувствительных данных.

Ручной откат и восстановление

deploy.sh не является автоматическим rollback: выбор старого тега сам по себе не доказывает совместимость со схемой. Сначала проверьте план на отдельной копии данных с прежним ключом, другим Compose project и отдельным портом.

Подготовьте снимок выбранного совместимого тега для ручных Compose-команд:

RECOVERY_BUNDLE=$(mktemp -d)
git archive vCOMPATIBLE.VERSION.HERE | tar -x -C "$RECOVERY_BUNDLE"
unset FRONTEND_IMAGE BACKEND_IMAGE COMPOSE_FILE COMPOSE_PROJECT_NAME COMPOSE_PROFILES
COMPOSE=(docker compose --project-name wealthledger \
  --env-file /opt/wealthledger/production.env \
  --env-file "$RECOVERY_BUNDLE/release.env" -f "$RECOVERY_BUNDLE/compose.yaml")

Замените демонстрационный тег настоящим. Используйте Bash и реальные абсолютные пути. Для image rollback без изменения данных:

"${COMPOSE[@]}" stop backend migration
"${COMPOSE[@]}" pull backend
"${COMPOSE[@]}" up -d --no-deps --wait --wait-timeout 120 backend

Для frontend аналогично выполняются pull frontend и up ... frontend. Migration при image rollback намеренно не запускается.

Restore — отдельное решение с потерей всех записей после выбранного backup. После проверки целостности выбранной копии и наличия её ключа, при остановленных писателях сохраните текущие данные под новым именем, не удаляя их:

"${COMPOSE[@]}" stop backend migration
mv /opt/wealthledger/data /opt/wealthledger/data-before-restore-UNIQUE_TIMESTAMP
cp -a /opt/wealthledger/backups/CHOSEN_BACKUP/data /opt/wealthledger/data
"${COMPOSE[@]}" up -d --no-deps --force-recreate --wait --wait-timeout 120 backend

Подставьте уникальное ещё не существующее имя и конкретный backup. Убедитесь, что backend именно пересоздан: после замены bind-каталога простой stop/start может сохранить mount прежнего каталога и вернуть более новые данные. Проверьте owner 1000:1000, PRAGMA integrity_check, доступность данных, auth, карты и расшифровку подключения. Убедитесь, что восстановленный image совместим со схемой; старые migration-файлы не являются down-migrations.

Только после проверки успешного recovery переместите .deploy/pending в файл инцидента, например .deploy/recovered-UNIQUE_TIMESTAMP, и повторите smoke. Если новый релиз ещё не установлен, текущая запись может оставаться прежней: следующее обновление сверяется с реальными контейнерами. Файл lock не удаляйте: блокировка освобождается процессом; удаление файла при живом процессе опасно.

Резервные копии

Скрипт создаёт уникальный каталог и не перезаписывает прежние копии. Готовой копия становится только после полного успешного cp -a; частичные копии отмечены префиксом .partial-. Проверяйте восстановление на отдельной копии.

Очистка только ручная. Контролируйте свободное место; не удаляйте backup, нужный незавершённому обновлению. Копия на том же диске не защищает от его потери. Независимое хранение ключа обязательно; внешнее backup-хранилище сюда не входит.

Выпуск комплекта и проверки

  1. Дождитесь публикации компонентов в Nexus. В release.env закрепите ровно FRONTEND_IMAGE и BACKEND_IMAGE с version tags. Не используйте latest.

  2. Выполните локальный gate (Python 3 нужен только для tests):

    bash -n deploy.sh tests/deploy.sh
    bash tests/deploy.sh
    git diff --check
    

    Tests используют настоящий Git, backup-файлы и file locks, а Docker заменяют управляемым double. Проверяются полные повторные updates, настройки, ключи, ошибки pull/backup/migration/readiness, конкуренция и незавершённая операция. Отдельная проверка реального Docker для restore: bash tests/deploy.sh --docker-restore. Она создаёт временный project, заменяет bind-каталог и проверяет пересоздание контейнера. На arm64 для проверки текущих amd64 images можно использовать DOCKER_DEFAULT_PLATFORM=linux/amd64 при наличии Docker emulation.

  3. На disposable Linux-установке с настоящими images проверьте --init, adoption, frontend-only/backend-only update, повтор, backup/restore и HTTPS smoke. Сверьте OCI revision images с release commits компонентов. Для проверки кандидата используйте временный Git origin/tag, не двигайте опубликованный тег.

  4. После review и проверок примите commit в main, создайте аннотированный vX.Y.Z именно на проверенном commit и отправьте этот тег. Версия комплекта самостоятельная: одинаковые номера frontend/backend не требуются.

Выпуск компонента не выпускает комплект и не обновляет сервер автоматически. Опубликованные Git и Nexus tags не переназначаются. Для исправления нужен новый релиз комплекта. В репозитории не нужны npm, собственный release framework или pipeline, автоматически выбирающий последние образы.