DinD docker 嵌套部署踩坑
最近要把一个 web 服务容器化部署。开发的时候没写 dockerfile,部署的时候可头疼死我了。
把相关的依赖在 dockerfile 里装好,写好环境变量用了 6h。然后更重量级的来了,DinD 的路径需要填 host 的路径,container 里调用 docker 的时候需要做映射目录的转换,这东西还不好调试;然后 docker 里面的用户权限也翻车了:binwalk3 是 Ubuntu、sfuzz-web 里面 nginx 需要 root、django 之前是按非 root 写的、用 root 跑的话上传的文件全是 root。
下午的时候决策是创建一个非 root 用户跑 django 会比较好,结果调试了 12 个小时。这玩意运行调试太地狱了
DinD 基础
DinD(docker in docker) 解决了 docker 嵌套的问题。解决方案也很粗暴:把 host 的 /var/run/docker.sock 文件映射到容器里,让容器里的 cli, sdk 直接访问主机 docker daemon.
但这样一来,容器内调用 docker 的参数就原封不动被传给主机 docker 了。在涉及 volume 共享文件的时候,会出现两个问题:1. 文件路径需要用主机绝对路径;2. 文件的权限是直接映射的 uid,也就是说 ubuntu(1000) 等价于 myuser(1000),跨机的 user 和 group 需要保持 id 一致。并且如果有哪个文件不存在被创建,有极大可能会被 root 所有。
在解决这个问题的时候,又会遇到其他问题,例如:在 RUN 阶段切换 USER,但 CMD 要 root,最后靠 su -c 解决了;在 RUN 阶段的命令依赖于 mount 的共享文件,靠 COPY 先解决着。
一个好消息是 ENV 对所有用户可见,不用担心切用户 ENV 刷新了。
回忆了一下注意点,最好还是照着模板改:
1. 写 dockerfile:要记得配置镜像,不然超级慢(pip + apt 都要,都慢)
2. `docker run binwalk3` 一开始以为用不了,但其实在 container 内部装一个 docker-cli 就可以
3. DInD 的路径转换。这个避免不了,因为 binwalk3 和 SFuzz 至少都要映射路径。但这就要求主机上保存 uploads, results, SFUZZ_STATIC_ROOT
4. 想了一下,其实用 SFUZZ_STATIC_ROOT 找工具不如把 SFuzz 放到 ./tools 下面来的好用。你想一般需要配环境变量的都是 python, AndroidSDK 这种需要快速命令行查找的。绿色软件哪里需要这个,都是从子目录找。(但 how about config 文件,或者 visual studio 的 vswhere
5. 多docker 环境需要提前考虑好哪些 volume 是要共享的。SFuzz 目录不能复制,必须 mount,因为 SFuzz 那个 docker 也要用这一次先拿环境变量凑合了
6. 用户组问题:不要吝啬 useradd 和 groupadd,没名字只有 uid 的时候 ~ 是错的,pip 会爆炸。id 相同的 u 和 g 就是一个东西。
7. 权限问题:docker 默认是 root,创建的文件 own by root,需要改掉。但简单 USER 切换之后连不上 sock 了,需要建组。mount point 本身的权限可能也得改。