在 docker 容器之间共享单个文件

时间:2021-03-04 10:34:19

标签: docker docker-compose

我想在 docker 容器之间共享单个文件

ContainerA:
- file-1
- file-2
- file-3
- shared-file

ContainerB
- file-a
- file-b
- file-c
- shared-file

无法为我共享完整的卷。 容器中的路径不一样。

3 个答案:

答案 0 :(得分:2)

由于 docker 默认将目录作为卷,并且仅当源是现有文件时才绑定挂载文件,因此使用起来有点困难。

如果您想在当前目录中共享 file,您可以在 docker-compose.yml 中使用绑定挂载

services:
  app1:
    # ...
    volumes:
      - ./file:/path/to/file1:rw
  app2:
    # ...
    volumes:
      - ./file:/path/to/file2:rw

这要求文件已经存在于容器之外。另请参阅 jubnzv's answer 中绑定挂载文件的注意事项。

根据您的用例,可能更好的解决方法是使用 symlinks 并将共享文件安装在目录卷中:

# tree layout in containers:
ContainerA:
|- shared/
|   ` shared-file
`- app_folder_a/
    |- file-1
    |- file-2
    |- file-3
    `- shared-file-a -> /shared/shared-file


ContainerB:
|- shared/
|   ` shared-file
`- app_folder_b/
    |- file-a
    |- file-b
    |- file-c
    `- shared-file-b -> /shared/shared-file
# docker-compose.yml
services:
  app1:
    # ...
    volumes:
      - ./shared/:/shared/:rw
  app2:
    # ...
    volumes:
      - ./shared/:/shared/:rw

或者,如果您不想/不能在主机上拥有文件或共享目录,您可以使用带符号链接的命名卷:

services:
  app1:
    # ...
    volumes:
      - shared:/app_folder_a
  app2:
    # ...
    depends_on:
      - app1
    volumes:
      - shared:/shared

volumes:
  shared:

和容器B中符号链接的共享文件:

ContainerB:
|- shared/
|   ` ...
`- app_folder_b/
    |- file-a
    |- file-b
    |- file-c
    `- shared-file-b -> /shared/shared-file-a

这里的重要部分是,当第一次创建新卷 shared 时,docker 将使用容器中目标目录的内容预先填充它。因此,要正常工作,需要先启动 app1,以便 shared 卷填充 app_folder_a 的内容 - 因此 depends_on

这样你就拥有了 shared 卷,其中填充了 containerA 的 /app_folder_a/ 的内容,并安装到了同一个以及 containerB 的 /shared/ 上,而 /app_folder_b/shared-file-b 是一个/shared/shared-file-a 的符号链接。

答案 1 :(得分:0)

您可以使用卷来共享单个文件,而不是目录。但在某些情况下,您无法正确写入已挂载的文件。

这是一个最小的例子:

Enter birth date in the format: hh:min/dd.mm.yyyy
13:28/04.03.2021
NOW: 1614853702 BD: 1614853680
seconds elapsed: 22
year  70
mon   0
mday  1
hour  0
min   0
sec   22

在容器内,您可以使用 echo 'Test.' > /tmp/1.txt docker run -it --user $(id -u):$(id -g) --rm -v /tmp/1.txt:/tmp/2.txt:rw alpine 路径从主机系统访问 /tmp/1.txt

/tmp/2.txt

但是一些实用程序会在写入文件时尝试创建一个新的 inode。例如:

/ $ cat /tmp/2.txt
Test.
/ $ echo '123' > /tmp/2.txt 
/ $ cat /tmp/2.txt
123

重点是将文件安装为卷会在容器内安装特定的 inode。一些修改文件的工具会用新的 inode 替换 inode。但是您不能这样做,因为您挂载了一个指向您的文件的特定 inode。

因此,您需要挂载一个包含可以在容器内修改的 inode 的目录。有关详细信息,请参阅 docker volumes documentation

答案 2 :(得分:0)

如果 containerA 在某个路径创建一个文件并覆盖符号链接,我认为不可能用“干净”的方法来做到这一点(否则检查 acran 的答案)。

我能想到的唯一方法是:

  • 启动容器A
  • 等待文件创建
  • 获取文件(例如 docker cp)
  • 用种子启动ContainerB

但是有一些问题,例如如果 ContainerA 崩溃了 ContainerB 也需要重新创建,或者您需要再次复制文件。

如果您将其包装在 Makefile 中,它可能如下所示:

.DEFAULT_GOAL := run

run:
    docker-compose up -d containerA
    sleep 10
    docker cp containerA:/seed-file seed-file
    docker-compose up -d containerB