在Docker(容器的系统中)中运行Docker

某些场景下我们需要在Docker中运行Docker,例如在Docker中部署Jenkins,在Jenkins的任务中对项目进行打包测试发布,而项目也是基于Docker的。

首先明确我们需要的是什么,Docker其实包含服务器(Docker Engine或者叫Docker Daemon)和客户端(Docker CLI),我们需要的是在容器内能够使用Docker客户端访问到Docker服务器,而Docker服务器其实不必运行在容器内,可以运行在宿主机上。

docker的客户端和服务器有一个参数决定了两者的通讯方式,默认情况下使用/var/run/docker.sock进行通讯,这个文件表示一个Unix Socket,Unix Socket是一种类似我们熟知的TCP/UDP的进程间通讯方式,我们也可以通过增加-H tcp://0.0.0.0:2376参数在启动时修改默认的通讯方式为TCP2376端口通讯。

1
-H, --host=[unix:///var/run/docker.sock]: tcp://[host]:[port][path]

方法一

我们可以通过在创建容器时指定-v /var/run/docker.sock:/var/run/docker.sock把宿主机的Socket映射到容器内,容器内的Docket客户端就相当于直接连到了宿主机的Docker Engine。

这样容器内和容器外使用的是同一个engine可以相互操作对方创建的镜像有一定风险。

方法二

那么还有一个方法就是使用别人制作的特殊系统镜像,镜像名称通常包含dind字样,表示支持Docker in Docker,例如gitlab/dind,这种镜像启动时需要--privileged参数,启动后容器内部预装了docker环境,容器内外的engine是独立不互通的,这种方法的问题是系统的版本是固定的,取决于dind镜像提供的什么版本。

方法三

替换docker运行时为sysbox

1
docker run --runtime=sysbox-runc --name sysbox-dind -d docker:dind

需要安装sysbox,参考sysbox/install-package.md at master · nestybox/sysbox (github.com)

因为安装前需要停止并删除所有容器,我并没有尝试过。