我有一个Docker容器“ A”,它将启动另一个容器“ B”(通过卷挂载/var/run/docker.sock)。现在,这些容器需要共享文件。
容器“ B”期望文件被卷挂载,而最简单的方法是将挂载从“ A”绑定到“ B”,但是Docker无法做到这一点(绑定挂载始终源自主机文件系统)。
是否有一种简单的方法可以使容器与其创建的容器共享文件,而无需依赖主机文件系统,也无需从“ A”构建“ B”映像?
我一直在尝试创建卷并将文件复制到其中,但是解决方案往往很复杂且脆弱。理想情况下,我想将解决方案放在docker-compose文件中,以在“ A”内部运行,但这实际上几乎是不可能的。
作为参考,这是可以完全解决我的问题的另一个想法: https://github.com/docker/compose/issues/3593#issuecomment-272089143
答案 0 :(得分:3)
当您安装Docker套接字时,它实际上并不是docker中的docker,而是仅客户端通过API向主机上的守护程序发出请求,而该守护程序不知道请求来自何处。因此,您可以将这个问题简化为“您可以将文件从一个容器装载到另一个容器中”。不幸的是,如果不使用两个容器外部的卷,就没有简单的答案。这是因为容器文件系统依赖于用于组装各种图像和容器层的图形驱动程序,因此,即使是可能对overlay2都适用的解决方案也会在其他驱动程序上中断,并且将依赖于docker内部,而这些内部组件可能会在不发出警告的情况下进行更改
一旦进入外部卷,我就会想到几种可能的解决方案。
选项A:公共主机目录。我经常在笔记本电脑上使用透明容器,这在我在容器内部运行命令的事实中经常使用。我在容器中安装了具有完整路径的公共目录,例如-v $HOME:$HOME
。如果在每个容器中都安装了相同的主机目录,则可以从容器“ A”和“ B”内部使用相同的技术。如果您对容器“ A”使用如上所述的卷挂载,则此操作将适用于撰写文件,因为容器内部的路径与主机上的路径相同。
选项B:volumes_from。我什至会提及此选项,因为随着用户采用群体模式,该选项已逐步淘汰,但是可以选择将容器“ A”中的所有卷装入容器“ B”。这仍然需要您在容器“ A”中定义一个卷,但是现在您不必关心该卷的源了,它可以是主机卷,命名卷或匿名卷。
选项C:共享命名卷。命名卷允许docker管理数据的存储,默认情况下位于主机上的/ var / lib / docker / volumes下。您可以使用相同的命名卷运行两个容器,这使您可以在容器之间传递数据。您确实需要在容器“ A”中具有该卷的名称,才能对具有相同名称的容器“ B”运行命令。首次使用命名卷时,命名卷还会从映像中初始化命名卷的内容,因此这可能是有益的,尤其是对于文件所有权和权限。请注意,在下次使用相同名称的卷时,它不会对任何现有数据重新初始化,而是先前的数据将是持久性的。对于撰写文件,您需要将命名卷定义为外部卷。
选项D:手动创建的命名卷。如果仅尝试将某些文件从容器“ A”注入到容器“ B”中,则可以通过多种方式将其注入docker API。我已经看到文件保存到“ A”上的环境变量中,然后将环境变量写回到“ B”入口点中的文件中。对于较大的文件,或者为避免更改“ B”的入口点,您可以创建命名卷并通过将数据通过docker的stdin / stdout管道传递到正在运行的容器中,然后使用tar打包/解压缩该数据来进行发送I / O管道。这将在容器“ A”内部工作,因为tar命令的一半在该容器的文件系统内部运行。然后,容器“ B”将挂载该命名卷。要将数据从容器“ A”导入命名卷,如下所示:
tar -cC source_dir . | \
docker run --rm -i -v target_vol:/target busybox tar -xC /target
要从命名卷中取回数据,请按相反的顺序进行操作:
docker run --rm -v source_vol:/source busybox tar -cC /source . | \
tar -xC target_dir
类似于选项C,您需要在撰写文件中将此命名卷定义为外部卷。
答案 1 :(得分:0)
如果您不依赖卷,则共享文件的另一种方法是将它们从“ A”传递到“ B”。您将需要容器B来处理STDIN上的输入。带有自定义入口点。
在容器A中:
cat some_file_on_A.txt | docker run -i container_B
容器B中的示例入口点:
while read input_from_A; do
echo "${input_from_A}" > some_file_on_B.txt
done