4. 容器与快照基础:容器根文件系统(snapshot)的创建、挂载与生命周期
在 containerd 中,容器的根文件系统并非完整的操作系统镜像副本,而是通过 快照(Snapshot) 机制构建的轻量级、分层视图。理解快照的创建、挂载与生命周期,是掌握磁盘容量释放与垃圾回收的前提。本节将深入剖析这一核心机制。
4.1 快照(Snapshot)的核心概念
快照是 containerd 对容器镜像层和容器读写层的一种抽象管理单元。它基于 OverlayFS 或类似联合文件系统技术,实现了以下关键特性:
- 分层复用:多个容器可以共享相同的只读镜像层,仅在各自的读写层记录变更。
- 写时复制(Copy-on-Write, CoW):对容器根文件系统的修改仅在写入时复制到上层,极大节省磁盘空间。
- 高效创建:创建新容器时,无需复制整个文件系统,只需创建一个指向已有层的轻量级快照。
关键术语:在 containerd 中,“快照”通常指代一个文件系统层或视图,而非传统意义上的时间点备份。其核心价值在于 共享 与 隔离 的平衡。
4.2 快照的层级结构:从镜像层到容器层
一个容器的根文件系统由多层快照组成,形成一个从底向上、从只读到可写的层级链。下图展示了典型的四层结构:
4.3 快照的创建与挂载流程
当 containerd 启动一个容器时,快照的创建与挂载遵循以下步骤:
- 解析镜像:从镜像仓库拉取或本地缓存中获取镜像的 manifest 和层列表。
- 准备快照链:为镜像的每一层创建只读快照,并建立父子关系。
- 创建容器快照:在镜像顶层之上,创建一个可读写的容器快照(即 active snapshot)。
- 挂载文件系统:使用 OverlayFS 将只读层与读写层联合挂载到容器的 rootfs 路径。
- 启动容器进程:容器进程以挂载后的 rootfs 作为根文件系统运行。
挂载命令示例(简化):containerd 内部通过类似以下命令实现联合挂载:
mount -t overlay overlay \
-o lowerdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/1/fs:\
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/2/fs:\
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/3/fs,\
upperdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/4/fs,\
workdir=/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/4/work \
/run/containerd/io.containerd.runtime.v2.task/default/<container-id>/rootfs
4.4 快照的生命周期状态
containerd 的快照管理器中,每个快照都处于以下生命周期状态之一:
| 状态 | 描述 | 磁盘占用 | 可回收性 |
|---|---|---|---|
| Active | 当前被容器使用的读写快照,容器进程正在运行 | 持续增长(写入时复制) | 不可回收 |
| Committed | 已提交的只读快照,通常对应镜像层或已停止容器的快照 | 固定大小 | 若未被引用则可回收 |
| View | 只读视图快照,用于临时访问,不参与写操作 | 无额外占用 | 可随时释放 |
| Removed | 已被标记删除,但可能仍有其他快照依赖 | 待释放 | 依赖解除后回收 |
4.5 快照的引用计数与垃圾回收基础
containerd 通过 引用计数(Reference Count) 机制管理快照的生命周期。每个快照维护一个计数器,记录有多少上层快照或容器正在使用它。当引用计数降为零时,该快照即成为垃圾回收的候选对象。
常见陷阱:即使容器已停止,其读写层快照仍可能被保留(Committed 状态),直到被显式删除或触发垃圾回收。这是磁盘空间泄漏的常见原因之一。
下图展示了快照之间的引用关系与回收判定逻辑:
4.6 快照存储目录结构
containerd 默认将快照数据存储在 /var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/ 目录下。每个快照对应一个数字 ID 的子目录,其内部结构如下:
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/snapshots/
├── 1/
│ ├── fs/ # 快照的文件系统内容
│ └── work/ # OverlayFS 工作目录(仅读写层有)
├── 2/
│ ├── fs/
│ └── work/
├── 3/
│ └── fs/ # 只读层无 work 目录
├── metadata.db # 快照元数据数据库(boltdb)
└── ...
磁盘容量分析切入点:通过检查
metadata.db 中的引用计数和快照大小,可以精确识别哪些快照占用了大量磁盘空间且不再被引用,这是后续垃圾回收策略的核心数据来源。
4.7 快照生命周期对磁盘容量的影响
快照的生命周期直接决定了磁盘空间的占用模式。下表总结了不同阶段的空间特征:
| 阶段 | 空间占用特征 | 典型场景 | 对GC的影响 |
|---|---|---|---|
| 容器运行中 | 读写层持续增长,镜像层固定 | 生产服务运行 | 不可回收 |
| 容器已停止 | 读写层变为Committed,不再增长 | 任务型容器执行完毕 | 若未被其他容器引用,可回收 |
| 镜像已删除 | 镜像层快照仍可能被其他容器引用 | 清理旧镜像 | 需检查引用计数 |
| 孤立快照 | 无任何容器或镜像引用 | 异常中断或清理残留 | 优先回收目标 |