first cycle lab release

This commit is contained in:
2026-10-04 00:30:09 +07:00
parent 85f6897365
commit d134daafd8
92 changed files with 5623 additions and 9 deletions
+118
View File
@@ -0,0 +1,118 @@
# Backup и восстановление — Phase 5
`./mcpack backup` работает с полным релизом и runtime, который уже связан
с ним через `scripts/server.sh`. Нужны Node/npm dependencies, закреплённый
Compose, Docker daemon, GNU tar и zstd. Оператор должен читать весь runtime
и сохранять владельцев при распаковке: запускать от владельца данных или
с необходимыми правами. Проверка UID/GID не пропускается.
## Создание snapshot
```bash
export MC_ROOT=/absolute/server-root
export MC_RELEASE_DIR=/absolute/full-release
# MC_ENV_FILE — необязательный абсолютный путь, по умолчанию MC_ROOT/.env.
./mcpack backup --wait-timeout 120
```
Команда удерживает общую `.mcpack-runtime.lock`, проверяет релиз/settings,
останавливает сервер через Compose и подтверждает остановку по Docker state.
После этого архивирует **весь `MC_ROOT/runtime` без исключений**: world,
данные модов вне world, конфиги, server.properties, whitelist/operators,
логи, cache, downloads и установленные server/mod JAR. Для NeoForge безопасные
исключения пока не подтверждены. Releases, snapshots и host `.env` находятся
вне runtime и не входят в архив; внутри snapshot хранится отдельная полная
копия исходного релиза, включая его `.env.example`.
Результат находится в `MC_ROOT/backups/<UTC timestamp>-<UUID>/`:
```text
runtime.tar.zst
metadata.json
SHA256SUMS
release/ # исходный полный релиз с собственными checksums
```
Metadata фиксирует исходный релиз, SHA256 manifest/checksum list, закреплённый
image, целевой релиз (если передан `--target-release /absolute/release`),
прежнее состояние сервера, подтверждение остановки, время, исключения,
архив SHA256/размер и inventory путей/хешей/размеров/mode/UID/GID runtime.
`--target-release` только проверяет и записывает назначение будущего deployment;
команда backup сама не применяет новый релиз.
Перед публикацией выполняются tar/zstd listing, проверка типов/путей и
пробная распаковка с точным сравнением inventory. Checksums покрывают все
файлы snapshot и сохранённого релиза. Каталог публикуется атомарным rename
внутри backups; незавершённый snapshot не появляется под окончательным именем.
При успехе ранее запущенный сервер возвращается на тот же релиз через
`up --wait`. Остановленный сервер или отсутствующий контейнер не запускаются.
Ошибка backup возвращает non-zero. При ошибке после успешной остановки сервер
остаётся остановленным; оператор получает ошибку и status в
`MC_ROOT/.mcpack-backup-operation.json`. Ошибка resume сохраняет опубликованный
проверенный snapshot и пытается снова остановить сервер. Новый deployment
должен использовать `backupBeforeApply` из `platform/backups.mjs`: callback
применения допускается только после публикации snapshot и под той же блокировкой.
Этот gate проверен тестами и используется SSH deployment Phase 7 под общей
блокировкой всей операции: [deploy.md](deploy.md).
Snapshot не удаляется автоматически. Нужны свободное место под полный runtime,
пробную распаковку и копию релиза; операция завершается ошибкой при нехватке места.
Символические/жёсткие ссылки и специальные файлы в runtime сейчас отклоняются.
Команды вне wrapper не участвуют в блокировке; во время backup не изменять
runtime вручную и не запускать контейнер прямым Compose.
## Восстановление в отдельный каталог
```bash
./mcpack restore \
--backup /absolute/server-root/backups/TIMESTAMP-UUID \
--destination /absolute/restored-server
```
Destination должен **не существовать**. Команда сначала проверяет snapshot,
распаковывает во временный соседний каталог, сверяет bytes/mode/UID/GID,
проверяет сохранённый релиз и публикует новый root атомарным rename.
Исходный runtime не изменяется. Результат:
```text
restored-server/runtime/
restored-server/release/
restored-server/.mcpack-runtime.json
restored-server/restore-report.json
```
Host settings и EULA acceptance из snapshot не восстанавливаются; сервер
автоматически не запускается. Для ручного recovery подготовить `.env` из
`release/server/.env.example`, задать прежние UID/GID, подходящие memory/port
и принятие EULA. Используется прежний стабильный Compose project из binding.
Прежде чем запускать восстановленную копию под тем же project, остановить
и удалить **старый контейнер** через wrapper (данные старого root сохраняются):
```bash
MC_ROOT=/absolute/original-server \
MC_RELEASE_DIR=/absolute/original-release scripts/server.sh down
# На данном host settings уже настроены и EULA принята:
export MC_ROOT=/absolute/restored-server
export MC_RELEASE_DIR="$MC_ROOT/release"
export MC_ENV_FILE=/absolute/prepared-host-settings.env
scripts/server.sh up -d --wait --wait-timeout 120
scripts/server.sh exec -T minecraft mc-health
scripts/server.sh logs --tail 100
```
Не заменять binding или release на более новую версию: восстановленный мир
нужно запускать с сохранённым исходным релизом. Если прежний контейнер ещё
использует другой root, wrapper отклонит запуск. Это ручное восстановление
в отдельный root; переключение active release и rollback — последующие фазы.
## Область проверки
Проверен local Linux/WSL Docker и NeoForge 21.1.252 / Minecraft 1.21.1.
Primary Phase 0 runtime пока управляется старым spike wrapper без full-release
binding, поэтому его миграция не выполняется этой командой. Off-host копии,
retention, автоматический rollback и защита от внезапного отключения питания
во время записи (fsync) остаются последующими улучшениями.
Реальный опыт восстановления и свидетельства: [phase5-results.md](phase5-results.md).