【问题标题】:Docker - Can't share data between containers within a volume (docker-compose 3)Docker - 无法在卷内的容器之间共享数据(docker-compose 3)
【发布时间】:2018-10-28 22:58:05
【问题描述】:

我现在有一些用于 Web 应用程序的容器(nginx、gunicorn、postgres 和节点,用于从源代码和 React 服务器端渲染构建静态文件)。在节点容器的 Dockerfile 中,我有两个步骤:构建和运行 (Dockerfile.node)。它最终在容器内有两个目录:bundle_client - 是 nginx 的静态目录,bundle_server - 在节点容器本身中用于启动快速服务器。

然后我需要与 nginx 容器共享一个构建的静态文件夹 (bundle_client)。为此,请根据我的docker-compose.yml 中的 docker-compose 参考,我有以下服务(请参阅完整的docker-compose.yml):

node:
  volumes:
    - vnode:/usr/src

nginx:
  volumes:
    - vnode:/var/www/tg/static
  depends_on:
    - node

和卷:

volumes:
  vnode:

运行docker-compose build 完成,没有错误。运行docker-compose up 运行正常,我可以打开localhost:80,nginx、gunicorn 和 node express SSR 都运行良好,我可以看到一个网页,但所有静态文件都返回 404 not found 错误。

如果我使用 docker volume ls 检查卷,我可以看到两个新创建的卷,名为 tg_vnode(我们在此处考虑)和 tg_vdata(请参阅完整的 docker-compose.yml)

如果我使用 docker run -ti -v /tmp:/tmp tg_node /bin/bash 进入 nginx 容器,我看不到我的 www/tg/static 文件夹,该文件夹应该从节点卷映射我的静态文件。我还尝试使用 nginx 容器 Dockerfile.nginx 创建一个空的 /var/www/tg/static 文件夹,但它保持为空。

如果我在nginx.volumes 部分的docker-compose.yml 中将主机上的bundle_client 文件夹映射为- ./client/bundle_client:/var/www/tg/static,它可以正常工作,我可以在浏览器中看到所有使用nginx 提供的静态文件。

我做错了什么以及如何让我的容器与 nginx 容器共享构建的静态内容?

PS:我阅读了所有文档、所有 github 问题和 stackoverflow 问答,据我所知,它必须有效,但没有信息在无效时该怎么做。

UPD:docker volume inspect vnode的结果:

[
{
    "CreatedAt": "2018-05-18T12:24:38Z",
    "Driver": "local",
    "Labels": {
        "com.docker.compose.project": "tg",
        "com.docker.compose.version": "1.21.1",
        "com.docker.compose.volume": "vnode"
    },
    "Mountpoint": "/var/lib/docker/volumes/tg_vnode/_data",
    "Name": "tg_vnode",
    "Options": null,
    "Scope": "local"
}
]

文件: Dockerfile.node, docker-compose.yml

Nginx dockerfile:Dockerfile.nginx


UPD:我创建了一个简化的 repo 来重现一个问题:reponpm install 上有一些警告,没关系,它安装和构建都可以)。最终,当我们打开 localhost:80 时,我们会在 Chrome 开发工具中看到一个空白页面和静态文件(vendor.jsapp.js)的 404 条消息,但应该有一条由 react 脚本生成的消息 React app: static loaded

【问题讨论】:

  • 在多个服务中使用相同的卷容器的问题在于,首先加载的容器会将自己的数据复制到卷中,其余的都将看到相同的内容。如果你想避免这种情况,你需要使用nocopyoption。我在您的作文中看到您在多个地方使用过它,只有一个地方会将其内容放入卷中并以初始内容获胜。如果在挂载后发生,则构建会将文件置于运行时。我很难想象你的作文,但看看这些指针是否有帮助
  • 是的,“...首先加载的容器会将其自己的数据复制到卷中,其余的都将看到相同的内容”,这就是我需要的 - 最初复制内置 @ 987654356@ artefact 在一个卷中,然后在 nginx 容器中使用它。我通过将depends_on.node 设置为nginx 容器来确保节点容器排在第一位。也许我搞砸了 Dokerfile 并编写了文件并误解了它的实际工作原理。您能否解释一下-“如果在挂载后发生,则构建会将文件置于运行时。”。我不确定我是否理解它。
  • 我根据长语法将nocopy: true添加到nginx.volumes,并在gunicorn容器中使用vnode进行注释,但不幸的是nginx容器内的文件夹仍然是空的。
  • 有没有可能得到一个 repo 来调试?
  • 你能添加你的 Dockerfile.nginx 文件吗?我正在尝试重现您的错误。我有一些线索,但我需要检查 nginx 容器

标签: docker docker-compose docker-volume


