【问题标题】:How to migrate Docker volume between hosts?如何在主机之间迁移 Docker 卷?
【发布时间】:2017-08-16 13:08:26
【问题描述】:

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

在 SO 上四处寻找,我发现了一个 older 问题(大约 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 flask docker-volume


【解决方案1】:

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

对我来说,这是共享数据的“Docker”方式,它使事物在 Docker 环境之间保持可移植性。您还可以通过 Jenkins 等 CI 环境中的作业定期生成数据容器。

【讨论】:

  • 做到了!非常感谢@rob-blake! :D :D :D
  • 一个快速的后续问题,如果您愿意提供帮助:假设我的远程主机上的用户添加了新数据,我想在本地将其拉回做docker commits(我听说它变得非常快),有没有办法做到这一点?
  • @ericmjl 好吧,您可以例如 docker cp 将数据从容器中取出,基于该数据构建另一个数据容器,将新数据容器推送到 Docker Hub,然后在本地进行 docker pull。以上可以每天编写脚本并由 CI 服务器管理,例如詹金斯。有意义吗?
【解决方案2】:

你可以使用这个技巧:

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

【讨论】:

    【解决方案3】:

    根据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
    

    【讨论】:

      猜你喜欢
      • 2014-11-03
      • 1970-01-01
      • 2015-04-28
      • 2020-01-07
      • 2016-05-03
      • 2023-03-21
      • 2020-08-13
      • 2021-03-01
      • 2017-02-21
      相关资源
      最近更新 更多