mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-10 11:54:37 +00:00
Add more content
This commit is contained in:
234
underly/ufs.md
234
underly/ufs.md
@@ -1,22 +1,230 @@
|
||||
# 联合文件系统
|
||||
|
||||
联合文件系统([UnionFS](https://en.wikipedia.org/wiki/UnionFS))是一种分层、轻量级并且高性能的文件系统,它支持对文件系统的修改作为一次提交来一层层的叠加,同时可以将不同目录挂载到同一个虚拟文件系统下(unite several directories into a single virtual filesystem)。
|
||||
## 什么是联合文件系统
|
||||
|
||||
联合文件系统是 Docker 镜像的基础。镜像可以通过分层来进行继承,基于基础镜像(没有父镜像),可以制作各种具体的应用镜像。
|
||||
联合文件系统(UnionFS)是一种**分层、轻量级**的文件系统,它将多个目录"联合"挂载到同一个虚拟目录,形成一个统一的文件系统视图。
|
||||
|
||||
另外,不同 Docker 容器就可以共享一些基础的文件系统层,同时再加上自己独有的改动层,大大提高了存储的效率。
|
||||
> **核心思想**:将多个只读层叠加,最上层可写,形成完整的文件系统。
|
||||
|
||||
Docker 中使用的 AUFS(Advanced Multi-Layered Unification Filesystem)就是一种联合文件系统。 `AUFS` 支持为每一个成员目录(类似 Git 的分支)设定只读(readonly)、读写(readwrite)和写出(whiteout-able)权限, 同时 `AUFS` 里有一个类似分层的概念, 对只读权限的分支可以逻辑上进行增量地修改(不影响只读部分的)。
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────┐
|
||||
│ 容器看到的文件系统 │
|
||||
│ /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 目前支持的联合文件系统包括 `OverlayFS`, `AUFS`, `Btrfs`, `VFS`, `ZFS` 和 `Device Mapper`。
|
||||
---
|
||||
|
||||
各 Linux 发行版 Docker 推荐使用的存储驱动如下表。
|
||||
## 为什么 Docker 使用联合文件系统
|
||||
|
||||
|Linux 发行版 | Docker 推荐使用的存储驱动 |
|
||||
| :-- | :-- |
|
||||
|Docker on Ubuntu | `overlay2` (16.04 +) |
|
||||
|Docker on Debian | `overlay2` (Debian Stretch), `aufs`, `devicemapper` |
|
||||
|Docker on CentOS | `overlay2` |
|
||||
|Docker on Fedora | `overlay2` |
|
||||
### 1. 镜像分层复用
|
||||
|
||||
在可能的情况下,[推荐](https://docs.docker.com/storage/storagedriver/select-storage-driver/) 使用 `overlay2` 存储驱动,`overlay2` 是目前 Docker 默认的存储驱动,以前则是 `aufs`。你可以通过配置来使用以上提到的其他类型的存储驱动。
|
||||
```
|
||||
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 默认推荐的存储驱动 |
|
||||
| **分层好处** | 镜像复用、快速构建、快速启动 |
|
||||
|
||||
## 延伸阅读
|
||||
|
||||
- [镜像](../basic_concept/image.md):理解镜像分层
|
||||
- [容器](../basic_concept/container.md):容器存储层
|
||||
- [构建镜像](../image/build.md):Dockerfile 层的创建
|
||||
|
||||
Reference in New Issue
Block a user