docker镜像由多层只读增量快照构成,每层对应dockerfile一条指令,记录文件差异;unionfs(如overlay2)通过叠加只读层与可写层实现统一视图,支持写时复制。

Docker 镜像不是“一个打包好的大文件”,而像一叠透明胶片——每张胶片只画了和上一张不同的部分,叠在一起才看到完整画面;UnionFS 就是那个让这叠胶片看起来像一张完整画纸的“投影仪”。
镜像层 = 一层一层的“差异快照”
你写一条 COPY app.py /app/,Docker 就生成一层,里面只存 app.py 这个文件;你再写一条 RUN apt install curl,新层就只记录 curl 相关的二进制、配置等新增内容,不会把整个系统重存一遍。基础镜像(比如 ubuntu:22.04)本身也是由多个小层拼成的,最底下甚至只有内核和启动所需最小文件(bootfs + rootfs)。
- 所有镜像层默认只读,不能直接改
- 用 docker history 镜像名 能清楚看到每一层对应哪条指令、多大、什么时候加的
- 不同项目共用同一基础镜像时,这些底层会自动共享,不重复占磁盘
UnionFS = 把只读层+可写层“叠”成一个可用文件系统
Docker 启动容器时,并不复制全部镜像层。它通过 UnionFS(主流是 overlay2)把所有只读层按顺序摞好,再在最上面加一个空的可写层(container layer)。你看到的 /app/、/etc/ 等路径,是所有层“叠加后”的统一视图。
- 读文件:先查最上层(可写层),没有就往下一层层找,直到找到为止
- 改文件:如果要改镜像里已有的 /etc/nginx.conf,UnionFS 会先把原文件从某只读层“复制”到可写层,再修改副本——原始层完全不动(这就是“写时复制”,Copy-on-Write)
- 删文件:在可写层标记该文件“已删除”,不影响下层真实存在
为什么这样设计?好处很实在
分层 + UnionFS 不是炫技,而是为了解决真实问题:
- 构建快:改一行代码重新 build,Docker 只新建一两层,其余直接复用缓存
- 拉取快:pull 镜像时,只下载本地没有的层,公司内部共用的基础层一次拉完,后续镜像几乎秒下
- 省空间:10 个基于 alpine 的服务镜像,共用同一个基础层,磁盘只存一份
- 易回滚:删掉最上面几层,就回到之前某个稳定版本的镜像状态











