Как перенести тома только для данных с одного хоста на другой?

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

По сути, это звучит потрясающе. Но есть одна вещь, которую я не понимаю.

Эти тома (которые явно не отображаются в папку на хосте по причинам переносимости, как указано в документации) создаются и управляются Docker в некоторой внутренней папке на хосте (/var/docker/volumes/…).

Предположим, я использую такой том, а затем мне нужно перенести его с одного хоста на другой - как мне перенести том? AFAICS у него есть уникальный идентификатор - могу ли я просто скопировать том и соответствующий ему контейнер только для данных на новый хост? Как узнать, какие файлы копировать? Или в Docker есть встроенная поддержка, которую я еще не обнаружил?

12 ответов

Решение

Официальный ответ теперь доступен здесь:

Совместное использование каталогов с использованием томов

В разделе "Резервное копирование, восстановление или миграция томов данных" у вас есть:

РЕЗЕРВНОЕ КОПИРОВАНИЕ:

sudo docker run --rm --volumes-from DATA -v $(pwd):/backup busybox tar cvf /backup/backup.tar /data
  • --rm: удалить контейнер при выходе
  • --volumes-from DATA: присоединить к томам, совместно используемым контейнером DATA
  • -v $(pwd):/backup: bind смонтировать текущий каталог в контейнер; записать файл tar в
  • busybox: небольшое простое изображение - хорошо для быстрого обслуживания
  • tar cvf /backup/backup.tar /data: создает несжатый tar-файл из всех файлов в каталоге /data

ВОССТАНОВИТЬ:

# create a new data container
$ sudo docker create -v /data --name DATA2 busybox true
# untar the backup files into the new container᾿s data volume
$ sudo docker run --rm --volumes-from DATA2 -v $(pwd):/backup busybox tar xvf /backup/backup.tar
data/
data/sven.txt
# compare to the original container
$ sudo docker run --rm --volumes-from DATA -v `pwd`:/backup busybox ls /data
sven.txt

Расширяя официальный ответ из документации Docker и верхний ответ здесь, вы можете иметь следующие псевдонимы в вашем.bashrc или.zshrc

# backup files from a docker volume into /tmp/backup.tar.gz
function docker-volume-backup-compressed() {
  docker run --rm -v /tmp:/backup --volumes-from "$1" debian:jessie tar -czvf /backup/backup.tar.gz "${@:2}"
}
# restore files from /tmp/backup.tar.gz into a docker volume
function docker-volume-restore-compressed() {
  docker run --rm -v /tmp:/backup --volumes-from "$1" debian:jessie tar -xzvf /backup/backup.tar.gz "${@:2}"
  echo "Double checking files..."
  docker run --rm -v /tmp:/backup --volumes-from "$1" debian:jessie ls -lh "${@:2}"
}
# backup files from a docker volume into /tmp/backup.tar
function docker-volume-backup() {
  docker run --rm -v /tmp:/backup --volumes-from "$1" busybox tar -cvf /backup/backup.tar "${@:2}"
}
# restore files from /tmp/backup.tar into a docker volume
function docker-volume-restore() {
  docker run --rm -v /tmp:/backup --volumes-from "$1" busybox tar -xvf /backup/backup.tar "${@:2}"
  echo "Double checking files..."
  docker run --rm -v /tmp:/backup --volumes-from "$1" busybox ls -lh "${@:2}"
}

Обратите внимание, что резервная копия сохраняется в /tmpТаким образом, вы можете переместить файл резервной копии, сохраненный там, между хостами Docker

Существует также две пары псевдонимов резервного копирования / восстановления. Один использует сжатие и debian:jessie, а другой без сжатия, но с busybox. Используйте сжатие, если файлы для резервного копирования большие.

Вы можете экспортировать том в tar и перенести на другую машину. И импортируйте данные с помощью tar на второй компьютер. Это не зависит от деталей реализации томов.

# you can list shared directories of the data container
docker inspect <data container> | grep "/vfs/dir/"

# you can export data container directory to tgz
docker run --cidfile=id.tmp --volumes-from <data container> ubuntu tar -cO <volume path> | gzip -c > volume.tgz

# clean up: remove exited container used for export and temporary file
docker rm `cat id.tmp` && rm -f id.tmp

Только что написал команду docker-volume-snapshot для аналогичного варианта использования. Эта команда основана на ответе tommasop.

С командой,

  1. Создать снимок
      docker-volume-snapshot create <volume-name> snapshot.tar
  1. Переместить snapshot.tar на другой хост
  2. Восстановить снимок
      docker-volume-snapshot restore snapshot.tar <volume-name>

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

