18 KiB
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 в скрипт не входят.
-
Установите Git, Bash, Docker Engine с Compose plugin (2.24.4 или новее),
flockиз util-linux и стандартныеtar,cp,mktemp. Используется локальный Docker daemon через Unix socket, не удалённый context. -
Настройте внешний HTTPS reverse proxy: весь домен направляется на
127.0.0.1:8080. Отдельный upstream/apiне нужен. Порт можно поменять черезFRONTEND_PORT;FRONTEND_ORIGINдолжен совпадать с HTTPS origin. -
Выберите одного оператора с доступом к Docker, Git origin, ключам и данным. Скрипту нужны права читать всю БД и создавать копии. Процесс backend работает с UID/GID
1000:1000; при другом UID оператора настройте доступ заранее. Запускайте команды из одной и той же учётной записи, чтобы Git и Docker использовали подготовленные SSH-ключи и registry credentials. -
Войдите в Nexus, вводя пароль интерактивно, без записи в shell history:
docker login nexus.personal.ksv741.ru --username wealthledger-ci -
Разместите 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 и при сбое pendinggit 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: существующий файл с ключами не перезаписывайте. -
Заполните настройки защищённым редактором.
DATA_DIRECTORYиTBANK_CA_CERT_FILE— существующие абсолютные пути, не внутри checkout.TBANK_CA_CERT_PATH— путь внутри контейнера; сертификат монтируется read-only. Каталог данных должен быть доступен для записи UID 1000, сертификат — для чтения. Не отключайте проверку TLS вместо установки корректного CA. -
Проверьте доступ к образам, свободное место под полную копию 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
- Проверка тега, настроек, данных и CA; загрузка образов и проверка прав runtime user. Ошибка до остановки сохраняет работающие сервисы.
- Stop backend → копия всего data directory с WAL/SHM → migration →
backend readiness. Только для
--initпустой базы backup не требуется. - Запуск frontend после готовности backend. Каждый вызов выполняет этот путь, включая повтор того же тега и frontend-only update. No-op/change detection отсутствуют; приняты короткий простой API и дополнительный backup.
- Успех записывается в
.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-хранилище сюда не входит.
Выпуск комплекта и проверки
-
Дождитесь публикации компонентов в Nexus. В
release.envзакрепите ровноFRONTEND_IMAGEиBACKEND_IMAGEс version tags. Не используйтеlatest. -
Выполните локальный gate (Python 3 нужен только для tests):
bash -n deploy.sh tests/deploy.sh bash tests/deploy.sh git diff --checkTests используют настоящий 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. -
На disposable Linux-установке с настоящими images проверьте
--init, adoption, frontend-only/backend-only update, повтор, backup/restore и HTTPS smoke. Сверьте OCI revision images с release commits компонентов. Для проверки кандидата используйте временный Git origin/tag, не двигайте опубликованный тег. -
После review и проверок примите commit в
main, создайте аннотированныйvX.Y.Zименно на проверенном commit и отправьте этот тег. Версия комплекта самостоятельная: одинаковые номера frontend/backend не требуются.
Выпуск компонента не выпускает комплект и не обновляет сервер автоматически. Опубликованные Git и Nexus tags не переназначаются. Для исправления нужен новый релиз комплекта. В репозитории не нужны npm, собственный release framework или pipeline, автоматически выбирающий последние образы.