Docker 存储原理精要
1. 镜像分层(Union File System, UnionFS)
- 核心思想:把只读镜像层 + 读写容器层叠加在一起,形成最终文件系统视图。
- 实现驱动:
- overlay2(CentOS 7+/Ubuntu 16.04+ 默认)
- aufs(早期 Ubuntu)
- btrfs、zfs、devicemapper(已逐渐弃用)
- 只读层(image layers)
- 每层对应 Dockerfile 的一条指令。
- 层与层之间通过 CoW(写时复制)共享数据,节省磁盘。
- 读写层(container layer)
- 容器启动时自动创建,仅保存运行时修改。
- 删除容器即删除该层(除非 commit 成新镜像)。
2. 写时复制(Copy-on-Write, CoW)
| 读操作 | 写操作 |
| 从镜像层直接读取 | **首次写入** → 将目标文件复制到读写层再修改;<br>**后续写入** → 直接在读写层修改。 |
> 优点:
> - 镜像层共享,减少冗余;
> - 启动容器只需极少量磁盘空间。
3. 存储驱动(Storage Driver)
- 职责**
- 管理层(layer)与挂载点;
- 实现 CoW、快照、配额等。
- overlay2 目录结构速查*
/var/lib/docker/
├── overlay2/ # 层数据
│ ├── <layer-id>/ # 每层一个目录
│ │ ├── diff/ # 层内容
│ │ └── link # 短名符号链接
├── image/overlay2/ # 元数据、layerdb
└── containers/<id>/ # 容器读写层(含挂载信息)
- 性能小贴士*
- 大量随机小写 → 选 overlay2 优于 aufs;
- 需要文件级快照 → 选 btrfs/zfs;
- SELinux 环境 → 开 `overlay2.override_kernel_check=true`。
4. 数据持久化三板斧
| 方式 | 场景 | 特点 |
| Volume(推荐) | 生产数据、数据库 | 独立于容器生命周期,支持 NFS、Ceph 等远程存储。 |
| Bind Mount | 开发调试 | 直接把宿主机目录挂进容器,路径硬编码,可移植性差。 |
|*tmpfs Mount | 敏感或临时数据 | 驻留内存,重启即失,不占用宿主机磁盘。 |
- 常用命令速记
bash
docker volume create pgdata
docker run -d -v pgdata:/var/lib/postgresql/data postgres:15
5. 磁盘空间回收
- 一键清理(慎用):
bash
docker system prune -a --volumes
- 精准瘦身:
- 删除已停止容器:`docker container prune`
- 删除 dangling 镜像:`docker image prune`
- 删除未使用卷:`docker volume prune`
6. 常见面试/考点速答
1. 为什么镜像拉取时显示多层下载?
每层对应 registry 的一个 blob,可并发、可复用。
2. 容器里修改文件会变慢?
首次写触发 CoW 复制,大文件尤为明显。
3. 如何查看某容器实际占用的磁盘?
`docker ps -s` 查看 `size` 与 `virtual` 两列。
4. **overlay2 与 overlay 区别?
overlay2 支持多层(>128)且 inode 利用率更高。