Docker镜像由按序堆叠的只读层组成,每层为构建指令产生的增量快照,依赖UnionFS(如overlay2)实现多层合并与写时复制;容器运行时 atop 可写层,共享基础层以节省空间。

Docker镜像不是单个大文件,而是一组按顺序堆叠的只读层(layers),每一层代表一次构建操作的变更。这种分层结构依赖底层存储驱动(如overlay2)提供的联合文件系统(UnionFS)能力,实现高效复用、快速启动和空间节省。
镜像层的本质:只读增量快照
每次 docker build 中的指令(如 RUN、COPY、ADD)都会生成一个新层,该层仅保存与上一层相比的文件增删改差异(diff)。基础镜像(如 ubuntu:22.04)本身也由多个层构成,最底层通常是操作系统根文件系统的精简副本。
- 所有镜像层默认只读,运行容器时才在顶部叠加一个可写层(container layer)
- 同一基础镜像的不同衍生镜像(如 python:3.11 和 node:18)会共享底层共用层,降低磁盘占用
-
docker history
可查看每层对应的构建指令、大小及创建时间
UnionFS如何“合并”多层目录视图
UnionFS(如 overlay2)将多个目录“叠加”成一个统一的挂载点。Docker 启动容器时,它把镜像各只读层 + 一个空的可写层,按顺序合并为一个逻辑文件系统。访问文件时,系统从上到下查找——可写层优先,未命中则向下穿透,直到找到或确认不存在。
- 写入新文件 → 落入可写层(copy-on-write)
- 修改已有文件 → 先从只读层复制到可写层再编辑(copy-on-write)
- 删除文件 → 在可写层放置一个“whiteout”标记,屏蔽下层同名文件(overlay2 使用 .wh.* 文件)
为什么分层会影响构建效率和镜像大小
层是缓存和复用的基本单位,但也是膨胀和冗余的源头。Docker 构建过程按指令逐层提交,一旦某层变化,其后所有层均失效重建;同时,被上层删除或覆盖的文件仍物理存在于旧层中,无法自动清理。
- 避免在不同层重复安装/删除软件包(如 apt update + apt install + apt clean 应写在同一 RUN 中)
- 使用多阶段构建(multi-stage build),仅将最终需要的二进制或配置复制到轻量运行镜像,丢弃构建依赖层
- docker image prune -a 可清理悬空层(dangling layers),但不会删除被任意镜像引用的层
实际验证:查看镜像层与存储布局
以本地镜像为例,可通过文件系统路径观察真实分层结构(以 overlay2 驱动为例):
- 镜像层元数据存于 /var/lib/docker/image/overlay2/imagedb/content/sha256/,记录每层 diffID 和 chainID
- 各层实际内容在 /var/lib/docker/overlay2/
/diff/ ,对应文件差异树 - 运行中容器的联合挂载点位于 /var/lib/docker/overlay2/
/merged/ ,即你 exec 进去看到的根文件系统

















