bigywater.tech
Docker · 86

层压缩:合并层能省多少,代价是什么

被删除的文件还占着镜像空间,怎么把它们真正去掉?这篇对比分两层删除、同一层删除、多阶段压平、export | import 和已被移除的 --squash,量出大小和层数,并看压平会丢掉什么。

76.5 MB 对 13.6 MB
分两个 RUN 生成再删除,与在同一个 RUN 里生成并删除的镜像体积
ENV、CMD 丢失
用 COPY --from / 或 export | import 压平后,镜像里的 ENV 和 CMD 不见了
--squash 被忽略
BuildKit 下 docker build --squash 只给警告,镜像仍有 4 层

为什么删了还占空间

实测 · 本机执行输出
  镜像 Size=76.5 MB,RootFS 层数=4,Cmd=['echo', 'from-cmd'],Env 有 DEMO 吗=True
  docker history 里各层的大小:4.1kB | 31.5MB | 4.1kB | 0B | 0B
  容器里 /big.bin 存在吗?ls: /big.bin: No such file or directory

后一层的删除只是在新层里标记文件被删,前一层里的内容原样保留(c3、c21)。所以镜像里装完东西再清理缓存,必须和安装放在同一条 RUN 里。

同一个 RUN

实测 · 本机执行输出
  镜像 Size=13.6 MB,RootFS 层数=3,Cmd=['echo', 'from-cmd'],Env 有 DEMO 吗=True

同一条 RUN 产生一个层,文件在这层里创建后又删除,最终层里没有它,体积和空 alpine 一样。

事后压平

实测 · 本机执行输出
  FROM scratch + COPY --from=<A> / /:镜像 Size=13.6 MB,RootFS 层数=1,Cmd=None,Env 有 DEMO 吗=False
  运行它:squashed-ok
  再补上 ENV 和 CMD:镜像 Size=13.6 MB,RootFS 层数=1,Cmd=['echo', 'from-cmd'],Env 有 DEMO 吗=True

多阶段构建 FROM scratch 再 COPY --from=… / / 得到单层镜像;ENV、CMD 这些元数据不会带过来(我测了这两项),要重新写。压成一层的代价是失去层复用(c18),我没有量化这一点。

export | import

实测 · 本机执行输出
  镜像 Size=13.6 MB,RootFS 层数=1,Cmd=None,Env 有 DEMO 吗=False

docker export | docker import 同样压成 1 层,同样丢掉 Cmd 和 Env。

--squash

实测 · 本机执行输出
  docker build --squash:退出码 0;['WARNING: experimental flag squash is removed with BuildKit. You should squash inside build using a multi-stage Dockerfile for efficiency.']
  加了 --squash 之后的镜像:镜像 Size=76.5 MB,RootFS 层数=4,Cmd=['echo', 'from-cmd'],Env 有 DEMO 吗=True(没有被压成 1 层)

在这个 Docker 的 BuildKit 构建器下,--squash 被忽略,只打一条警告;经典构建器下的行为我没有测。

分步演示

镜像压平
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Docker Desktop(Engine 29.8.2,容器跑在 Docker Desktop 自带的 Linux 虚拟机里,内核与宿主机的 macOS 不同);镜像为 linux/arm64;需要看虚拟机内部时用特权容器 + nsenter;计时用 time / date +%s%N,数字每次运行会有小幅抖动。随机文件用 /dev/urandom 生成(几乎不可压缩);镜像体积是 docker image inspect 的 Size(压缩内容加解包层,见 c18);层数取自 RootFS.Layers;每种方式构建一次;实验后已删除镜像和容器
    • 没有验证:经典构建器下 --squash、多阶段压平后推送拉取的传输体积、压平对后续构建缓存的影响、用 docker buildx build --output 直接导出平坦的 rootfs、overlay 层数上限(127 层)的实际表现
    京ICP备2026067502号-1京公网安备11010502063487号