Docker in docker
啥是docker in docker?字如其义,就是在docker里面实现docker,换句话说,就是如何在docker执行docker命令。
有人可能会问了,为啥要这么麻烦,直接裸机跑容器不就完了吗?
读完这篇文章,你应该会有所了解。
关键字:docker in docker
docker in docker(dind)
有时需要在容器里面执行docker命令,比如在jenkins 容器内运行 docker 命令执行构建镜像等。
事实上,docker是支持嵌套的。但是直接在docker容器里面安装docker有点臃肿。
更好的方法是:容器里面仅仅部署docker-cli(作为客户端),实际执行交给宿主机内的 docker-engine(服务端)
两种方式
一种方式是,通过宿主机的docker.sock文件,将宿主机docker服务端的socket文件挂载到容器内,同时将docker二进制文件挂载到容器内,这样,容器内就不需要安装docker程序。当容器内使用docker命令时,实际上调用的是宿主机的docker
daemon和docker命令。也就是说,容器内并未真正运行docker
server,但是能通过宿主机执行docker任务,从而实现轻量级docker in
docker。这种情况下,真正执行docker命令的是跑在宿主机上的docker-engine,并不是真正的docker
in
docker。但是这种情况速度较快,然后存在一定的安全问题。不过,这种情况就是我们所需要的呀!!
还有一种方式是,启动一个docker:dind
容器A,再启动一个docker容器B,容器B指定DOCKER_HOST为A容器内的docker
daemon。
使用宿主机的socket文件
本想着挂载宿主机的docker.sock文件和docker二进制文件到容器即可实现dind,无奈默认情况下docker.sock文件是经过tls证书加密的,而在默认情况下加密的根证书却没有找到,通过宿主机执行docker info命令会提示以下错误:

翻阅资料知道docker daemon可以通过暴露tcp端口实现通信,而默认情况不是加密的,于是这个路就通了!!
通过暴露宿主机的tcp端口实现通信
- 查看宿主机
docker服务单元文件地址

- 修改宿主机
docker服务单元文件
1 | sudo vim /lib/systemd/system/docker.service |
安全起见,指定IP地址为局域网内网地址即可。

- 重载服务单元文件
1 | sudo systemctl daemon-reload |
- 重启服务
1 | sudo systemctl restart docker.service |
- 设置容器环境实现和宿主机
docker daemon通信
1 | version: '3' |
- 测试
1 | docker-compose up |

通过上述方法,即可实现在jenkins容器中操作docker容器啦
后记
本来是想通过上述第一种方式来实现jenkins容器中操作docker容器,但是发现这种方法有点问题:
- 容器内使用的是实际上宿主机的
docker daemon,因此挂载路径时,实际上挂上去的是宿主机的目录。而不是jenkins容器内的文件!!因此如果要使用上面第一种dind的方式,那么每次部署的时候都需要重新打包镜像!!而不是挂载目录!!! - 如果采用了上面的方案实现了dind,那么怎么监听部署没部署成功呢?看来又要写相应脚本判断了。
- 更新:不用脚本,不用脚本,直接
docker inspect即可获得容器的状态!!!
- 更新:不用脚本,不用脚本,直接