Docker Compose - 在多个容器之间共享命名卷

178

我正在使用docker-compose和v3版本。我试图在Docker中挂载卷:

./appdata:/appdata

我想将其作为一个卷,并从多个容器中引用该卷。 卷配置参考 仅显示data-volume:作为命名卷,没有值,因此看起来与上述不同。

services:

    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes:
            - app-volume

    php:
        build: ./php/
        expose:
            - 9000
        volumes:
            - app-volume

volumes:
     app-volume: ./appdata:/appdata

这给了我:

错误: 在文件'./docker-compose.yml'中,卷'app-volume'必须是映射而不是字符串。

很明显我知道我需要改变volumes的键/值对,但我不确定如何更改它,以便我可以在服务之间共享一个volume。

我也查看了volumes_from,但这实际上只允许从其他容器继承。我看到有人在另一个包含他们想要的mapping的容器上使用volumes_from,但设置了command:true,这样该容器就永远不会被运行,对我来说似乎只是一种hack。

我该怎么做?


请注意,以下内容是有效的:

nginx:
    volumes:
        - ./appdata:/appdata
php:
    volumes:
        - ./appdata:/appdata

但这只是重复,我希望命名卷能帮助我避免这种情况 :-)


1
你可以在这个答案中找到答案:https://dev59.com/C1oV5IYBdhLWcg3wVNia#49920624 - Isen Ng
4个回答

211

命名卷可以通过以下方式在容器之间共享:

services:
    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes:
            - app-volume:location_in_the_container

    php:
        build: ./php/
        expose:
            - 9000
        volumes:
            - app-volume:location_in_the_container

volumes:
     app-volume: 

这是我用来更好地理解的一个示例配置。我将由web容器生成的静态文件暴露到名为static-content的命名卷中,然后由nginx容器读取和提供服务:

services:
  nginx:
    container_name: nginx
    build: ./nginx/

    volumes:
      - static-content:/usr/src/app

  web:
    container_name: web
    env_file: .env
    volumes:
      - static-content:/usr/src/app/public
    environment:
      - NODE_ENV=production

    command: npm run package

volumes:
  static-content:

133
在主机文件系统上,你应该将static_content的位置设置在哪里? - Travis Bear
11
app-volume: location_in_the_container 中的空格是错误的。 - hasufell
9
如果 nginx 容器中的 /usr/src/appweb 容器中的 /usr/src/app/public 都有原始内容,那么哪一个将被使用,为什么? - jallen0927
3
针对这种情况(在容器之间共享数据),并不需要将其放在主机上。例如,静态数据的示例很好 - 在一个容器中执行“collectstatic”命令,并希望在另一个容器中可用结果,但您不关心主机文件夹。 - The Godfather
17
@Kannaj TravisBear的问题是我最困惑的一个问题。在Compose文件中,你如何指定命名卷的来源?我不想让Docker引擎决定将命名卷存储在主机上的位置,我想指定一个路径。 - Ben Collins
显示剩余8条评论

47

以下方法解决了这个问题,而不需要使用命名卷:

      volumes:
          - ./appdata:/appdata

所以,看起来是这样的:

services:

  nginx:
      build: ./nginx/
      ports:
          - 80:80
      links:
          - php
      volumes:
          - ./appdata:/appdata

  php:
      build: ./php/
      expose:
          - 9000
      volumes:
          - ./appdata:/appdata

6
啊,时间正好!我刚刚在上面做了这个(请看我的更改)。然而,似乎我们仍在重复映射。如果我在三个容器中使用它,它就会变得很大。我们能否使用命名容器来避免这种重复? - Jimbo
问题在于命名卷不仅仅是语法和清晰代码的问题。它将在Docker数据安装目录中创建一个卷,您将无法在那里找到本地文件(./appdata)。无论如何,这对您有用吗? - Robert
3
我一定需要 ./appdata,这就是我想做的事情。不过还是请把你的回答留在这里 :) +1 - Jimbo
5
如果我有两个相同镜像的容器,在一个容器上传文件(通过上传文件服务),那么这个文件会在另一个容器中可用吗?如果不行,我该怎么做? - magnoz

34
你可以使用以下两个选项之一:
  1. 命名卷:https://docs.docker.com/compose/compose-file/07-volumes/

  2. 扩展字段,以避免复制卷源并防止未来的错别字:

version: '3.5'

x-services-volume:
  &services-volume
  type: bind
  source: ./appdata
  target: /appdata

services:

    nginx:
        build: ./nginx/
        ports:
            - 80:80
        links:
            - php
        volumes: *services-volume

    php:
        build: ./php/
        expose:
            - 9000
        # Use same way as for nginx if target override not needed.
        volumes:
            - <<: *services-volume
            target: /opt/target-override

注意:此功能从3.4版本文件格式开始提供。


6
docker-compose 的第三个版本中,命名卷,即顶级的 volumes 字段,似乎仍然是一个存在的东西。 - Alex Povel
我尝试了这种方法来在三个容器和一个主机之间共享数据。在我的情况下,容器中的文件夹结构是相同的。看起来这个方法按预期工作。但我不明白的是,当再次启动容器(或主机)时,哪个容器(或主机)拥有特权权利?我的意思是:当发出docker-compose down命令时,每个容器的内部文件系统都保存在内部某个地方。现在,如果我更改主机文件夹中的数据并再次执行docker-compose up命令,共享文件夹中的内容规则是什么?主机上的数据会覆盖内部保存的数据吗?谢谢! - and0r
1
@and0r 这个文件夹是共享的,就像 Google Drive 和真实用户 + 共享文件夹一样,如果有人在该文件夹中删除文件,则对于其他用户来说它将不复存在。 - Andriy Ivaneyko
5
卷的名称是否已经被删除了?我找不到任何关于这方面的参考资料。 - Kevin Van Ryckegem
kevinVanRyckegem @devrimbaris 很好的观点,我已经更新了答案,谢谢大家。 - Andriy Ivaneyko
显示剩余5条评论

12

之前的回答对我很有帮助(谢谢!),但是花了更多时间才弄清楚如何设置选项来创建共享tmpfs卷(内存文件系统)。我分享出来,希望能让处于同样情况下的开发者的生活更加轻松。

以下示例仅展示docker-compose.yml的相关部分:

version: '3'

volumes:
  shared-tmpfs:
    driver: local
    driver_opts:
      type: "tmpfs"
      device: "tmpfs"
      o: "size=256m,uid=1000"

services:
  nginx:
    volumes:
      - shared-tmpfs:/tmp/mytmpfs

  php-fpm:
    volumes:
      - shared-tmpfs:/tmp/mytmpfs

我使用它来避免在开发/监视模式下频繁写入(构建大量静态HTML文件)对SSD的损耗。

您可以在此处阅读有关driver_opts的更多信息,官方Docker文档。


針對你而言, 接受的答案有什麼問題沒有解決?這裡你必須定義兩次 - 使用接受的答案的 &* 表示法,這樣你只需要定義一次即可。 - Jimbo
1
@Jimbo,我确实喜欢已接受的答案,但是我无法使用那种方法实现相同的功能。那个解决方案绑定了一个现有的目录,而我的解决方案会根据给定的选项即时创建一个新的tmpfs卷。这可能是我的问题,但我无法将其转换为已接受答案的形式(扩展字段)。 - szegheo

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