Cargo был разработан для переноса контейнеров с одного хоста на другой хост с их данными с минимальным временем простоя. Cargo использует возможности объединения данных файловой системы union для создания унифицированного представления данных (главным образом корневой файловой системы) на исходном и целевом хостах. Это позволяет Cargo запускать контейнер практически сразу (в течение миллисекунд) на целевом хосте, поскольку данные из исходной корневой файловой системы копируются на целевые хосты либо по требованию (с использованием раздела копирования при записи (COW)), либо лениво в фоновом режиме (используя rsync).

Важными моментами являются: centralized сервер обрабатывает процесс миграции

Ссылка на проект приведена здесь:

https://github.com/nadgowdas/cargo

Вот однострочный вариант на тот случай, если между машинами может быть установлено SSH-соединение:

      docker run --rm -v <SOURCE_DATA_VOLUME_NAME>:/from alpine ash -c "cd /from ; tar -cf - . " | ssh <TARGET_HOST> 'docker run --rm -i -v <TARGET_DATA_VOLUME_NAME>:/to alpine ash -c "cd /to ; tar -xpvf - " '

Кредиты отправляются на пост Гвидо Дипена .

Если ваши машины находятся в разных VPC или вы хотите копировать с / на локальный компьютер (как в моем случае), вы можете использовать созданный мной dvsync. Это в основном нгрок в сочетании с rsync через SSH упакованы в два небольших (оба ~25 МБ) изображения. Во-первых, вы начинаете dvsync-server на машине, с которой вы хотите скопировать данные (вам понадобится NGROK_AUTHTOKEN который может быть получен из панели инструментов ngrok):

$ docker run --rm -e NGROK_AUTHTOKEN="$NGROK_AUTHTOKEN" \
  --mount source=MY_VOLUME,target=/data,readonly \
  quay.io/suda/dvsync-server

Тогда вы можете начать dvsync-client на машине, на которую вы хотите скопировать файлы, передавая DVSYNC_TOKEN показывается сервером:

docker run -e DVSYNC_TOKEN="$DVSYNC_TOKEN" \
  --mount source=MY_TARGET_VOLUME,target=/data \
  quay.io/suda/dvsync-client 

Как только копирование будет выполнено, клиент выйдет. Это работает также с Docker CLI, Compose, Swarm и Kubernetes.

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

Зачем вам нужно копировать файл в папку ?

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

Копирование содержимого в named docker volume

  1. На хост-компьютере следуйте инструкциям из принятого ответа или по документации по томам докеровтомам докеров,документации чтобы создать файл и отправить его в какой-либо репозиторий.

  2. Вытащите на машину соавтора из репозитория.

  3. На компьютере соавтора создайте временный контейнер и именованный том докера.

docker run -v named_docker_volume:/dbdata --name temp_db_container ubuntu /bin/bash

  • --name temp_db_container : Создать контейнер с именем

  • ubuntu /bin/bash : Использовать ubuntu образ для сборки с командой запуска /bin/bash

  • -v named_docker_volume:/dbdata: Смонтируйте папку в том докера с именем. Мы используем этот специально названный том, чтобы он соответствовал имени тома, указанному в нашем docker-compose.yml файл.

  1. На компьютере соавтора скопируйте содержимое в названный том докера.

docker run --rm --volumes-from temp_db_container -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

  • --volumes-from temp_db_container: папка контейнера была сопоставлена ​​с томом на предыдущем шаге. Таким образом, любой файл, который хранится в папке, будет немедленно скопирован в named_docker_volume объем докера.
  • -v $(pwd):/backup : сопоставить текущий рабочий каталог локального компьютера с /backup папка, расположенная внутри
  • ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1" : Разверните backup.tar файл и хранить неупакованное содержимое внутри /dbdata папка.
  1. На машине соавтора очистите временный контейнер temp_db_container

docker rm temp_db_container

Я остался недоволен ответом using. Я решил взять дело в свои руки. Поскольку я собираюсь часто синхронизировать данные, а они будут большими, я специально хотел их использовать. С использованием tar отправлять все данные каждый раз было бы пустой тратой времени и переносить.

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

  • запустите два контейнера докеров - один в источнике, другой в месте назначения, каждый с одним смонтированным томом - исходный том и целевой том.
  • запустить rsync --deamon на одном из контейнеров, который будет передавать / загружать данные с тома
  • запустить docker exec source_container socat - TCP:localhost и беги docker exec desintation_container socat TCP-LISTEN:rsync -и соедините оба этих stdin и stdout . Таким образом, один подключается и перенаправляет данные из / в stdout / stdin, другой слушает :rsyncпорт (порт 873) и перенаправление на / из stdin / stdout. Затем соедините их вместе, так что в основном мы передаем данные из одного порта контейнера в другой.
  • затем запустите другой том rsync клиент, который будет подключаться к localhost:rsync, эффективное подключение через " socat труба "к rsync --daemon.

В основном это работает так:

      log "Running both destination and source containers"
