This commit is contained in:
Baohua Yang
2026-02-09 12:56:12 -08:00
parent 63377d0431
commit b44c9acd6c
228 changed files with 326 additions and 271 deletions

View File

@@ -0,0 +1,248 @@
## 14.4 联合文件系统
联合文件系统UnionFS Docker 镜像分层存储的基础它允许将多个目录挂载为同一个虚拟文件系统
### 什么是联合文件系统
联合文件系统UnionFS是一种**分层轻量级**的文件系统它将多个目录"联合"挂载到同一个虚拟目录形成一个统一的文件系统视图
> **核心思想**将多个只读层叠加最上层可写形成完整的文件系统
```
┌─────────────────────────────────────────────────────────┐
│ 容器看到的文件系统 │
│ /bin /etc /lib /usr /var /app /data │
└────────────────────────┬────────────────────────────────┘
┌───────────────┴───────────────┐
│ UnionFS 联合挂载 │
└───────────────┬───────────────┘
┌────────────────────────┴────────────────────────────────┐
│ 容器层 (读写) │ /app/data/log.txt (新写入) │
├────────────────────┼────────────────────────────────────│
│ 镜像层3 (只读) │ /app/app.py │
├────────────────────┼────────────────────────────────────│
│ 镜像层2 (只读) │ /usr/local/bin/python │
├────────────────────┼────────────────────────────────────│
│ 镜像层1 (只读) │ /bin /etc /lib (基础系统) │
└────────────────────┴────────────────────────────────────┘
```
---
### 为什么 Docker 使用联合文件系统
Docker 选择联合文件系统作为其存储驱动主要基于以下几个核心优势
#### 1. 镜像分层复用
具体内容如下
```
nginx:alpine myapp:latest
│ │
└────────┬────────────┘
alpine:3.19 (共享基础层)
```
多个镜像共享相同的底层节省磁盘空间
#### 2. 快速构建
每个 Dockerfile 指令创建一层只有变化的层需要重建
```docker
FROM node:20 # 层1基础镜像
COPY package.json ./ # 层2依赖定义
RUN npm install # 层3安装依赖
COPY . . # 层4应用代码
```
代码变化时只需重建层4层1-3 使用缓存
#### 3. 容器启动快
容器启动时不需要复制镜像只需
1. 在镜像层上创建一个薄的可写层
2. 联合挂载所有层
---
### Copy-on-Write写时复制
当容器修改只读层中的文件时
```
修改前: 修改后:
┌─────────────────────┐ ┌─────────────────────┐
│ 容器层 (空) │ │ 容器层 │
├─────────────────────┤ │ /etc/nginx.conf ←──┼── 复制到容器层后修改
│ 镜像层 │ ├─────────────────────┤
│ /etc/nginx.conf │ │ 镜像层 │
└─────────────────────┘ │ /etc/nginx.conf │ (原文件仍在,但被遮蔽)
└─────────────────────┘
```
**流程**
1. 从只读层读取文件
2. 复制到容器的可写层
3. 在可写层中修改
4. 后续读取使用可写层的版本
---
### Docker 支持的存储驱动
Docker 可使用多种联合文件系统实现
| 存储驱动 | 说明 | 推荐程度 |
|---------|------|---------|
| **overlay2**| 现代 Linux 默认驱动性能优秀 | **推荐** |
| **aufs** | 早期默认兼容性好 | 遗留系统 |
| **btrfs** | 使用 Btrfs 子卷 | 特定场景 |
| **zfs** | 使用 ZFS 数据集 | 特定场景 |
| **devicemapper** | 块设备级存储 | 遗留系统 |
| **vfs** | 不使用 CoW每层完整复制 | 仅测试 |
#### 各发行版推荐
| Linux 发行版 | 推荐存储驱动 |
|-------------|-------------|
| Ubuntu 16.04+ | overlay2 |
| Debian Stretch+ | overlay2 |
| CentOS 7+ | overlay2 |
| RHEL 8+ | overlay2 |
| Fedora | overlay2 |
#### 查看当前存储驱动
运行以下命令
```bash
$ docker info | grep "Storage Driver"
Storage Driver: overlay2
```
---
### overlay2 工作原理
overlay2 是目前最推荐的存储驱动
```
┌─────────────────────────────────────────────────────────────┐
│ merged合并视图
│ 容器看到的完整文件系统 │
└─────────────────────────┬───────────────────────────────────┘
┌───────────────┴───────────────┐
│ OverlayFS │
└───────────────┬───────────────┘
┌────────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ upper │ │ lower2 │ │ lower1 │
│ (容器层) │ │ (镜像层) │ │ (基础层) │
│ 读写 │ │ 只读 │ │ 只读 │
└─────────────┘ └─────────────┘ └─────────────┘
```
- **lowerdir**只读的镜像层可以有多个
- **upperdir**可写的容器层
- **workdir**OverlayFS 的工作目录
- **merged**联合挂载后的视图
#### 文件操作行为
| 操作 | 行为 |
|------|------|
| **读取** | 从上到下查找第一个匹配的文件 |
| **创建** | upper 层创建 |
| **修改** | 如果在 lower 先复制到 upper 层再修改 |
| **删除** | upper 层创建 whiteout 文件标记删除 |
---
### 查看镜像层
运行以下命令
```bash
## 查看镜像的层信息
$ docker history nginx:alpine
IMAGE CREATED CREATED BY SIZE
a6eb2a334a9f 2 weeks ago CMD ["nginx" "-g" "daemon off;"] 0B
<missing> 2 weeks ago STOPSIGNAL SIGQUIT 0B
<missing> 2 weeks ago EXPOSE map[80/tcp:{}] 0B
<missing> 2 weeks ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B
<missing> 2 weeks ago COPY 30-tune-worker-processes.sh /docker-ent… 4.62kB
...
## 查看层的存储位置
$ docker inspect nginx:alpine --format '{{json .GraphDriver.Data}}' | jq
{
"LowerDir": "/var/lib/docker/overlay2/.../diff:/var/lib/docker/overlay2/.../diff",
"MergedDir": "/var/lib/docker/overlay2/.../merged",
"UpperDir": "/var/lib/docker/overlay2/.../diff",
"WorkDir": "/var/lib/docker/overlay2/.../work"
}
```
---
### 最佳实践
为了构建高效轻量的镜像我们在使用联合文件系统时应注意以下几点
#### 1. 减少镜像层数
具体内容如下
```docker
## ❌ 每条命令创建一层
RUN apt-get update
RUN apt-get install -y nginx
RUN rm -rf /var/lib/apt/lists/*
## ✅ 合并为一层
RUN apt-get update && \
apt-get install -y nginx && \
rm -rf /var/lib/apt/lists/*
```
#### 2. 避免在容器中写入大量数据
容器层的写入性能低于直接写入大量数据应使用
- 数据卷Volume
- 绑定挂载Bind Mount
#### 3. 使用 .dockerignore
排除不需要的文件可以
- 减小构建上下文
- 避免创建不必要的层
---
### 本章小结
| 概念 | 说明 |
|------|------|
| **UnionFS** | 将多层目录联合挂载为一个文件系统 |
| **Copy-on-Write** | 写时复制修改时才复制到可写层 |
| **overlay2** | Docker 默认推荐的存储驱动 |
| **分层好处** | 镜像复用快速构建快速启动 |
### 延伸阅读
- [镜像](../02_basic_concept/2.1_image.md)理解镜像分层
- [容器](../02_basic_concept/2.2_container.md)容器存储层
- [构建镜像](../04_image/4.5_build.md)Dockerfile 层的创建