Docker 多个容器之间的命名卷

Docker named volumes between multiple containers

我想将一些服务部署到我的服务器中,所有这些服务都将使用 nginx 作为 Web 服务器,每个项目都有自己的 .conf 文件,我想与 nginx 容器共享所有这些文件。我尝试使用命名卷,但当它被多个容器使用时,数据会被替换。我想从不同的容器中获取所有这些 .conf 文件并放入一个卷中,以便 nginx 容器可以读取它。我还尝试在命名卷中使用子目录,但是,使用 namedVolumeName/path 不起作用。

Obs:我在所有项目中都使用 docker-compose

version: "3.7"

services:
  backend:
    container_name: jzmimoveis-backend
    image: paulomesquita/jzmimoveis-backend
    command: uwsgi --socket :8000 --wsgi-file jzmimoveis/wsgi.py
    volumes:
      - nginxConfFiles:/app/nginx
      - jzmimoveisFiles:/app/src
    networks:
      - jzmimoveis
    restart: unless-stopped
    expose:
      - 8000

  frontend:
    container_name: jzmimoveis-frontend
    image: paulomesquita/jzmimoveis-frontend
    command: serve -s build/
    volumes:
      - nginxConfFiles:/app/nginx
    networks:
      - jzmimoveis
    restart: unless-stopped
    expose:
      - 5000

volumes:
  nginxConfFiles:
    external: true
  jzmimoveisFiles:
    external: true
networks:
  jzmimoveis:
    external: true

例如,在这种情况下,我是否将前端和后端 nginx 文件都链接到命名卷 nginxConfFiles,但是,当我在此文件中执行 docker-compose up -d 时,只有一个 .conf 文件出现在卷中,我认为它会被同一文件中的其他容器覆盖。

可能您可以在 nginx 容器上将共享卷指向 /etc/nginx/conf.d,然后为每个项目配置文件使用不同的名称。

在概念验证下,三台服务器,每台服务器都附加一个配置文件,以及一个共享卷绑定到 /config:

的代理(您的 Nginx)
version: '3'

services:
  server1:
    image: busybox:1.31.1
    volumes:
    - deleteme_after_demo:/config
    - ./server1.conf:/app/server1.conf
    command: sh -c "cp /app/server1.conf /config; tail -f /dev/null"

  server2:
    image: busybox:1.31.1
    volumes:
    - deleteme_after_demo:/config
    - ./server2.conf:/app/server2.conf
    command: sh -c "cp /app/server2.conf /config; tail -f /dev/null"

  server3:
    image: busybox:1.31.1
    volumes:
    - deleteme_after_demo:/config
    - ./server3.conf:/app/server3.conf
    command: sh -c "cp /app/server3.conf /config; tail -f /dev/null"

  proxy1:
    image: busybox:1.31.1
    volumes:
    - deleteme_after_demo:/config:ro
    command: tail -f /dev/null

volumes:
  deleteme_after_demo:

让我们创建 3 个要包含的配置文件:

➜ echo "server 1" > server1.conf
➜ echo "server 2" > server2.conf
➜ echo "server 3" > server3.conf

然后:

➜ docker-compose up -d                  
Creating network "deleteme_default" with the default driver
Creating deleteme_server2_1 ... done
Creating deleteme_server3_1 ... done
Creating deleteme_server1_1 ... done
Creating deleteme_proxy1_1  ... done

最后,让我们验证配置文件是否可以从代理容器访问:

➜ docker-compose exec proxy1 sh -c "cat /config/server1.conf"
server 1

➜ docker-compose exec proxy1 sh -c "cat /config/server2.conf"
server 2

➜ docker-compose exec proxy1 sh -c "cat /config/server3.conf"
server 3

希望对您有所帮助。 干杯!

注意:您应该看到挂载卷的方式与使用 Unix 挂载命令的方式完全相同。如果您已经在挂载点内有内容,则在挂载之后您将不会看到它,而是看到挂载设备的内容(除非它是空的并且首先在此处创建)。无论你想看到什么,都需要已经在设备上,否则你需要在之后移动它。

所以,我通过挂载文件来做到这一点,因为我使用的容器中没有数据。然后用启动命令复制这些。您可以用不同的方式解决它,例如,通过使用映像中的入口点脚本将配置文件复制到已安装的卷。

命名卷在 empty/new 时初始化,容器使用该卷启动。初始化是从映像文件系统开始的,之后,命名卷是持久的,并且会保留以前使用时的状态。

在这种情况下,您遇到的是竞争条件。 volume 正在共享文件,但它取决于哪个容器 compose 先启动来控制使用哪个图像来初始化 volume。命名卷在多个图像之间共享,它只是您想要不同的内容。

对于您的用例,您最好在映像构建和入口点中放置一些逻辑,以将要在卷中镜像的文件保存到构建时映像中的不同位置,然后更新卷在容器启动时。通过将其移出命名卷初始化步骤,您可以避免竞争条件,并允许使用映像中的未来更改更新卷。这方面的一个例子是在我的 base imagesave-volume 你会在 Dockerfile 中 运行 , load-volume 你会 运行 在你的入口点。

附带说明一下,在不需要写入配置文件的容器中将该命名卷挂载为只读也是一个好习惯。