2013年8月,JérômePetazzoni在Docker中创建了Docker,简称dind,这允许在Docker Containers中创建Docker容器,这一功能非常受欢迎,导致Jérôme的GitHub Repository获得了上千个星星和三百个叉子。
从两年后(2015年8月)发布的Docker 1.8开始,Docker直接支持Docker中的Docker。但是,在Docker中使用Docker会带来警告,似乎与Jérôme的文章:在您的CI或测试环境中使用Docker-in-Docker?三思而后行。这着重说明了为什么Docker中的Docker并不是持续集成的理想选择的原因。
为什么在Docker中使用Docker为什么不好?这是避免海龟全程下降的简单案例吗?还是性能方面的考虑?



评论

除了已经阅读过Docker,我对Docker并不熟悉。但是考虑一下,就好像您在硬件上安装了主机操作系统,该主机加载一个容器,然后该容器加载另一个。鉴于此想法是部署映像,因此似乎有很多开销。一幅画的一幅画……对这个问题的实际答案也很感兴趣。

您正在将答案链接到您的问题...还是我错过了什么?

#1 楼

持续集成问题

简而言之:Docker中的Docker(dind)不能很好地处理并发性。设计为对其存储目录具有独占访问权(通常为/var/lib/docker)。 Dind不尊重这一点,因为所有子进程同时使用此目录。每次重建时(例如,从CI重建),此目录中与您的应用相关的所有内容都会被清除,并从零开始。如果您的用户输入他们的付款详细信息,单击“购买”,然后突然发现自己回到登录屏幕,就像他们从未做过任何事情一样,会如何?那只是不好的用户体验。一次进行两次重建?对于涉及到的每个人(包括您的数据完整性)来说,这确实将是一个糟糕的结局。

其他问题

从OP发布的链接中,由于系统将尝试执行以下操作,因此出现了安全隐患以非常类似于CSS的方式应用安全策略,除非明确禁止,否则下层容器可以访问外部容器的资源。还记得何时可以通过执行“ mywebsite.com/../another_folder/private_resource.txt”之类的操作来访问Web服务器资源吗?另外,有时文件系统以这种方式嵌套时,它们彼此之间无法很好地发挥作用。

修复程序

很幸运,OP中的博客文章这个问题的好解决方案。除非“通过在Docker上运行的CI系统本身构建/运行/推送Docker容器”无法满足您的需求,否则您可以在Docker套接字(通常为-v)上使用/var/run/docker.sock:/var/run/docker.sock模式(向容器中添加数据卷)以允许您需要对“共享”数据量进行某种访问。这些容器将与父容器一起启动,而不是从下面开始,从而强制进行同步IO。现在,您(几乎)拥有与dind相同的东西,但是没有为并发而构建Docker的缺点。

参考(来自OP):在您的CI或测试环境中使用Docker-in-Docker?三思。

评论


这是描述的针对Jenkins的方法(dood)的一个示例,但在使用该方法时仍报告了多个问题

–菱形
17 Mar 27 '17在23:26

从这个解释中,我仍然无法真正确定我是否应该避免使用dind ...我的构建代理在docker容器中运行,并执行以下操作:1.签出回购。 2.启动容器和安装回购。 3.在容器中运行一些构建/测试脚本。每个代理只能运行一个“ dind”容器。在这个用例中,灰尘仍然存在问题吗?

–helmesjo
17年11月12日11:41



#2 楼

多年来,Docker-in-docker变得越来越好,并且docker dind映像变得越来越成熟。但是,仍然存在许多警告,使得使用它的难度相对较大。在主机上,您将拥有ext4之类的文件系统,docker可以在其上运行overlayfs2。但是,在docker容器中,docker无法将overlayfs2用作另一个overlayfs2的后备文件系统。它不能递归工作。没有简单的设置来创建运行良好的递归docker-in-docker存储驱动程序堆栈。
唯一适用于任何事物的存储驱动程序是vfs。但是,vfs没有写时复制功能,这意味着每个docker build层实际上都是先前各层的完整副本。在具有多个层的Docker构建中,大量重复会导​​致性能问题以及迅速耗尽磁盘空间。因此,这通常不是一个真正的解决方案。
可能的解决方法是对内部docker守护程序的存储目录(/var/lib/docker)使用卷挂载。然后内部docker守护程序可以直接使用主机文件系统,并因此可以在其上运行overlayfs2。为了避免在磁盘上预先分配空间,可以为循环设备使用稀疏文件。例如
dd if=/dev/zero of="$image_file" bs=1M count=0 seek="$sparse_loop_device_size_mb"
mkfs.ext4 "$image_file"
mount -n -o loop,noatime,nodiratime,noexec,noauto "$image_file" /var/lib/docker

(此处循环设备的大小是最大大小,而不是初始大小)
但是请注意,Docker建议不要将大量写容器用作该容器的可写层由于性能原因。因此,建议为docker daemon目录使用卷挂载。
图像缓存
另一个典型的问题是docker-in-docker中docker构建的缓存或docker pull的缓存。如果您每次都在构建中启动docker-in-docker守护程序,则它将具有零缓存。或者,如果您启动了docker-in-docker守护程序进行集成测试,那么您将不得不重新拉下所有内容。考虑到这一点很明显,但是如果不加以考虑,则可能是关键的性能问题。当前尚没有简便的方法可以在主机docker守护程序和docker-in-docker之间共享缓存。 。只需确保您永远不要将其同时安装到两个docker守护程序上,因为这是一种由于损坏而导致无法预测的行为的简便方法。 docker dir的设计目的不能被一个以上的守护进程同时访问。上面提到的驱动程序和缓存注意事项)。
安全性
docker-in-docker需要特权模式,这可能是附加的攻击媒介。有正在进行的工作以无根模式支持docker-in-docker,包括使用ext4的保险丝变体。但是,这种方法还不成熟。这不是真正的docker-in-docker,因为容器仅使用客户端连接到主机的docker守护程序。但是,对于某些用例,它是一种流行的无忧选项。如果您的情况允许,这将更容易实现。