【解决方案1】:

您需要进行两项更改。在您的节点服务中添加如下卷:

volumes:
  - vnode:/usr/src/bundle_client

由于您要共享 /usr/src/bundle_client,因此您不应该使用 /usr/src/,因为这也会共享整个文件夹和结构。

然后在你的 nginx 服务中添加如下卷:

volumes:
  - type: volume
    source: vnode
    target: /var/www/test/static
    volume:
      nocopy: true

nocopy: true 清楚地表明了我们的意图,即在容器的初始映射中不应复制映射文件夹的内容。默认情况下,第一个映射到卷的容器将获取映射文件夹的内容。在您的情况下,您希望这是 node 容器。

另外,在测试之前,请确保您运行以下命令来终止缓存卷:

docker-compose down -v

你可以在我的测试中看到容器有文件:

【讨论】:

    【解决方案2】:

    逐步解释发生的事情

    Dockerfile.node

        ...
        COPY ./client /usr/src
        ...
    

    docker-compose.yml

    services:
      ...
      node:
        ...
        volumes:
          - ./server/nginx.conf:/etc/nginx/nginx.conf:ro
          - vnode:/usr/src
      ...
    volumes:
      vnode:
    
    1. docker-compose up 使用此 Dockerfile.node 和 docker-compose 部分创建一个命名卷,其中数据保存在 /usr/src 中。

    Dockerfile.nginx

    FROM nginx:latest
    
    COPY ./server/nginx.conf /etc/nginx/nginx.conf
    
    RUN mkdir -p /var/www/tg/static
    
    EXPOSE 80
    EXPOSE 443
    
    CMD ["nginx", "-g", "daemon off;"]
    
    1. 这会产生使用docker-compose 创建的nginx 容器将有一个空的/var/www/tg/static/

    docker-compose.yml

     ...
     nginx:
        build:
          context: .
          dockerfile: ./Dockerfile.nginx
        container_name: tg_nginx
        restart: always
        volumes:
          - ./server/nginx.conf:/etc/nginx/nginx.conf:ro
          - vnode:/var/www/tg/static
        ports:
          - "80:80"
          - "443:443"
        depends_on:
          - node
          - gunicorn
        networks:
          - nw_web_tg
    
     volumes:
       vdata:
       vnode:
    
    1. docker-compose up 将产生 vnode 命名卷被创建并填充从 /var/www/tg/static(现在为空)到现有 vnode 的数据。

    所以,在这一点上, - nginx 容器的 /var/www/tg/static 为空,因为它是空创建的(参见 Dockerfile.nginx 中的 mkdir) - 节点容器有 /usr/src 目录和客户端文件(请参阅在 Dockerfile.node 中复制的内容) - vnode 有来自node/var/www/tg/static 来自nginx 的/usr/src 的内容。

    明确地说,要将 /usr/src 中的数据从您的 node 容器传递到 nginx 容器中的 /var/www/tg/static,您需要做一些不太漂亮的事情,因为 Docker 还没有开发出另一种方式:您需要将源文件夹中的 named volume 与目标文件夹中的 bind volume 结合起来:

     nginx:
         build:
           context: .
           dockerfile: ./Dockerfile.nginx
         container_name: tg_nginx
         restart: always
         volumes:
           - ./server/nginx.conf:/etc/nginx/nginx.conf:ro
           - /var/lib/docker/volumes/vnode/_data:/var/www/tg/static
         ports:
           - "80:80"
           - "443:443"
         depends_on:
           - node
           - gunicorn
         networks:
           - nw_web_tg
    

    只需将 docker-compose - vnode:/var/www/tg/static 更改为 - /var/lib/docker/volumes/vnode/_data:/var/www/tg/static

    【讨论】:

    • 我也是这么想的,最初没有RUN mkdir -p /var/www/tg/static,后来添加只是为了尝试。如果将其注释掉,我最终会得到不包含 www/var 文件夹。
    • RUN rm -rf /var/www/tg/static显式删除没有效果。
    • 好吧,我误会了。看到解释,我们会继续。我不太明白你想做什么。也许您对命名卷的理解有误,我希望能澄清一下。
    • 这里我会尽量解释一下:
    • 我有一个节点容器,在 docker-compose up 上应该运行 npm install && npm build 并创建一个带有编译静态的人工制品文件夹并放入某个地方以便将它传递给 nginx 容器(据我所知命名卷是这样做的唯一方法)。接下来,据我所知,当我第一次提到一个卷(此处的节点部分)时,它将用给定的数据填充它,然后(在 nginx 中 - 第二次提到)它将使用这些数据。我通过depends_on.node 确保 node 是第一个,nginx 是第二个。我在这里错过了什么?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 2021-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多