Files
minecraft-lab/docs/backups.md
T
2026-10-04 00:30:09 +07:00

7.9 KiB

Backup и восстановление — Phase 5

./mcpack backup работает с полным релизом и runtime, который уже связан с ним через scripts/server.sh. Нужны Node/npm dependencies, закреплённый Compose, Docker daemon, GNU tar и zstd. Оператор должен читать весь runtime и сохранять владельцев при распаковке: запускать от владельца данных или с необходимыми правами. Проверка UID/GID не пропускается.

Создание snapshot

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>/:

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.

Snapshot не удаляется автоматически. Нужны свободное место под полный runtime, пробную распаковку и копию релиза; операция завершается ошибкой при нехватке места. Символические/жёсткие ссылки и специальные файлы в runtime сейчас отклоняются. Команды вне wrapper не участвуют в блокировке; во время backup не изменять runtime вручную и не запускать контейнер прямым Compose.

Восстановление в отдельный каталог

./mcpack restore \
  --backup /absolute/server-root/backups/TIMESTAMP-UUID \
  --destination /absolute/restored-server

Destination должен не существовать. Команда сначала проверяет snapshot, распаковывает во временный соседний каталог, сверяет bytes/mode/UID/GID, проверяет сохранённый релиз и публикует новый root атомарным rename. Исходный runtime не изменяется. Результат:

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 сохраняются):

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.