VPS

Как сделать резервную копию Docker volume и восстановить данные

Архивируем именованный том Docker, проверяем SHA-256 и восстанавливаем файлы в новый том перед переключением Compose.

Архив переносится из исходного тома Docker в отдельный том

Именованный том Docker хранит файлы независимо от жизненного цикла контейнера. Для переноса файлового тома сделайте архив через вспомогательный контейнер, восстановите его в отдельный том и проверьте данные. Контрольное восстановление позволяет обнаружить пустой архив, неверное имя тома и проблемы с правами до переключения рабочего приложения.

Определить, что нужно копировать

docker volume ls
docker inspect myapp --format '{{range .Mounts}}{{println .Type .Name .Source .Destination}}{{end}}'

Подставьте имя контейнера. Смотрите на Type, Name и Destination. Для volume берите точное имя из Name. Compose обычно добавляет префикс проекта, поэтому uploads в файле и myproject_uploads в Docker могут обозначать один том. Для bind исходник — каталог хоста в Source. Такие файлы копируют средствами хоста с учётом владельцев, ACL и символьных ссылок.

Этот сценарий подходит обычным файлам, например загрузкам приложения. Для активной PostgreSQL применяйте логическую выгрузку и проверку восстановления. Для другой базы используйте поддерживаемый ею способ согласованного резервирования. Архив каталога базы во время записи может содержать несовместимые данные и журнал транзакций.

Остановить запись и создать архив

Остановите все процессы, которые пишут в выбранный том, включая фоновые обработчики. В Compose для этого можно остановить конкретные сервисы через docker compose stop app worker, подставив имена из docker compose config --services. Подключение readonly в команде архивации защищает исходник от действий вспомогательного контейнера. Остальные контейнеры сохраняют свои права записи.

Пример рассчитан на обычный Docker Engine, запущенный от root. Выполняйте блоки архивации и восстановления в одной отдельной оболочке администратора на хосте Docker, например открыв её через sudo -i. Это позволит прочитать закрытый архив, который создаёт вспомогательный контейнер. Если CLI подключён к удалённому демону, локальный временный каталог клиента недоступен демону.

set -eu
src=myproject_uploads
stamp=$(date -u +%Y%m%dT%H%M%SZ)
work=$(mktemp -d)
archive="uploads-$stamp.tar.gz"

docker volume inspect "$src" >/dev/null
docker pull alpine:3
docker run --rm --network none \
  --mount "type=volume,src=$src,dst=/data,readonly" \
  --mount "type=bind,src=$work,dst=/backup" \
  -e ARCHIVE="$archive" alpine:3 \
  sh -ec 'umask 077; tar -C /data -czf "/backup/$ARCHIVE.part" .; mv "/backup/$ARCHIVE.part" "/backup/$ARCHIVE"'

Файл .part помогает отличить прерванную запись от законченного архива. Docker создаёт отсутствующие именованные тома при некоторых вариантах запуска, поэтому docker volume inspect заранее проверяет имя источника. Для автоматизации закрепите проверенный digest вспомогательного образа и контролируйте ошибки загрузки.

Проверьте содержимое и сохраните контрольную сумму вместе с архивом. Рабочие сервисы можно вернуть в работу после завершения чтения тома и проверки архива.

tar -tzf "$work/$archive" > "$work/$archive.list"
sed -n '1,30p' "$work/$archive.list"
(cd "$work" && sha256sum "$archive" > "$archive.sha256")

Перед отправкой архива проверьте, что среди его путей есть ожидаемые файлы. Храните постоянную копию в защищённом хранилище с подходящими правами и шифрованием. Если используете S3, проверьте доступ на чтение и контрольную сумму после скачивания. Временные файлы на VPS удаляйте после этой проверки.

Восстановить в новый том

Получите архив и файл контрольной суммы из хранилища. В примере они уже лежат в $work. При восстановлении на другом хосте задайте заново work с путём к закрытому временному каталогу, archive с именем скачанного файла и stamp для имени нового тома. Проверка на существование защищает от распаковки в старый или уже подключённый каталог. Выполняйте блок в оболочке с set -e, чтобы ошибка проверки остановила дальнейшие команды.

dest="uploads_restore_$stamp"
if docker volume inspect "$dest" >/dev/null 2>&1; then
  printf 'Том уже существует: %s\n' "$dest" >&2
  exit 1
fi
(cd "$work" && sha256sum -c "$archive.sha256")
docker volume create "$dest"
docker run --rm --network none \
  --mount "type=volume,src=$dest,dst=/restore" \
  --mount "type=bind,src=$work,dst=/backup,readonly" \
  -e ARCHIVE="$archive" alpine:3 \
  sh -ec 'tar -xzf "/backup/$ARCHIVE" -C /restore; ls -lan /restore'

Распаковывайте только архив из доверенного источника. Для SELinux, rootless Docker или томов с особыми атрибутами проверьте права и владельцев отдельно. Если приложению нужны расширенные атрибуты или ACL, используйте архиватор, который умеет сохранить и восстановить их, и испытайте этот вариант до миграции.

Проверить приложение и переключить том

Проверьте наличие контрольных файлов и их SHA-256, числовые UID/GID и чтение от имени пользователя приложения. Для реальных данных лучше поднять копию приложения с новым томом, открыть несколько файлов и проверить запись в выделенный тестовый каталог. Уберите тестовый файл после проверки.

При переключении Compose можно явно указать уже созданный том:

services:
  app:
    volumes:
      - uploads:/app/uploads
volumes:
  uploads:
    external: true
    name: uploads_restore_20261106T090000Z

Это фрагмент существующего файла. Подставьте точное имя $dest, сохраните остальные параметры сервиса и проверьте docker compose config. Пересоздайте только нужный сервис командой docker compose up -d --no-deps app. После переключения проверьте старые загрузки и новые записи. Оставьте рабочий исходный том доступным до окончания проверки. docker compose down -v удаляет объявленные в проекте тома, поэтому для обычной остановки используйте stop. Подготовить исходное окружение поможет руководство по установке Docker.

На стенде мы упаковали тестовый том, проверили SHA-256 и восстановили файлы в новый том. Содержимое, числовые UID и GID и режим доступа файла совпали.

Первоисточники

Нашли неточность?

Сообщите адрес статьи и фрагмент через контакты редакции.