Linux UnionFS
Linux UnionFS(联合文件系统)详解。
内容:概念 -> 内核实现 -> 主流实现 -> 行为细节 -> 与容器的关系 -> 性能与陷阱 -> 最佳实践
UnionFS 是一种“把多个目录(分支)叠加成一个统一视图”的文件系统机制。
- 上层:可写层(upper)
- 下层:只读层(lower)
- 对用户呈现:一个完整目录树
📌 UnionFS ≠ OverlayFS(OverlayFS 是内核实现之一)
应用层(可写)
---------
基础镜像层(只读)
---------
OS 层(只读)
- 节省空间
- 快速创建
- 层复用
- Live 系统:只读 + 内存写层
- 回滚 / 快照
- 嵌入式系统
- 安全系统
每一层目录叫一个 branch
- lower branch:只读
- upper branch:可写
用于“在上层删除下层文件”的特殊标记
- 删除 ≠ 真删除
- 是创建 .wh.<filename>
📌 这是 UnionFS 的核心魔法之一
当你:
echo hello >> /bin/ls
实际发生的是:
- /bin/ls 从 lower copy 到 upper
- 在 upper 中修改
- lower 不变
- 外部模块
- 稳定性一般
- 已基本弃用
- 功能强大
- 非主线内核
- Ubuntu 曾长期使用
📌 RHEL 系列从未支持 AUFS
现在事实上的标准
- Linux 内核原生
- Docker / Podman / CRI-O 默认
- RHEL / AlmaLinux / Rocky 全支持
lowerdir=/layers/base:/layers/app
upperdir=/layers/write
workdir=/layers/work
挂载后:
/merged
mount -t overlay overlay \
-o lowerdir=lower,upperdir=upper,workdir=work \
merged
📌 workdir 用于原子操作(必须)
读:
- upperdir
- 从上到下依次 lowerdir
写:
- lower -> copy 到 upper -> 写
删:
- 创建 whiteout
- 同一路径
- 不同层 inode 不同
📌 影响:
- bind mount
- inode cache
- 某些数据库
- OverlayFS 对 hardlink 支持有限
- 跨层 hardlink 基本不可用
- 跨层 rename 实际是:
- copy + delete
📌 对 fsync 敏感程序危险
- 触发 COW
- 文件被复制到 upper
container_rw_layer (upper)
--------------------------
image layer N
--------------------------
image layer N-1
--------------------------
base OS layer
- 不复制 rootfs
- 只 mount 联合视图
- metadata 操作多
- copy-up 代价大
- fsync 穿透层
原因:
- fsync 不可控
- rename 不安全
- inode 不稳定
- 白障文件膨胀
📌 这就是 “数据库为什么不适合跑在容器” 的底层原因之一
- Git
- 编译缓存
- npm / pip
- stat
- readdir
- lookup
- 第一次写 = 全文件复制
- 大文件尤其明显
- upper + lower 组合
- 存储栈不透明
- rootfs:overlay2
- 数据目录:bind mount / volume
-v /data/mysql:/var/lib/mysql
- 只读 OS + overlay
- 日志 / 数据单独盘
- ❌ overlay2 存数据库数据
- ❌ overlay2 跑消息队列
- ❌ overlay2 做性能 benchmark
| 特性 | OverlayFS | bind mount | tmpfs |
|---|---|---|---|
| 分层 | ✅ | ❌ | ❌ |
| 可写 | ✅ | ✅ | ✅ |
| 性能 | 中 | 高 | 高 |
| 数据安全 | 低 | 高 | 低 |
| 适合数据库 | ❌ | ✅ | ❌ |
UnionFS 是 “视图文件系统”,不是 “数据文件系统”。
它的使命是:
- 镜像
- 分层
- 复用
不是:
- 高一致性
- 高 fsync 可靠性
- 数据持久化