镜像是只读层堆叠,每条dockerfile指令生成一层;容器启动时通过overlay2联合挂载:lowerdir(只读层)、upperdir(可写层)、merged(最终根文件系统),并依赖写时复制机制实现高效隔离。

直接从“分层”和“挂载”两个动作切入,比先背概念更有效。
先搞懂镜像为什么是“只读层堆叠”
每条 Dockerfile 指令(如 FROM、RUN、COPY)都会生成一个只读层,这些层按顺序摞在一起,形成镜像。关键点在于:
- 每一层只记录和上一层的差异(比如新增了哪些文件、删了哪些配置)
- 相同内容的层(如都用 alpine:latest 作基础)在本地只存一份,多个镜像共用
- 可以用 docker image inspect 镜像名 查看 Layers 字段,看到一串 SHA256 哈希值,每个就对应一层
再理解容器启动时发生了什么
运行容器不是“复制整个镜像”,而是通过联合文件系统(如 overlay2)做一次联合挂载:
- 把所有只读层设为 lowerdir
- 新建一个空的可写目录作为 upperdir
- 指定一个工作目录 workdir(overlay2 内部用,不用手动管)
- 最终把它们合并到 merged 目录下,这个 merged 就是容器里看到的根文件系统 /
重点掌握“写时复制”(Copy-on-Write)怎么起作用
这是联合文件系统隔离性和效率的核心机制:
- 容器读文件:优先从 upperdir 找;找不到就往下一层层查 lowerdir
- 容器改文件:如果该文件只在 lowerdir 中存在,系统会先把它完整拷贝到 upperdir,再修改 —— 这就是“写时复制”
- 容器删文件:不是真删 lowerdir 的,而是在 upperdir 创建一个“白名单”(.wh.* 文件),标记它被删除了
动手验证比纯看文档更牢靠
在 Linux 主机上跑几条命令,马上能看到结构:
- docker inspect 容器ID | grep graphdriver → 确认当前用的是 overlay2
- find /var/lib/docker/overlay2 -name "merged" | head -1 → 找到某个容器的 merged 目录
- 进那个 merged 目录,执行 ls -l /proc/1/root(容器内 PID 1 的 root)→ 会发现它软链到了 merged 路径











