Linux OverlayFS详解
OverlayFS 是 Linux 内核自带的联合挂载(Union Mount)文件系统:把多个目录叠成一个统一目录树,读写在逻辑上像操作普通文件夹,底层却可区分「只读基底」与「可写覆盖层」。Docker 镜像分层、Live 系统、测试回滚、增量备份背后,常见都有它的影子。
速览
- 四要素 :
lowerdir(只读层)+upperdir(读写层)+workdir(内部工作目录)→ 挂载到 merged 视图。- 读 :先 upper ,再按优先级查 lower。
- 写 :修改 lower 上已有文件 → 写时复制(CoW) 到 upper 再改;新建直接写在 upper。
- 删 lower 文件 :在 upper 建 whiteout 标记,不删 lower 实体。
- 依赖 :upper/work 须在支持 xattr 的文件系统上(如 ext4、xfs),且 同一文件系统。
text
merged(用户看到的统一视图)
↑ mount overlay
lowerdir(只读,可多目录) + upperdir(可写) + workdir(临时)
目录
一、概念与结构
- [1. OverlayFS 是什么](#1. OverlayFS 是什么)
- [2. 四层目录角色](#2. 四层目录角色)
二、读写与合并规则
- [3. 读取路径](#3. 读取路径)
- [4. 写入与写时复制 CoW](#4. 写入与写时复制 CoW)
- [5. 删除与 whiteout](#5. 删除与 whiteout)
- [6. 目录合并与 opaque](#6. 目录合并与 opaque)
三、使用与场景
- [7. 挂载命令与示例](#7. 挂载命令与示例)
- [8. 典型应用场景](#8. 典型应用场景)
- [9. 实战案例提要](#9. 实战案例提要)
四、运维
- [10. 性能与选型注意](#10. 性能与选型注意)
- [11. 速查卡](#11. 速查卡)
1. OverlayFS 是什么
| 特点 | 说明 |
|---|---|
| 联合挂载 | 多个目录合并为一个逻辑文件系统视图 |
| 非块设备 FS | 不直接管理磁盘块,叠在 ext4、xfs、btrfs 等已有 FS 之上 |
| 内核原生 | Linux 3.18+ 主线;容器生态广泛使用 |
| 与 UnionFS | 思路相近;现代 Linux 上 OverlayFS 是主流实现 |
底层文件系统
Overlay 层
用户视角
merged 挂载点
统一目录树
upperdir 可写
lowerdir 只读
可多层
workdir 内部
ext4 / xfs / ...
2. 四层目录角色
| 目录 | 别名 | 读写 | 作用 |
|---|---|---|---|
| lowerdir | 下层 / 只读层 | 只读 | 基底内容;可多个 ,逗号分隔;左侧优先级高于右侧 |
| upperdir | 上层 / 读写层 | 读写 | 所有变更(新建、修改、删除标记)落在这里 |
| workdir | 工作目录 | 内核用 | 必须为空 ;CoW 等操作的临时空间;必须与 upperdir 同一文件系统 |
| merged | 合并视图 / 挂载点 | 用户访问 | mount 后对外呈现的路径 |
text
lowerdir=A:B:C (只读;查找时 **A 优先于 B 优先于 C**,最左优先级最高)
upperdir=U (唯一可写)
workdir=W (空目录,与 U 同 FS)
merged=M (mount 目标)
Docker 对应关系(概念):
| Overlay | Docker |
|---|---|
| lowerdir 多层 | 镜像层(只读) |
| upperdir | 容器可写层 |
| merged | 容器内 / 所见根文件系统 |
3. 读取路径
是文件/目录
否
是
否
访问 merged 下路径
upperdir
存在?
返回 upper 内容
按优先级扫描 lowerdir
左 → 右
找到?
返回 lower 内容
不存在
| 规则 | 说明 |
|---|---|
| 文件 | upper 有则用 upper;否则在 lower 链中找第一个命中 |
| 目录 | 同名目录 合并 展示(见 §6) |
| whiteout | upper 上的特殊标记表示「下层文件已删除」,读时 不可见 |
4. 写入与写时复制 CoW
| 操作 | 行为 |
|---|---|
| 在 merged 新建文件/目录 | 直接创建在 upperdir |
| 修改 upper 已有文件 | 直接写 upper |
| 修改 lower 已有文件 | CoW :先复制到 upper,再改 upper 副本;lower 原文件不变 |
workdir upperdir lowerdir merged 应用 workdir upperdir lowerdir merged 应用 lower 中 foo 不变 写 lower 已有文件 foo CoW: 复制 foo 到 upper(用 workdir 辅助) 修改 upper/foo
CoW 的价值:
- 多实例 共享只读 lower (如镜像层)→ 省磁盘;
- 容器 秒级启动(不必复制整镜像);
- 回滚测试环境 → 删掉 upper 即可恢复 lower 视图。
代价 :首次修改大文件时有一次 完整复制 I/O;频繁改大量小文件时 元数据与 CoW 压力 上升(见 §10)。
5. 删除与 whiteout
| 删除对象 | 实际行为 |
|---|---|
| upper 中的文件 | 直接从 upper 删除 |
| 仅存在于 lower 的文件 | 在 upper 创建 whiteout (特殊字符设备或 xattr 标记),merged 视图中该路径 消失 ,lower 实体 仍保留 |
| 目录 | 规则类似;可能配合 opaque(§6) |
text
lower: /bin/app (只读镜像里)
用户: rm merged/bin/app
upper: 出现 whiteout 标记(不是真删 lower)
merged: /bin/app 不可见
whiteout 让「逻辑删除」与「物理只读层」共存,是镜像分层的基础机制之一。
6. 目录合并与 opaque
6.1 目录合并
上下层 同名目录 在 merged 中 合并列出:upper 与 lower 中的条目一起呈现(子项仍遵循「文件优先 upper、否则 lower」)。
text
lower/foo: a.txt b.txt
upper/foo: c.txt
merged/foo: a.txt b.txt c.txt (合并视图)
6.2 opaque 目录
若在 upper 某目录设置 opaque 属性(依赖 xattr):
- merged 中该目录 不再合并 lower 同名目录内容;
- 表现为 upper 目录 完全遮蔽 lower 侧同名树。
用于「上层整棵替换下层子树」的语义。
7. 挂载命令与示例
7.1 基本语法
bash
mount -t overlay overlay \
-o lowerdir=<lower>[,<lower2>...],upperdir=<upper>,workdir=<work> \
<mountpoint>
| 选项 | 含义 |
|---|---|
lowerdir |
一个或多个只读目录,逗号分隔,左优先 |
upperdir |
可写层 |
workdir |
空目录,与 upper 同 FS |
<mountpoint> |
merged 挂载点(需已存在) |
7.2 最小实验
bash
mkdir -p /tmp/ovl/{lower,upper,work,merged}
echo "from lower" > /tmp/ovl/lower/hello.txt
mount -t overlay overlay \
-o lowerdir=/tmp/ovl/lower,upperdir=/tmp/ovl/upper,workdir=/tmp/ovl/work \
/tmp/ovl/merged
cat /tmp/ovl/merged/hello.txt # from lower
echo "from upper" > /tmp/ovl/merged/new.txt
ls /tmp/ovl/upper/new.txt # 新文件只在 upper
echo "modified" >> /tmp/ovl/merged/hello.txt
# CoW 后 upper/hello.txt 存在,lower/hello.txt 仍为 from lower
umount /tmp/ovl/merged
7.3 多层 lower
bash
mount -t overlay overlay \
-o lowerdir=/layer2:/layer1,upperdir=/upper,workdir=/work \
/merged
layer2 中同名文件优先于 layer1。
7.4 常用挂载参数(选读)
| 参数 | 说明 |
|---|---|
index=on/off |
是否用索引优化硬链接等;部分场景 index=off 降开销 |
xino=on |
跨层 inode 编号展示(调试/兼容) |
redirect_dir=on |
目录重命名优化(较新内核) |
具体以当前内核 Documentation/filesystems/overlayfs.txt 为准。
8. 典型应用场景
| 场景 | lower | upper | 收益 |
|---|---|---|---|
| Docker / K8s 容器 | 镜像层(只读) | 容器层 | 共享镜像、隔离可写、快速创建 |
| Live CD / 只读根 | 系统只读分区 | U 盘或缓存分区 | 系统完整性 + 会话内可写 |
| 软件测试 / 升级 | 稳定系统快照 | 测试 upper | 失败则 删 upper 回滚 |
| 增量备份 | 全量备份目录 | 当日变更 upper | 只备份 upper ≈ 增量 |
增量备份
全量 lower
每日 upper
容器
镜像层 lower
容器 A upper
容器 B upper
9. 实战案例提要
9.1 Docker 分层
- 镜像各层只读叠加为 lower 链;
docker run创建 容器可写层 = upper;- 容器内
echo、apt install写入 upper;删除容器常删除 upper 层数据。
查看(宿主机,路径因存储驱动而异):
bash
docker inspect <container> --format '{{.GraphDriver.Data}}'
# overlay2: LowerDir, UpperDir, WorkDir, MergedDir
9.2 Live USB
- 系统镜像作 lower,用户数据分区作 upper 或独立挂载;
- 重启后保留 upper 中 home 等变更(需正确分区与挂载脚本)。
9.3 测试与升级回滚
text
lower = 当前稳定根文件系统快照(只读挂载)
upper = /test-upper
merged = 挂载后在此 chroot 或容器内测试
测试失败: umount merged && rm -rf /test-upper/*
9.4 增量备份与恢复
text
1. 全量 rsync → /backup/base (作 lower)
2. 每日变更 overlay upperdir=/backup/inc-20260526
3. 备份任务只同步 upper (增量体积小)
4. 恢复: overlay 挂载 base + 各日 upper 或合并策略还原视图
具体脚本因备份产品而异,核心是 lower 稳定 + upper 存差量。
10. 性能与选型注意
| 注意项 | 说明 |
|---|---|
| CoW 开销 | 首次改大文件复制整文件;海量小文件频繁写 → IOPS 与延迟敏感 |
| upper 文件系统 | 需 xattr (opaque、部分 whiteout);推荐 ext4、xfs |
| workdir | 必须空目录 ;与 upperdir 同一文件系统 |
| 优化思路 | 测试环境 upper 用 tmpfs ;评估 index=off;避免在 overlay 上再叠复杂 FS |
| 权限与 SELinux | 容器场景注意挂载标签、--security-opt;upper 权限需与进程匹配 |
| NFS 作 upper | 可行但 xattr/锁语义需验证,生产常本机块设备更稳 |
| 现象 | 可能原因 |
|---|---|
| mount 失败 invalid argument | workdir 非空、upper/work 不同 FS、lower 路径不存在 |
| 修改不生效 | 写的是 lower 只读挂载点而非 merged |
| 空间暴涨 | CoW 复制大文件 + upper 累积未清理 |
11. 速查卡
text
┌─────────────────────────────────────────────────────────┐
│ 读: upper → lower(左优先) │
│ 写: 新文件→upper;改 lower 文件→CoW 到 upper 再改 │
│ 删: upper 文件直接删;lower 文件→upper whiteout │
│ 目录: 合并;upper opaque → 屏蔽 lower 同名树 │
├─────────────────────────────────────────────────────────┤
│ mount -t overlay overlay -o lowerdir=,upperdir=,workdir= │
│ workdir: 空;与 upper 同 FS;upper 需 xattr(ext4/xfs) │
├─────────────────────────────────────────────────────────┤
│ Docker: 镜像=lower 链 容器层=upper 视图=merged │
└─────────────────────────────────────────────────────────┘
落地注意
- 生产容器多通过 overlay2 存储驱动使用 OverlayFS,路径与手工
mount示例不同,但 lower/upper/work/merged 语义一致。 - 内核与 util-linux 版本差异会导致挂载选项略有不同,部署前在目标环境做一次 mount 实验。
- 嵌入式/Android 等场景若涉及只读 system + 可写 data,需结合 dm-verity、AVB 等安全机制,不能仅靠 Overlay 理解全盘方案。
一句话 :OverlayFS 用 只读 lower + 可写 upper 叠出统一视图,靠 CoW 与 whiteout 实现省空间、快启动、易回滚------搞懂四层目录与读写规则,就抓住了 Docker 分层与大量「基底 + 差量」系统设计的底层逻辑。