UnionFS的写时复制(CoW)机制通过文件级复制实现分层共享:修改只读层文件时,先复制到可写层再操作,未修改文件零开销指向原层;overlay2以lowerdir、upperdir和merged三目录实现该机制,删除用.whiteout标记而非物理移除。

UnionFS 的写时复制(Copy-on-Write,CoW)机制是容器镜像分层存储的核心基础。它让多个容器能共享只读的底层镜像层,仅在需要修改文件时才复制一份私有副本,既节省空间又提升启动速度。
写时复制如何工作
UnionFS 将多个目录(称为“层”)叠加成一个统一视图。所有底层镜像层默认只读,最上层为可写层(如容器运行时的 upperdir)。当容器尝试修改一个只读层中的文件时,CoW 不会直接改原文件,而是:
- 先将该文件从底层只读层完整复制到可写层
- 再在可写层中对副本进行修改、删除或新建
- 后续读取该路径时,始终优先看到可写层中的内容(覆盖效应)
注意:复制粒度是“文件”,不是块或字节;未被修改的文件始终指向原始只读层,零额外开销。
容器镜像的分层结构
Docker 等容器运行时基于 UnionFS(或其现代替代如 overlay2)组织镜像。每个 FROM 指令生成一层,每层是一个只读的 tar 包,包含文件系统变更(新增/修改/删除)。
- 基础层(如 ubuntu:22.04)提供 /bin、/usr 等目录
- 中间层(如 RUN apt install curl)只记录 curl 及其依赖文件的增删
- 镜像本身不含“完整文件系统”,而是层叠的差分集合
docker images 显示的 SIZE 是该层自身增量大小,不是解压后占用;实际磁盘占用取决于各层复用程度。
可写层与容器生命周期绑定
容器启动时,运行时会在镜像最上层之上挂载一个新的空可写层(即容器层)。所有运行时产生的文件(如日志、临时文件、应用状态)都落在此层。
- 容器停止后,该层仍存在,可提交为新镜像(docker commit)
- 容器删除(docker rm)默认会清除该可写层,除非使用 --volumes 或绑定挂载持久化数据
- 同一镜像启动的多个容器,各自拥有独立可写层,互不影响
overlay2 中的 CoW 实际体现
当前 Docker 默认使用 overlay2 驱动,它是 UnionFS 思想的高效实现,含三个关键目录:
- lowerdir:只读镜像层,按顺序拼接(冒号分隔)
- upperdir:容器可写层,存放所有写入和删除标记(whiteout)
- merged:对外暴露的统一挂载点,程序看到的“根文件系统”
例如,删除 /etc/passwd 时,overlay2 并不真删 lowerdir 中的文件,而是在 upperdir 创建一个 .wh.passwd 标记,使 merged 视图中该路径不可见——这也是 CoW 在语义层的延伸。








