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

How to migrate Docker volume between hosts?

Docker 的 documentation 声明卷可以是 "migrated" - 我假设这意味着我应该能够将卷从一台主机移动到另一台主机。 (很高兴在这一点上得到纠正。)但是,同一文档页面没有提供有关如何执行此操作的信息。

深入研究 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

我的 .dockerignore.gitignore 中有文件夹 data/*,因此它们不在版本控制之下,并且在构建图像时被 Docker 忽略.

在开发应用程序时,我还尝试使用尽可能接近真实世界的数据库条目和 PDF,因此我在应用程序中植入了非常小的真实数据子集,这些数据存储在实例化 Docker 容器时直接装入 data/ 的卷。

我想做的是将容器部署到远程主机上,但为远程主机播种启动数据(理想情况下,这将是我一直在本地使用的卷,以提供最大的便利);稍后在远程主机上添加更多数据时,我希望能够将其拉回,以便在开发过程中我可以使用最终用户输入的最新数据。

环顾四周,我想做的 "hacky" 方法就是简单地使用 rsync,这可能会很好。但是,如果有我遗漏的解决方案,我将不胜感激指导!

我采用的方法是生成一个 Docker 容器,用于存储要用于播种开发环境的数据副本。然后,您可以将该容器中的数据公开为一个卷,最后将该卷装载到您的开发容器中。我将举例说明:

创建数据容器

首先,我们将创建一个 Docker 容器,其中仅包含您的种子数据。我会在 ~/data/Dockerfile 处创建一个 Dockerfile 并为其提供以下内容:

FROM alpine:3.4
ADD . /data
VOLUME /data
CMD /bin/true

然后您可以使用以下方法构建它:

docker build -t myproject/my-seed-data .

这将为您创建一个 Docker 标记为 myproject/my-seed-data:latest 的图像。该图像仅包含您想要为环境播种的所有数据,存储在图像内的 /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[=27= 之类的东西更好地编排它]

使用 Docker Compose 的简单编排

Docker Compose 是一种 运行 同时安装多个容器的方法。您可以声明您的环境需要的外观并执行诸如 define:

之类的操作

"My development container depends on an instance of my seed data container"

您创建一个 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 图像。然而,这意味着任何环境现在都可以拉取此映像并使用其中包含的数据。这意味着当您有新的种子数据时,您可以重新生成数据图像,将其推送到 :latest 标签下的 Docker Hub,当您重新启动您的开发环境时,将拥有最新的数据。

对我来说,这是共享数据的 "Docker" 方式,它使数据在 Docker 环境之间保持可移植性。你也可以做一些事情,比如让你的数据容器在像 Jenkins 这样的 CI 环境中由作业定期生成。

你可以使用这个技巧:

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

more information

根据 Docker docs 您还可以创建一个备份并恢复它:

备份量

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 CONTAINER:/MOUNT_POINT_OF_VOLUME ./LOCAL_FOLDER

然后将其复制到其他主机并从例如

开始
docker run -v ./LOCAL_FOLDER:/MOUNT_POINT_OF_VOLUME some_image