先看一个框架图,有疑问我们可以评论区或者加微信群一起讨论容器的文件系统之所以“看起来像一个完整系统”,核心不是复制了一套 Linux rootfs,而是依赖一种典型的内核机制:分层合并文件系统 OverlayFS。它解决的不是“存储问题”,而是一个更关键的问题:如何在不复制数据的情况下,让多个容器共享同一套镜像,同时保持各自可写隔离。
第一章:容器文件系统的真实模型是“视图拼接”
容器文件系统本质是一个多层只读 + 单层可写的叠加模型:
lowerdir(镜像层1)lowerdir(镜像层2)lowerdir(镜像层3) ↓upperdir(容器可写层) ↓merged(统一视图)
OverlayFS 的关键不是“文件系统”,而是把多个目录虚拟合成为一个统一目录视图,容器看到的是 merged,但底层可能来自几十个镜像层共享结果。
第二章:OverlayFS 的三层结构——lower / upper / work
OverlayFS 的核心结构由三部分组成:
1)lowerdir(只读层)
ubuntu layer ↓nginx layer ↓app layer
2)upperdir(可写层)
每个容器独立:
/var/lib/docker/overlay2/<container-id>/diff
所有写操作都发生在这里。
3)workdir(内部工作区)
用于:
最终挂载点:/merged → 容器看到的根目录
第三章:路径查找机制——OverlayFS 如何“骗过 VFS”
当容器访问一个文件时,例如:cat /etc/nginx/nginx.conf
OverlayFS 的查找逻辑如下:
1. 先查 upperdir2. 未命中 → 依次查 lowerdir(从上到下)3. 返回第一个命中的文件
流程图:
lookup(path) ↓ upperdir exists? / \ yes no ↓ ↓ return search lowerdir stack ↓ first hit wins
关键是OverlayFS 并不“合并文件”,而是“按优先级查找文件”。
第四章:写时复制(COW)机制——容器“可写”的关键
lowerdir 是只读的,那容器修改文件是通过:Copy-on-Write(写时复制)
例如:echo "test" >> /etc/config
执行过程:
1. 文件在 lowerdir2. 触发写操作3. 复制到 upperdir4. 修改 upperdir 副本5. merged 覆盖显示
结构变化:
lowerdir: /etc/config (immutable)upperdir: /etc/config (copied + modified)
主要是写操作永远不会污染镜像层
第五章:删除机制——whiteout 的“隐藏逻辑”
OverlayFS 删除文件不是 delete,是 whiteout(白化标记)
例如:rm /bin/ls,不会真正删除 lowerdir 文件,是在 upperdir 创建标记:
upperdir: .wh.ls查找逻辑变为:if .wh.<file> exists: treat as deleted
效果:
lowerdir 文件仍存在
merged 视图不可见
第六章:容器启动流程——OverlayFS 如何参与整个链路
容器启动时 OverlayFS 的挂载过程是关键步骤:
docker run ↓containerd ↓runc ↓mount overlayfs ↓pivot_root ↓execve
核心 mount 调用:
mount("overlay", "/merged", "overlay", 0, "lowerdir=layer3:layer2:layer1, upperdir=/diff, workdir=/work");
之后:/merged → container rootfs
再通过:pivot_root("/merged"),完成容器“根目录切换”。
第七章:为什么 OverlayFS 足够快但不是完美
OverlayFS 的优势来自三个点:
1)零拷贝启动
镜像层共享:N containers → 1 image
2)写入隔离
所有修改进入 upperdir:write → upperdir only
3)page cache 复用
lowerdir 是只读,极易命中缓存。但它也有明显限制:
(1)层级越多,查找越慢
lookup cost ∝ number of layers
(2)写放大问题
写一个文件 → copy → upperdir 增长
(3)不适合高频写场景,主要是适合:读多写少(典型的容器是这样的)
OverlayFS 并不是“容器文件系统”,是让多个镜像层共享 + 单容器可写 + 统一视图呈现的合成引擎
整体模型是:
容器 rootfs = OverlayFS(lower layers + upper layer + workdir)
主要是解决三个关键问题:
镜像复用(共享 lowerdir)
启动加速(无需拷贝)
写隔离(upperdir + COW)