overlay2的只读层物理结构位于/var/lib/docker/overlay2/目录下,每个镜像层对应一个以哈希值命名的子目录,其diff子目录存储该层实际文件内容;复用依赖内容哈希(diff_id/cache_id)而非镜像名,相同内容层共用同一diff目录,通过联合挂载(lowerdir叠加+upperdir可写层)向容器提供透明统一视图。

Overlay2 的只读层物理结构在哪
所有镜像层都真实存放在 /var/lib/docker/overlay2/ 目录下,每个层对应一个以哈希值命名的子目录(如 abc123-diff),里面是该层新增或变更的文件内容。这些目录本身不可写,且不随容器启动而变化。
执行 docker inspect <image-id></image-id> 可看到 GraphDriver.Data.Layers 字段,列出从底到顶的所有只读层路径;每层路径指向的就是 /var/lib/docker/overlay2/<layer-id>/diff</layer-id> 这个实际存储位置。
复用怎么发生的:靠内容哈希而非镜像名
Overlay2 判断是否复用某一层,依据是该层的 diff_id(构建时内容哈希)和 cache_id(运行时存储哈希)。只要两个镜像中某一层的内容完全一致,它们就指向磁盘上同一个 diff 目录。
- 比如
ubuntu:22.04和基于它的nginx:alpine,若共用 alpine 基础层,该层在磁盘仅存一份 -
docker pull redis:7.0和docker pull redis:7.0-alpine若共享某个 alpine 层,也只占用一次磁盘空间 - 本地构建时,
RUN apt install curl生成的层,只要命令和上下文完全相同,下次构建就会命中缓存,跳过执行并直接复用原有层
联合挂载如何让复用“透明可见”
当容器启动,Overlay2 将多个只读层(LowerDir)按顺序叠加,并在其上挂载一个可写层(UpperDir),最终通过 MergedDir 向容器暴露统一视图。
这个过程对应用完全透明:
- 读文件时,从
UpperDir开始找,找不到就逐层向下查LowerDir,直到第一个匹配项 - 写文件时,只复制被修改的文件到
UpperDir,原只读层保持原样,不影响其他容器或镜像 - 删除文件时,在
UpperDir创建白条文件(whiteout),屏蔽掉LowerDir中同名文件
验证复用的几个实用命令
快速确认是否真的复用了层:
-
docker history <image-name></image-name>:看各层大小,重复出现的<missing></missing>行往往对应共享基础层 -
docker image ls --digests:对比不同镜像的 digest,相同 digest 的镜像极可能共享底层 -
find /var/lib/docker/overlay2 -name "diff" | xargs ls -ld | head -10:观察多个镜像层是否指向同一组 diff 目录 -
docker inspect <container-id> | jq '.GraphDriver.Data.UpperDir, .GraphDriver.Data.LowerDir'</container-id>:直接查看当前容器挂载的上下层路径











