При использовании Docker часто возникает необходимость создавать резервные копии данных, хранящихся в томах, или дублировать их в другие тома для тестирования.

Может возникнуть мысль просто использовать команду docker cp, но эта команда поддерживает только копирование между файловой системой контейнера и хостом и не может получить доступ к управляемым Docker томам напрямую.

В этой статье мы рассмотрим правильный способ копирования Docker томов. Мы не просто перечислим команды, но и сосредоточимся на ‘почему’ именно этот подход должен использоваться. Поняв этот принцип, вы сможете применять его естественно, без необходимостив запоминать команды.

Суть принципа проста.

Самый безопасный и ‘докерный’ способ манипуляции с Docker томами – это использовать ‘временный контейнер’, который может получить доступ к этому тому через мост (bridge).


1. Копирование существующего тома в новый том (Volume-to-Volume)



Это самый распространенный сценарий. Вы можете захотеть дублировать работающий том db_data в тестовый том db_data_test.

🤔 ПОЧЕМУ: Зачем использовать временный контейнер?

Docker тома хранятся где-то в файловой системе хоста (например, /var/lib/docker/volumes/...), но Docker demon управляет этим путем. Не рекомендуется напрямую обращаться к этому пути с командой cp, так как это может привести к проблемам с разрешениями или целостностью данных.

Вместо этого мы запускаем временный контейнер с двумя одновременно смонтированными томами.

  1. Контейнер монтирует оригинальный том (source_volume) по пути /from.

  2. Контейнер монтирует целевой том (new_volume) по пути /to.

  3. Как только контейнер запустится, он выполняет простую команду Linux (cp или tar), чтобы скопировать все данные из /from в /to.

  4. После завершения команда контейнер автоматически уничтожается (--rm опция).

Этот контейнер используется исключительно как ‘инструмент’ для копирования данных.

🚀 КАК: Пример команды

Пример копирования данных из тома source_data в том target_data.

  1. Создание тестового тома (по желанию)
docker volume create source_data
docker volume create target_data
# (предположим, что в source_data есть данные.)
  1. Копирование с использованием временного контейнера
docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cp -a /from/. /to/"

💡 Объяснение команды

  • docker run --rm: Флаг --rm означает, что контейнер будет сразу удален после завершения своей работы. Это критично для временных задач.

  • -v source_data:/from: Монтирует том source_data в директории /from в контейнере.

  • -v target_data:/to: Монтирует том target_data в директории /to в контейнере.

  • alpine: Использует очень легкий образ Linux alpine, содержащий основные утилиты, такие как cp и sh.

  • sh -c "...": Команда, которая будет выполнена при запуске контейнера alpine.

  • cp -a /from/. /to/:

    • -a (архив): Этот флаг важен. Он копирует все атрибуты, включая права доступа, временные метки и владельца, в отличие от простой копии (cp -r). Это очень важно, когда вы работаете с чувствительными данными, такими как файлы баз данных.

    • /from/.: Это не относится к директории /from, а относится к всем содержимым внутри /from (включая скрытые файлы).


2. Копирование данных тома в файловую систему хоста (резервное копирование)

Используется, когда вы хотите сделать резервную копию данных из тома в определенную директорию на локальном компьютере или сервере, например, в виде файла .tar.

🤔 ПОЧЕМУ: Как это работает?

Принцип такой же, как и в пункте 1. Разница лишь в том, что целью является не ‘Docker том’, а ‘директория на хосте’.

Docker поддерживает функцию привязанного монтирования (Bind Mount), которая монтирует определенную директорию хоста в контейнер.

  1. Контейнер монтирует оригинальный том (source_volume) по пути /data.

  2. Контейнер монтирует определенную директорию хоста ($(pwd)/backup) по пути /backup.

  3. Контейнер копирует (или сжимает) содержание /data в директорию /backup.

  4. Хотя операция происходит внутри контейнера, директория /backup связана с реальной директорией на хосте, поэтому результаты остаются на хосте.

🚀 КАК: Пример команды

Копирует данные из тома source_data в директорию backup в текущем местоположении ($(pwd)).

# Создание директории для резервного копирования на хосте
mkdir -p $(pwd)/backup

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd)/backup:/backup \
       alpine \
       cp -a /data/. /backup/

💡 Объяснение команды

  • -v source_data:/data:ro: Мы добавили флаг :ro (только для чтения). Так как для резервного копирования данные нужно только читать, рекомендуется монтировать в режиме только для чтения, чтобы избежать случайного изменения оригинального тома.

  • -v $(pwd)/backup:/backup: В отличие от source_data (имя тома), / или $(pwd) (текущий путь) начинается с абсолютного/относительного пути, который указывает на директорию хоста.


3. Основные советы по копированию (Tips)



Совет 1: Использование tar для эффективного копирования (сжатое резервное копирование)

Использование tar вместо команды cp имеет несколько преимуществ. Особенно это полезно, когда вы хотите запаковать данные в архивный файл (.tar.gz) за раз.

Volume-to-Volume (используя tar)

Может быть быстрее, чем cp, особенно когда файлов много.

docker run --rm \
       -v source_data:/from \
       -v target_data:/to \
       alpine \
       sh -c "cd /from && tar -cf - . | (cd /to && tar -xf -)"
  • cd /from && tar -cf - .: Переход к /from и упаковка содержимого текущей директории (.) с помощью tar, отправляя это в стандартный вывод (-).

  • | (cd /to && tar -xf -): Получает стандартный вывод через пайп (|) и распаковывает его в директории /to с помощью tar (опция x).

Volume-to-Host (сжатое резервное копирование)

Содержимое тома source_data сжимается в файл backup.tar.gz и сохраняется на хосте.

docker run --rm \
       -v source_data:/data:ro \
       -v $(pwd):/backup \
       alpine \
       tar -czf /backup/backup.tar.gz -C /data .
  • tar -czf /backup/backup.tar.gz ...: c (создание), z (gzip сжатие), f (в файл) создает файл /backup/backup.tar.gz.

  • -C /data .: Эта часть важна. Сначала переходит в директорию /data, а затем сжимает все внутри нее (.

    ) Это помогает избежать захвата ненужного пути /data внутри tar файла.

Совет 2: Восстановление файлов хоста в том

Противоположное резервному копированию, восстановление также использует тот же принцип. Просто меняем направление cp.

# Восстановление данных из директории $(pwd)/backup в новый том new_data
docker run --rm \
       -v new_data:/data \
       -v $(pwd)/backup:/backup:ro \
       alpine \
       cp -a /backup/. /data/

Резюме

Ключ к работе с Docker томами заключается в “использовании контейнеров как инструментов”. Вместо того, чтобы обращаться к файлам томов напрямую, запускайте временный контейнер с необходимыми томами и директориями, чтобы безопасно выполнять стандартные команды Linux, такие как cp или tar внутри него.

Запомните этот принцип, и вы сможете свободно копировать, резервировать и восстанавливать данные томов в любой ситуации.