进入 Docker Desktop 虚拟机读容器的 cgroup v2 目录:/sys/fs/cgroup/docker/容器ID(86 个文件);--cpus 0.5 是 cpu.max = 50000 100000、--cpu-shares 512 是 cpu.weight = 59、--memory 100m 是 memory.max = 104857600、--pids-limit 50 是 pids.max = 50、--device-write-bps 变成 io.max;cgroup.procs 与 docker top 一致;docker pause 就是 cgroup.freeze = 1。
在 Docker Engine 29.8.2 里实测 docker system df:四行(Images、Containers、Local Volumes、Build Cache);往卷写 30 MB 随机数据 Local Volumes 增 31.0 MB,容器可写层 30 MB 使 Containers 增 31.5 MB,30 MB 的镜像层使 Images 和 Build Cache 各增 63.0 MB;Reclaimable 就是没有容器引用的部分(卷 299.3MB → 267.8MB、镜像 323.2MB → 260.3MB)。
在 Docker Engine 29.8.2 里实测各种 prune,全部带 --filter label=bwlab=1 只清理自己创建的对象:container prune 只删 exited 和 created 的容器;image prune 不带 -a 只删悬空镜像(这里是 0B),-a 才删没有容器使用的镜像;volume prune 只清匿名卷,-a 才删命名卷;network prune 删没有容器的自定义网络;别的对象前后数量不变。
直接对 Docker Desktop 的 unix socket 发 HTTP 请求:/_ping、/version(ApiVersion 1.56,MinAPIVersion 1.40)、/info;用 API 创建、启动、等待、读日志(多路复用流,8 字节帧头)、删除一个容器;API 版本写在路径里,低于 1.40 或高于 1.56 都返回 400;用代理记录 docker run --rm 发出的 6 个请求。
实测 docker context:上下文存放在 ~/.docker/contexts/meta/名字的 sha256 目录下的 meta.json,当前上下文记在 config.json 的 currentContext;新建上下文后用 --context 或 DOCKER_CONTEXT 临时使用而不改当前配置;优先级是 -H / --context 胜过 DOCKER_HOST,DOCKER_HOST 胜过 DOCKER_CONTEXT,--context 与 -H 同时给报冲突;ssh 上下文通过 ssh 连接远端。
只读查看 Docker Desktop 的引擎配置:Mac 上 ~/.docker/daemon.json 只有 builder.gc 和 experimental 两项,虚拟机里实际生效的 daemon.json 有 20 个键,其余由 Docker Desktop 补充(log-driver local、storage-driver overlayfs、default-stop-timeout 3、mtu 65535、host-gateway-ips、userland-proxy false 等),并与前面各篇观察到的行为一一对应。
在一个嵌套的 dockerd 里实测 live-restore:默认停 dockerd 要先停掉所有容器(10.3 秒),重启后容器 exited(137);--live-restore 下停 dockerd 只要 0.1 秒,容器主进程继续运行,重启后同一个 PID、同一个 StartedAt 被重新接管;kill -9 dockerd 同样不影响;dockerd 停着时 docker 命令全部失败。Docker Desktop 默认没有开启。
在 Docker Engine 29.8.2 里实测构建缓存何时失效:只改文件修改时间不会失效,改内容才会,而且从那条 COPY 起后面全部重新执行;先 COPY 依赖清单再 COPY 源码,改源码的构建从 3.4 秒降到 0.3 秒;加注释和行尾空格不失效,改命令字符或前面插入 ENV 才失效;--no-cache-filter 只让指定阶段重跑。
在 Docker Engine 29.8.2 里实测镜像压平:一个 RUN 生成 30 MB 文件、下一个 RUN 删除,镜像仍是 76.5 MB(4 层);同一个 RUN 里生成并删除则是 13.6 MB;FROM scratch + COPY --from 把整个根文件系统压成 1 层(13.6 MB),但 ENV 和 CMD 要重新写;export | import 同样丢元数据;docker build --squash 在 BuildKit 下被忽略。
自己写 Python 分析 docker save 出来的镜像层(类似 dive):故意构造覆盖文件、删除文件、只改权限的 Dockerfile,7 层里文件字节总和 45.5 MB,被后面层覆盖或删除的浪费 26.2 MB(效率 42.4%);chmod 也会重写整个 10.5MB 的文件;合并成一条 RUN 后镜像从 87.0 MB 降到 34.6 MB,容器里的文件完全一样。
在 Docker Engine 29.8.2 里实测非 root 运行:USER app(uid 10001)后进程 CapEff 为 0、只能写 /tmp 和 HOME;COPY 默认仍归 root(要加 --chown),USER 之后创建的 WORKDIR 属于该用户;--user 可以覆盖,passwd 里没有的 uid 没有名字、HOME 是 /;USER 在构建时就生效,之后的 RUN mkdir / 会失败。
在 Docker Engine 29.8.2 里实测入口脚本的信号转发:sh 里直接 python(不 exec)时应用收不到 SIGTERM,docker stop -t 5 等满 5.2 秒后 137;exec python 0.7 秒优雅退出;trap 转发时只 wait 一次会让脚本在应用清理完之前退出(143),被打断后再 wait 一次才正确;--init 不能替脚本转发;HUP 等其它信号要自己转发。