如何在主机之间迁移Docker数据卷?

12
Docker的文档指出,卷可以进行“迁移”,我认为这意味着我应该能够将一个卷从一个主机移动到另一个主机(如果有错误,请指正)。然而,同一文档页面没有提供如何操作的信息。
在SO上查找时,我发现了一个较早的问题(约2015年左右),它说明这是不可能的,但是考虑到时间已经过去2年,我想再次提问。
如果需要,我正在开发一个使用[TinyDB]+本地磁盘作为数据存储的Flask应用程序。我确定我不需要比这更复杂的东西;目前这是一个学习项目,因此我决定采用非常轻量级的方法。该项目的结构如下:
/project_directory
|- /app
   |- __init__.py
   |- ...
|- run.py  # assumes `data/databases/ and data/files/` are present
|- Dockerfile
|- data/
   |- databases/
      |- db1.json
      |- db2.json
   |- files/
      |- file1.pdf
      |- file2.pdf

我有一个名为data/*的文件夹,它在我的.dockerignore.gitignore中,因此它们不会被放入版本控制并且在构建镜像时被Docker忽略,同时我也想尽可能接近真实世界地使用数据库条目和PDF文件,所以我用一小部分真实数据来填充应用程序,这些数据存储在一个卷中,当Docker容器被实例化时,该卷直接挂载到data/中。
我想要做的是在远程主机上部署容器,但是让远程主机使用起始数据(理想情况下,这将是我在本地使用的卷,以获得最大方便性); 随着在远程主机上添加更多数据,我希望能够将其拉回,以便在开发期间,我正在使用最新的由最终用户输入的数据。
寻找解决方案时,我考虑了“hacky”的方法,即简单地使用rsync,这可能完全可以胜任。 但是,如果我错过了什么解决方案,我将非常感激您的指导!

1
这可能很有用 https://www.guidodiepen.nl/2016/05/transfer-docker-data-volume-to-another-host/ - yamenk
为了完整起见,Docker Desktop 存在一个用于备份和共享卷的扩展。请参阅:https://www.docker.com/blog/back-up-and-share-docker-volumes-with-this-extension/ - undefined
3个回答

11
根据Docker文档,您也可以创建备份并进行恢复:

备份卷

docker run --rm --volumes-from CONTAINER -v \
$(pwd):/backup ubuntu tar cvf /backup/backup.tar /MOUNT_POINT_OF_VOLUME

在另一个主机上从备份恢复卷

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

或者(我更倾向于)将其复制到本地存储

docker cp --archive CONTAINER:/MOUNT_POINT_OF_VOLUME ./LOCAL_FOLDER

然后将其复制到另一个主机上并以例如的方式启动。

docker run -v ./LOCAL_FOLDER:/MOUNT_POINT_OF_VOLUME some_image

7
我会采用生成一个Docker容器的方法来处理这个问题,该容器存储您想要用于种子数据的开发环境。然后您可以将该容器中的数据作为卷公开,并最终将该卷挂载到开发容器中。以下是一个示例:
创建数据容器
首先,我们将只创建一个包含种子数据且不包含其他内容的Docker容器。我会在~/data/Dockerfile创建一个Dockerfile文件,并提供以下内容:
FROM alpine:3.4
ADD . /data
VOLUME /data
CMD /bin/true

您可以使用以下命令构建此项目: docker build -t myproject/my-seed-data . 这将创建一个名为myproject/my-seed-data:latest的Docker镜像。该镜像只包含您要用于环境种子数据的所有数据,存储在镜像中的/data位置。每当我们将镜像作为容器的实例创建时,它将公开/data中的所有文件作为卷。 将卷挂载到另一个Docker容器中 我想您正在运行Docker容器,类似于以下方式: docker run -d -v $(pwd)/data:/data your-container-image <start_up_command> 现在,您可以扩展该命令以执行以下操作:
docker run -d --name seed-data myproject/my-seed-data
docker run -d --volumes-from seed-data your-container-image <start_up_command>

我们要做的第一件事是创建您的种子数据容器的实例。然后,我们创建一个开发容器的实例,并将数据容器中的卷挂载到其中。这意味着您将在开发容器内的/data获取种子数据。
这会有点麻烦,因为您需要运行两个命令,所以我们可以使用像Docker Compose这样的工具更好地进行编排。
使用Docker Compose进行简单编排 Docker Compose 是一种同时运行多个容器的方式。您可以声明您的环境需要什么样子,并定义以下内容:
“我的开发容器依赖于我的种子数据容器的实例”
您可以创建一个 docker-compose.yml 文件来布置您所需的内容。它可能看起来像这样:
version: 2
services:
  seed-data:
   image: myproject/my-seed-data:latest

  my_app:
    build: .
    volumes_from:
     - seed-data
    depends_on:
     - seed-data

您可以使用docker-compose up -d my_app来一次性启动所有容器,Docker Compose会聪明地先启动数据容器的实例,最后启动应用程序容器。
在主机之间共享数据容器的最简单方法是将其作为映像推送到Docker Hub。构建完成后,可以通过以下方式将镜像推送到Docker Hub: docker push myproject/my-seed-data:latest 这在概念上与将Git提交推送到远程存储库非常相似,只不过这种情况下您正在推送一个Docker映像。然而,这意味着任何环境现在都可以拉取此映像并使用其中包含的数据。这意味着当您有新的种子数据需要重新生成数据镜像时,可以将其推送到Docker Hub的:latest标签下,并在重新启动开发环境时获得最新数据。
对我来说,这是共享数据的“Docker”方式,并且它使Docker环境之间的移植性更强。您还可以执行诸如通过Jenkins中的CI环境内的作业定期生成数据容器之类的操作。

如果您能够帮忙,我有一个跟进问题:假设我的远程主机上的用户添加了新数据,我想在本地将其拉回,而不必执行 docker commit(我听说这会变得非常混乱),是否有一种方法可以实现? - ericmjl
1
@ericmjl 例如你可以使用 docker cp 命令将容器中的数据复制出来,基于这些数据构建另一个数据容器,把新的数据容器推送到 Docker Hub 上,然后在本地使用 docker pull 命令拉取它。以上步骤可以每天自动执行,并由 CI 服务器如 Jenkins 进行管理。明白吗? - Rob Lockwood-Blake

4

你可以使用这个技巧:

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 - " '

更多信息


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接