联合文件系统与 overlay2
UnionFS 的核心思想:把多个目录分层叠加,对外呈现为一个统一的文件系统视图。 Docker 默认的存储驱动是overlay2,它基于 Linux 内核的 OverlayFS 实现。查看你的驱动:
容器的四层目录结构
容器运行时,overlay2 为它准备四个目录。用docker inspect 可以看到:
镜像层(lowerdir)
镜像层是只读的,来自docker build 的每条指令。同一台宿主机上,多个镜像共享相同的基础层,磁盘上只存一份。
查看一个镜像的分层:
init 层
LowerDir 里那个带 -init 后缀的目录就是 init 层。它是容器启动时 Docker 在镜像层之上注入的一个特殊只读层,内容只有几个容器专属的配置文件:
/etc/hostname:容器的主机名/etc/hosts:容器的 hosts 记录/etc/resolv.conf:DNS 解析配置
容器层(upperdir)
容器层是唯一可写的一层。容器内新建、修改、删除文件,全部落在这里:- 新建文件:直接写进容器层
- 修改镜像层文件:先把文件从只读层复制上来(copy-up),再修改
- 删除镜像层文件:在容器层写一个 whiteout 标记,把下层文件”遮住”,而不是真的删除只读层
merge 层(mergeddir)
merge 层把只读层和容器层叠加后的统一视图。容器进程看到的/ 就是它。
同名文件的覆盖规则:上层优先。容器层(upperdir)的文件会覆盖镜像层(lowerdir)的同名文件;whiteout 标记则让下层的文件”消失”。
写时复制(Copy-on-Write)
修改只读层文件的完整过程:1
发起写入
容器内进程修改一个来自镜像层的文件,比如
sed -i 改配置。2
copy-up
OverlayFS 把该文件从 lowerdir 复制到 upperdir。文件越大,这一步越慢,但只在首次修改时发生。
3
写入容器层
修改落在 upperdir 的副本上,镜像层原件保持不变。之后对该文件的读写都直接走容器层。
写时复制保证了镜像层的不可变性:一百个容器共用一个镜像层,谁也改不到它。代价是首次修改大文件有复制开销。
实地查看一个容器的分层
1
启动一个实验容器
2
找到它的分层目录
3
在容器里制造一个改动
4
在宿主机上验证
与数据持久化的关系
容器层(upperdir)的生命周期和容器绑定——docker rm 之后,这一层连同里面的数据一起删除。这就是为什么生产数据必须放到 Volume 里,见 Docker 存储。
延伸阅读
- Docker 镜像:镜像分层的构建视角
- Docker 存储:用 Volume 持久化数据
- Docker 生产实践:分层结构对生产部署的影响