mirror of
https://github.com/yeasy/docker_practice.git
synced 2026-03-11 12:21:17 +00:00
222 lines
5.8 KiB
Go
222 lines
5.8 KiB
Go
## 12.4 联合文件系统
|
||
|
||
联合文件系统 (UnionFS) 是 Docker 镜像分层存储的基础,它允许将多个目录挂载为同一个虚拟文件系统。
|
||
|
||
### 12.4.1 什么是联合文件系统
|
||
|
||
联合文件系统 (UnionFS) 是一种 **分层、轻量级** 的文件系统,它将多个目录 “联合” 挂载到同一个虚拟目录,形成一个统一的文件系统视图。
|
||
|
||
> **核心思想**:将多个只读层叠加,最上层可写,形成完整的文件系统。
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
ContainerFS["容器看到的文件系统<br/>/bin /etc /lib /usr /var /app /data"]
|
||
UnionFS["UnionFS 联合挂载"]
|
||
|
||
ContainerLayer["容器层 (读写) : /app/data/log.txt (新写入)"]
|
||
ImageLayer3["镜像层3 (只读) : /app/app.py"]
|
||
ImageLayer2["镜像层2 (只读) : /usr/local/bin/python"]
|
||
ImageLayer1["镜像层1 (只读) : /bin /etc /lib (基础系统)"]
|
||
|
||
ContainerFS --> UnionFS
|
||
UnionFS --> ContainerLayer --> ImageLayer3 --> ImageLayer2 --> ImageLayer1
|
||
```
|
||
|
||
---
|
||
|
||
### 12.4.2 为什么 Docker 使用联合文件系统
|
||
|
||
Docker 选择联合文件系统作为其存储驱动,主要基于以下几个核心优势。
|
||
|
||
#### 1. 镜像分层复用
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Nginx["nginx:alpine"] --> Alpine["alpine:3.19 (共享基础层)"]
|
||
MyApp["myapp:latest"] --> Alpine
|
||
```
|
||
|
||
多个镜像共享相同的底层,节省磁盘空间。
|
||
|
||
#### 2. 快速构建
|
||
|
||
每个 Dockerfile 指令创建一层,只有变化的层需要重建:
|
||
|
||
```docker
|
||
FROM node:20 # 层1:基础镜像
|
||
COPY package.json ./ # 层2:依赖定义
|
||
RUN npm install # 层3:安装依赖
|
||
COPY . . # 层4:应用代码
|
||
```
|
||
|
||
代码变化时,只需重建层 4,层 1-3 使用缓存。
|
||
|
||
#### 3. 容器启动快
|
||
|
||
容器启动时不需要复制镜像,只需:
|
||
|
||
1. 在镜像层上创建一个薄的可写层
|
||
2. 联合挂载所有层
|
||
|
||
---
|
||
|
||
### 12.4.3 Copy-on-Write (写时复制)
|
||
|
||
当容器修改只读层中的文件时:
|
||
|
||
```mermaid
|
||
flowchart LR
|
||
subgraph Before ["修改前"]
|
||
direction TB
|
||
B_C["容器层 (空)"]
|
||
B_I["镜像层<br/>/etc/nginx.conf"]
|
||
end
|
||
|
||
subgraph After ["修改后"]
|
||
direction TB
|
||
A_C["容器层<br/>/etc/nginx.conf ← 复制到容器层后修改"]
|
||
A_I["镜像层<br/>/etc/nginx.conf (原文件仍在,但被遮蔽)"]
|
||
end
|
||
B_C --- B_I
|
||
A_C --- A_I
|
||
```
|
||
|
||
**流程**:
|
||
|
||
1. 从只读层读取文件
|
||
2. 复制到容器的可写层
|
||
3. 在可写层中修改
|
||
4. 后续读取使用可写层的版本
|
||
|
||
---
|
||
|
||
### 12.4.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
|
||
```
|
||
|
||
---
|
||
|
||
### 12.4.5 overlay2 工作原理
|
||
|
||
overlay2 是目前最推荐的存储驱动:
|
||
|
||
```mermaid
|
||
flowchart TD
|
||
Merged["merged (合并视图)<br/>容器看到的完整文件系统"]
|
||
OverlayFS["OverlayFS"]
|
||
|
||
Upper["upper<br/>(容器层)<br/>读写"]
|
||
Lower2["lower2<br/>(镜像层)<br/>只读"]
|
||
Lower1["lower1<br/>(基础层)<br/>只读"]
|
||
|
||
Merged --> OverlayFS
|
||
OverlayFS --> Upper
|
||
OverlayFS --> Lower2
|
||
OverlayFS --> Lower1
|
||
```
|
||
|
||
- **lowerdir**:只读的镜像层 (可以有多个)
|
||
- **upperdir**:可写的容器层
|
||
- **workdir**:OverlayFS 的工作目录
|
||
- **merged**:联合挂载后的视图
|
||
|
||
#### 文件操作行为
|
||
|
||
| 操作 | 行为 |
|
||
|------|------|
|
||
| **读取** | 从上到下查找第一个匹配的文件 |
|
||
| **创建** | 在 upper 层创建 |
|
||
| **修改** | 如果在 lower 层,先复制到 upper 层再修改 |
|
||
| **删除** | 在 upper 层创建 whiteout 文件标记删除 |
|
||
|
||
---
|
||
|
||
### 12.4.6 查看镜像层
|
||
|
||
```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"
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
### 12.4.7 最佳实践
|
||
|
||
为了构建高效、轻量的镜像,我们在使用联合文件系统时应注意以下几点。
|
||
|
||
#### 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
|
||
|
||
排除不需要的文件可以:
|
||
|
||
- 减小构建上下文
|
||
- 避免创建不必要的层
|
||
|
||
---
|