允许docker-compose中的多个服务共享合并卷

7

假设有一个以下的docker-compose.yml文件,我正在寻找一种方法,使得服务ab都可以访问一个共享卷,该卷由两个容器中合并后的内容组成。

version: '3'
volumes:
   shared-merged-volume:
services:
   a:
     volumes:
       - shared-merged-volume:/shared
   b:
     volumes:
       - shared-merged-volume:/shared

假设服务 a/shared/dir-from-a 目录下,而服务 b 也有一个类似的目录 /shared-dir-from-b。希望的结果是得到:
$ ls /shared # from either container
dir-from-a
dir-from-b

我发现的是其中一个容器会“胜出”,只有其中一个目录存在。我可以通过以下方式解决这个问题,但是需要更多的代码,并且如果目录内容发生变化,需要进行修改:
version: '3'
volumes:
   service-a-shared-volume:
   service-b-shared-volume:
services:
   a:
     volumes:
       - service-a-shared-volume:/shared/dir-from-a
       - service-b-shared-volume:/shared/dir-from-b
   b:
     volumes:
       - service-a-shared-volume:/shared/dir-from-a
       - service-b-shared-volume:/shared/dir-from-b

非常感谢您提前提供的任何帮助!


1
您找到了解决这个问题的有效方法吗? - JeffRSon
2个回答

0

使用命名卷是必需的吗?

如果不是,那么为了实现这种合并,我通常只是将目录映射到主机驱动器上的一个位置,而不是使用卷,这样就可以无问题地合并。在大负载和多个容器同时写入的情况下进行了测试。

建议的组合文件:

version: '3'
volumes:
   shared-merged-volume:
services:
   a:
     volumes:
       - /location/on/host/system:/shared
   b:
     volumes:
       - /location/on/host/system:/shared

从评论中编辑

此方法将本地主机目录中的所有内容都挂载到/shared,这意味着如果它是空的-它将挂载空目录,并且任何已经存在的内容-将被空目录覆盖。在您的服务启动后,在该挂载点内编写的所有内容都将按预期进行持久化和合并跨服务。


谢谢!这似乎会清除每个服务上/shared的任何现有内容,这不是我想要的。我想要来自每个容器中每个/shared的合并内容。 - jayp
很奇怪。如果我没有自己删除,它从来没有从该位置擦除任何内容。那我们应该深入调查一下。你的Docker和docker-compose版本是什么? - trust512
Docker 版本 18.03.1-ce,构建版本 9ee9f40 docker-compose 版本 1.21.1,构建版本 5a3f1a3 - jayp
这个案例很有趣。这些文件是在构建时只创建一次,而不是在服务启动后创建吗? - trust512
让我们在聊天中继续这个讨论 - jayp
显示剩余2条评论

0
如果两个容器都创建不同的文件夹,我不知道它们如何争夺创建自己相应文件夹的权利,除非它们首先删除/shared的内容,然后再创建文件夹?但这意味着在这种情况下使用卷是无效的,因为每次容器启动时都会删除内容。
无论如何,我发现通过路径重定向说服容器共享同一个文件夹通常是有用的。我将分享两种实现此目标的方法:
  1. 如果您可以访问创建 /shared 文件夹的代码,则可以使用环境变量来更改每个服务对 /shared 的预期位置。

    version: '3'
    volumes:
      shared-merged-volume:
    services:
      a:
        environment:
          SHARED_VOLUME_PATH: /shared/a/
        volumes:
          - shared-merged-volume:/shared
      b:
        environment:
          SHARED_VOLUME_PATH: /shared/b/
        volumes:
          - shared-merged-volume:/shared
    

    您可能需要让服务创建 SHARED_VOLUME_PATH,但现在它们可以和平共处。

  2. 如果您无法更改 /shared 的位置,这意味着每个服务始终希望使用该路径,则创建路径重定向的另一种方法是使用符号链接。为了使其工作,您将不得不覆盖服务的入口点在镜像的构建过程中执行此步骤

    version: '3'
    volumes:
      shared-merged-volume:
    services:
      a:
        entrypoint: [ "ln", "-sf", "/symshared/a/", "/shared/" ]
        volumes:
          - shared-merged-volume:/symshared
      b:
        entrypoint: [ "ln", "-sf", "/symshared/b/", "/shared/" ]
        volumes:
          - shared-merged-volume:/symshared
    

    或者,预先构建镜像,并在 Dockerfile 中添加一个简单的 RUN 命令来创建此符号链接:

    ...
    ARG SHARED_VOLUME_PATH
    RUN ln -sf ${SHARED_VOLUME_PATH} /shared/
    

    这样可以让每个容器继续使用它们以前使用的 /shared,但您仍然可以将其内容存储在卷中,而不会干扰其他容器想要处理自己版本的 /shared

    不用说,ln 命令仅适用于 Linux 和其他 Unix 系统,在某些情况下,您可能需要事先安装它。如果您的容器映像基于其他操作系统,例如 Windows,则需要找到其他可用于创建符号链接的工具。


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