如何将只有数据的卷从一台主机移植到另一台主机?

正如在关于 使用卷的 Docker 文档中所描述的那样,有一个所谓的 只提供资料容器的概念,它提供了一个可以装入多个其他容器的卷,无论仅数据容器是否实际运行。

基本上,这听起来很棒。但有一件事我不明白。

这些卷(由于文档状态的可移植性原因,没有显式地映射到主机上的文件夹)由 Docker 在主机上的某个内部文件夹(/var/docker/volumes/…)中创建和管理。

假设我使用这样一个卷,然后需要将它从一个主机迁移到另一个主机——如何移植该卷?AFAICS 有一个唯一的 ID-我可以直接将卷及其相应的数据容器复制到一个新的主机上吗?我如何找到要复制的文件?或者是否有一些我还没有发现的对 Docker 的内置支持?

120704 次浏览

您可以将卷导出到 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

正式答案见 “备份、还原或迁移数据卷”节:

备份:

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: 将工作目录绑定到容器中,将 tar 文件写入
  • busybox: 一个小的简单的图像-很好的快速维护
  • tar cvf /backup/backup.tar /data: 创建/data 目录中所有文件的未压缩 tar 文件

恢复:

# 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

码头文件这是最佳答案延伸正式答案,你可以在你的 .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 主机之间移动保存在 /tmp中的备份文件。

还有两对备份/恢复别名。一个使用压缩和 debian: jessie 和其他没有压缩,但与 busybox。如果要备份的文件比较大,最好使用压缩。

我将在这里添加另一个来自 IBM 的最新工具,它实际上是为从一个容器主机到另一个容器主机的卷迁移而制作的。这是一个正在进行的项目。因此,将来您可能会发现带有附加特性的不同版本。

Cargo 开发用于在最短的停机时间内将容器及其数据从一个主机迁移到另一个主机。Cargo 使用 联合文件系统联合文件系统的数据联合功能在源和目标主机之间创建数据的统一视图(主要是根文件系统)。这允许 Cargo 在源根文件系统中的数据按需(使用 书面复制(COW)分区)或在后台 (使用 rsync)中延迟地复制到目标主机时,几乎立即(在毫秒内)启动目标主机上的容器。

重点是: - centralized服务器处理迁移过程

该项目的链接如下:

https://github.com/nadgowdas/cargo

如果您的机器位于不同的 VPC 中,或者您想要从/复制到本地机器(就像在我的例子中) ,您可以使用我创建的 Dvsync。它基本上是将 恩格罗克rsync over SSH 组合在一起,打包成两个小的(都是约25MB)映像。首先,在要复制数据的机器上启动 dvsync-server(需要从 Ngrok 仪表盘获得的 NGROK_AUTHTOKEN) :

$ 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

一旦完成复制,客户端就会退出。这与多克 CLI,作曲,群和库伯内特以及工程。

如果可以在机器之间建立 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 - " '

荣誉归于 Guido Diepen 的 邮寄

改编自公认的答案,但是提供了更多的灵活性,因为您可以在 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的服务器和客户端功能直接同步卷和主机目录之间的目录。

我对使用 tar得到的答案不满意。我决定自己解决问题。因为我要经常同步数据,而且数据量很大,所以我特别想使用 rsync。每次使用 tar发送所有数据只是浪费时间和传输。

在花了几天时间研究如何解决两个远程码头集装箱之间的通信问题之后,我终于得到了一个使用 socat的解决方案。

  • 运行两个 Docker 容器-一个在源上,另一个在目的地上,每个都装有一个卷-源卷和目的卷。
  • 在其中一个容器上运行 rsync --deamon,该容器将从卷中流/加载数据
  • 运行 docker exec source_container socat - TCP:localhostdocker exec desintation_container socat TCP-LISTEN:rsync -将标准输入和标准输出连接在一起。因此,一个 socat连接到 rsync --daemon并将数据从/重定向到 stdout/stdin,另一个 socat侦听 :rsync端口(端口873)并重定向到/从 stdin/stdout。然后把它们连接起来,所以基本上我们把数据从一个集装箱港口输送到另一个。
  • 然后在与 localhost:rsync连接的另一卷 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

在这里添加一个答案,因为我没有评论的声誉。虽然以上所有的答案都对我有所帮助,但我想可能还有其他像我一样的人也在寻求将 backup.tar文件的内容复制到合作者机器上的 named docker volume中。我没有看到在上面或者在 码头卷文件中特别讨论过这个问题。

为什么要将 backup.tar文件复制到 named docker volume

在某些情况下,如果在现有的 docker-compose.yml文件中指定了一个 named docker volume,以供某些容器使用,那么这可能会很有帮助。

backup.tar的内容复制到 named docker volume

  1. 在主机上,按照接受答案或 码头卷文件中的步骤创建 backup.tar文件并将其推送到某个存储库。

  2. backup.tar从存储库拉入合作者的机器。

  3. 在协作者的机器上,创建一个临时容器和一个命名的 docker 卷。

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

  • --name temp_db_container: 创建一个名为 temp_db_container

  • ubuntu /bin/bash: 使用 ubuntu映像来 使用 /bin/bash的起始命令构建 temp_db_container

  • -v named_docker_volume:/dbdata: 安装 /dbdata文件夹的 temp_db_container到一个名为 我们使用这个特别命名的卷 named_docker_volume与我们的 docker-compose.yml文件。

  1. 在合作者的机器上,将 backup.tar的内容复制到指定的 docker 卷中。

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: 在上一步中,temp_db_container容器的 /dbdata文件夹被映射到 named_docker_volume卷。所以任何存储在 /dbdata文件夹中的文件将立即被复制到 named_docker_volume Docker 卷中。
  • -v $(pwd):/backup: 将本地机器的当前工作目录映射到位于 temp_db_container中的 /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

这个 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

刚刚为类似的用例编写了 码头-卷-快照命令。这个命令是基于 tommasop 的回答。

只要一声令下,

  1. 创建快照
docker-volume-snapshot create <volume-name> snapshot.tar
  1. 将快照.tar 移动到另一个主机
  2. 还原快照
docker-volume-snapshot restore snapshot.tar <volume-name>