bigywater.tech
Docker · 91

在容器里用 Docker:挂载 socket 与 DinD 的区别

在容器里用 docker 命令,是起一个嵌套的 dockerd 还是把宿主的 socket 挂进去?两种做法看到的东西、创建的容器、需要的权限各不相同。这篇用 docker:dind 镜像逐项实测。

0 对 9
嵌套的 docker ps 看到的容器数,与挂载 socket 后容器里 docker ps 看到的容器数(外层也是 9)
兄弟容器
通过挂载的 socket 创建的容器,出现在外层 docker ps 里
iptables Permission denied
不加 --privileged 起 dind 的 dockerd 时的报错

DinD

实测 · 本机执行输出
  不指定存储驱动直接起 dockerd,0.3 秒后就绪:29.9.0 storage=overlayfs cgroup=2 containers=0 images=0
  嵌套 dockerd 的启动日志里选存储驱动的行:630Z" level=info msg="loading plugin" id=io.containerd.snapshotter.v1.native type=io.containerd.snapshotter.v1 | Z" level=info msg="loading plugin" id=io.containerd.snapshotter.v1.overlayfs type=io.containerd.snapshotter.v1 | xtension=org.mobyproject.storage.bbolt.v0 origin=builtin providers="[org.mobyproject.extension.storage.kv.v0]"
  外层 Docker 的容器数 8;嵌套的 docker ps 看到的容器数:0(嵌套的 docker 看不到外层的任何容器)
  嵌套的镜像库一开始是空的,需要自己 load/pull;load 之后:alpine:3.20
  嵌套里运行一个容器:2abc8b975abb037fc9f1b1602dc574c4376f62c2dbbe04bb32297669ab9d0de0 inner1 Up Less than a second
  外层 docker ps 能看到 inner1 吗?不能(它只存在于嵌套的 dockerd 里)
  嵌套容器的主进程在外层容器(dind 容器)里的进程列表中:390 sleep 120

容器里起一个独立的 dockerd,有自己的镜像库和容器,和外层互不可见;镜像要重新 pull 或 load。需要 --privileged,否则 iptables 等操作被拒绝。镜像是 docker:dind(29.9.0),存储驱动在这里是 overlayfs。

DooD(挂 socket)

实测 · 本机执行输出
  docker run -v /var/run/docker.sock:/var/run/docker.sock:退出码 0
  这个容器里的 docker ps -q 看到 9 个容器;外层 docker ps -q 是 9 个——看到的是同一个 dockerd 管的所有容器(含 Docker Desktop 里别的项目的)
  docker info 的 Name / ServerVersion / Driver:docker-desktop 29.8.2 overlayfs
  在容器里 docker run 一个 sibling86:退出码 0
  外层 docker ps 能看到 sibling86 吗?能(它是外层 dockerd 的兄弟容器,不是子容器)

把宿主的 /var/run/docker.sock 挂进去,容器里的 docker 命令就是在操作外层的 dockerd:看到所有容器,创建的是外层的兄弟容器,共享镜像缓存。不需要 --privileged,但这个容器等于拥有了控制整个 Docker 的能力——它能列出甚至操作别的项目的容器。这里我只做了 ps 和创建删除一个带标签的容器。

取舍

实测 · 本机执行输出
  不加 --privileged:15 秒内 dockerd 就绪了吗?False;dockerd 日志最后几行:KER: iptables v1.8.13 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root)\n (exit status 4)" | -wait -t nat -N DOCKER: iptables v1.8.13 (nf_tables): Could not fetch rule set generation id: Permission denied (you must be root) |  (exit status 4)
  对比:DooD 不加 --privileged 就能用(上一节);DinD 在上一节用了 --privileged,嵌套 dockerd 0.3 秒就绪。

要隔离(CI 里每个任务一个干净的 Docker)用 DinD,代价是特权和冷缓存;要共享缓存、轻量用 DooD,代价是权限过大且容器互相可见。哪种适合,取决于你信任里面的代码到什么程度(本文没有做更多的安全测试)。

分步演示

Docker in Docker
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。嵌套的 dockerd 来自 docker:dind 镜像(Docker 29.9.0),用特权容器启动,启动耗时从 dockerd 进程拉起到 docker info 成功;DooD 部分挂载的是 Docker Desktop 虚拟机里的 /var/run/docker.sock;只创建和删除了带 bwlab 标签的容器;实验后已删除这些容器
    • 没有验证:DinD 的数据持久化与卷、DinD 里的网络与端口映射、rootless DinD、sysbox 之类的运行时、通过 socket 能做的破坏性操作(不做)、CI 里的实际性能差别
    京ICP备2026067502号-1京公网安备11010502063487号