如何更便捷地使用自定义daemon.json运行docker:dind镜像
现有配置的痛点
我用下面的Docker Compose配置启动docker:dind服务:
dind: image: docker:dind container_name: dind privileged: true command: ['dockerd', '--iptables=false', '--config-file=/etc/docker/daemon.json'] networks: isolated_network: ipv4_address: 172.16.0.4 restart: always hostname: 'Dindy' volumes: - ./volumes/dind/config:/etc/docker - ./volumes/dind/var/lib/docker:/var/lib/docker
这个方案能正常运行,但必须提前在宿主机创建./volumes/dind/config/daemon.json文件,总觉得这不是最优的用法。
尝试自定义镜像的方案
于是我试着用Dockerfile构建自定义镜像,把daemon.json直接复制进去:
FROM docker:dind RUN mkdir /etc/docker COPY ./daemon.json /etc/docker
但这个方案只有移除Docker Compose里的./volumes/dind/config:/etc/docker卷映射才能生效,不然查看docker logs dind会报错:
unable to configure the Docker daemon with file /etc/docker/daemon.json: open /etc/docker/daemon.json: no such file or directory
原因其实很简单:Docker的bind mount是覆盖式挂载——当你把宿主机目录挂载到容器内的/etc/docker时,容器镜像里原本存在的/etc/docker目录(包含我们复制的daemon.json)会被宿主机的目录完全替换。如果宿主机目录里没有daemon.json,容器自然找不到这个文件,就会报错。
可选的替代解决方案
除了提前创建宿主机文件、自定义镜像这两种方式,还有几种更灵活的方案:
1. 用临时容器初始化宿主机目录
启动dind服务前,先跑一个临时容器把daemon.json复制到宿主机的映射目录里:
docker run --rm -v ./volumes/dind/config:/target busybox cp ./daemon.json /target/
之后再启动Docker Compose,宿主机目录里就已经有daemon.json了,不需要手动创建。
2. 在Docker Compose中添加初始化服务
新增一个init服务,负责把daemon.json复制到共享目录,dind服务依赖这个init服务确保文件存在:
services: dind-init: image: busybox command: ['sh', '-c', 'cp /tmp/daemon.json /etc/docker/daemon.json'] volumes: - ./daemon.json:/tmp/daemon.json - ./volumes/dind/config:/etc/docker dind: image: docker:dind container_name: dind privileged: true command: ['dockerd', '--iptables=false', '--config-file=/etc/docker/daemon.json'] networks: isolated_network: ipv4_address: 172.16.0.4 restart: always hostname: 'Dindy' volumes: - ./volumes/dind/config:/etc/docker - ./volumes/dind/var/lib/docker:/var/lib/docker depends_on: - dind-init
3. 直接用命令行参数替代daemon.json
如果daemon.json里的配置项不多,完全可以把配置直接加到dockerd的命令行参数中,省去配置文件:
command: ['dockerd', '--iptables=false', '--log-level=info', '--storage-driver=overlay2']
4. 启动时动态生成daemon.json
在dind的启动命令里先动态生成配置文件,再启动dockerd,不需要提前准备文件或自定义镜像:
command: ['sh', '-c', 'echo \'{"log-level": "info", "storage-driver": "overlay2"}\' > /etc/docker/daemon.json && dockerd --iptables=false --config-file=/etc/docker/daemon.json']
更新补充
后来发现一种更优的思路:只挂载单个配置文件而非整个目录,这样不会覆盖容器内原有的/etc/docker目录,同时保留自定义配置:
volumes: - ./volumes/dind/config/daemon.json:/etc/docker/daemon.json - ./volumes/dind/var/lib/docker:/var/lib/docker
就算宿主机文件不存在,也可以通过前面的初始化步骤创建,同时不影响容器内其他默认配置文件。
内容的提问来源于stack exchange,提问作者Patrick Fromberg