src_did=$(
    env DOCKER_HOST=$src_docker_host docker run --rm -d -i -v \
    "$src_volume":/data:ro -w /data alpine_with_rsync_and_socat\
    sleep infinity
)
dst_did=$(
    env DOCKER_HOST=$dst_docker_host docker run --rm -d -i -v \
    "$dst_volume":/data:rw -w /data alpine_with_rsync_and_socat \
    sleep infinity
)

log "Running rsyncd on destination container"
    env DOCKER_HOST=$dst_docker_host docker exec "$dst_did" sh -c "
        cat <<EOF > /etc/rsyncd.conf &&
uid = root
gid = root
use chroot = no
max connections = 1
numeric ids = yes
reverse lookup = no
[data]
path = /data/
read only = no
EOF
        rsync --daemon
    "

log "Setup rsync socat forwarding between containers"
{
    coproc { env DOCKER_HOST=$dst_docker_host docker exec -i "$dst_did" \
       socat -T 10 - TCP:localhost:rsync,forever; }
    env DOCKER_HOST=$src_docker_host docker exec -i "$src_did" \
       socat -T 10 TCP-LISTEN:rsync,forever,reuseaddr - <&"${COPROC[0]}" >&"${COPROC[1]}"
} &

log "Running rsync on source that will connect to destination"
env DOCKER_HOST=$src_docker docker exec -e RSYNC_PASSWORD="$g_password" -w /data "$src_did" \
    rsync -aivxsAHSX --progress /data/ rsync://root@localhost/data

Еще одна действительно хорошая вещь в этом подходе заключается в том, что вы можете копировать данные между двумя удаленными хостами, никогда не сохраняя данные локально. Тоже делюсь сценарием ,docker-rsync-volumesчто я написал вокруг этой идеи. С помощью этого скрипта копировать том с двух удаленных хостов просто. ,docker-rsync-volumes --delete -f ssh://user@productionserver grafana_data -t ssh://user@backupserver grafana_data_backup.

Этот ssh копирует ваш том с одного сервера на другой.

      docker run --rm -v $VOLUME:/$VOLUME alpine tar -czv --to-stdout -C /$VOLUME . | ssh $REMOTEHOST "docker run --rm -i -v $VOLUME:/$VOLUME alpine tar xzf - -C /$VOLUME"

Если вы хотите скопировать более одного тома, соответствующего фильтру.

      REMOTEHOST=root@123.123.123.123

Volumes=($(docker volume ls --filter "name=mailcow*" --format="{{.Name}}"))

for VOLUME in ${Volumes[@]}; do
   docker run --rm -v $VOLUME:/$VOLUME alpine tar -czv --to-stdout -C /$VOLUME . | ssh $REMOTEHOST "docker run --rm -i -v $VOLUME:/$VOLUME alpine tar xzf - -C /$VOLUME"
done

На github есть репозиторий, в котором утилита управляет экспортом / загрузкой томов.

Адаптировано из принятого ответа, но дает больше гибкости, поскольку вы можете использовать его в конвейере bash:

      #!/bin/bash

if [ $# != 2 ]; then
    echo Usage "$0": volume /path/of/the/dir/in/volume/to/backup
    exit 1
fi

if [ -t 1 ]; then
    echo The output of the cmd is binary data "(tar)", \
         and it should be redirected instead of printed to terminal
    exit 1
fi

volume="$1"
path="$2"

exec docker run --rm --mount type=volume,src="$volume",dst=/mnt/volume/ alpine tar cf - . -C /mnt/volume/"$path"

Если вы хотите периодически и постепенно создавать резервные копии тома, вы можете использовать следующий сценарий:

      #!/bin/bash

if [ $# != 3 ]; then
    echo Usage "$0": volume /path/of/the/dir/in/volume/to/backup /path/to/put/backup
    exit 1
fi

volume="$1"
volume_path="$2"
path="$3"

if [[ "$path" =~ ^.*/$ ]]; then
    echo "The 3rd argument shouldn't end in '/', otherwise rsync would not behave as expected"
    exit 1
fi

container_name="docker-backup-rsync-service-$RANDOM"
docker run --rm --name="$container_name" -d -p 8738:873 \
    --mount type=volume,src="$volume",dst=/mnt/volume/ \
    nobodyxu/rsyncd

echo -e '\nStarting syncing...'

rsync --info=progress2,stats,symsafe -aHAX --delete \
    "rsync://localhost:8738/root/mnt/volume/$volume_path/"  "$path"
exit_status=$?

echo -e '\nStopping the rsyncd docker...'
docker stop -t 1 "$container_name"

exit $exit_status

Он использует rsyncсерверные и клиентские функции для прямой синхронизации каталога между томом и каталогом вашего хоста.

Другие вопросы по тегам