Docker - 无法在卷内的容器之间共享数据 (docker-compose 3)

Docker - Can't share data between containers within a volume (docker-compose 3)

我现在有一些用于 Web 应用程序的容器(nginx、gunicorn、postgres 和 node,用于从源代码和 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 都运行良好,我可以看到一个网页,但都是静态的文件 return 404 未找到错误。

如果我用 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 问题和 Whosebug 问答,据我所知,它必须有效,但没有信息什么时候没有。

更新: 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 docker文件:Dockerfile.nginx


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

逐步解释发生的事情

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 的 /usr/src 和来自 nginx 的 /var/www/tg/static 的内容。

Definitively, to pass data from /usr/src from your node container to /var/www/tg/static in nginx container you need to do something that is not very pretty because Docker hasn't developed another way yet: You need to combine named volume in source folder with bind volume in destination:

 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

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

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

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