Docker + containerd 存储和启动完整原理
明白了,你想要的不是简单概述,而是 从底层角度完整解释 Docker graphdriver、containerd snapshot/task、overlay2 merged 层及它们的关联和作用,并说明每个概念在启动流程和权限检查中的角色。下面我给你做一个 彻底完整的结构化说明。
Docker + containerd 存储和启动完整原理
1️⃣ Graphdriver(Docker 文件系统驱动)
-
概念:Docker 的 graphdriver 是 Docker 层管理的核心组件,用来管理镜像层和容器可写层的存储和挂载。
-
作用:
-
挂载镜像层和容器可写层到最终文件系统(即 overlay2 merged 层)
-
管理 Copy-On-Write(COW)机制
-
处理 graph 存储结构(layer 之间的依赖关系)
-
-
常见类型:
-
overlay2(现代默认,基于 OverlayFS) -
aufs(老式,Linux 专用) -
btrfs、zfs(高级文件系统)
-
-
初始化流程:
-
检查底层文件系统是否支持所需功能(xattr, metacopy 等)
-
创建 overlay2 工作目录:
diff/,work/,merged/ -
在 metacopy-check 目录做权限/功能检测(如 chmod 测试)
-
⚠️ 报错点:你图中的
operation not permitted就是 graphdriver 初始化 overlay2 metacopy 检查失败。
2️⃣ Overlay2 层解释
Overlay2 是 Docker 默认 graphdriver 的实现,结构如下:
/var/lib/docker/overlay2/<layer-id>/diff # 镜像或容器的只读/可写层内容work # OverlayFS 工作目录,用于合并写操作merged # 容器挂载后的最终文件系统(读写视图)lower # 下层只读镜像层metacopy-check* # 权限/功能检测
-
diff:镜像 layer 或容器 upper layer 的实际文件
-
work:OverlayFS 内部使用的工作目录,支持 COW
-
merged:容器启动后挂载的 最终可访问文件系统
-
lower:只读的镜像 layer
-
metacopy-check:Docker 在启动时检查 overlay2 是否允许
chmod等操作
这些层通过 graphdriver 管理,决定容器文件系统的挂载方式。
3️⃣ containerd 核心概念
containerd 是 Docker 后端的容器管理守护进程,主要负责 snapshot + task + runtime。
3.1 Snapshot
-
概念:snapshot 是 containerd 对文件系统层的抽象。
-
作用:
-
保存镜像层或容器可写层
-
提供 OverlayFS 的 COW(copy-on-write)功能
-
-
目录:
/var/lib/containerd/io.containerd.snapshotter.v1.overlayfs/<snapshot-id>/fs/ # 实际挂载内容metadata.json -
类型:
-
active snapshot:容器运行时的可写层 -
committed snapshot:镜像 layer,只读层
-
3.2 Task
-
概念:task 是 containerd 管理的 运行中容器实例,对应 runc 创建的进程。
-
作用:
-
对应一个 OCI 容器实例
-
持有 snapshot(文件系统挂载)、namespace、cgroup 等信息
-
-
存储:
/var/lib/containerd/runtime/v2/task/<task-id>/spec.json # OCI runtime specstate.json # 运行状态
3.3 Merged 层
-
概念:merged 层是 snapshot 挂载 OverlayFS 后的最终视图。
-
作用:
-
对容器和进程可见的文件系统
-
合并上层可写层 (upper) + 下层只读层 (lower)
-
-
由谁创建:containerd 通过 snapshot 挂载 OverlayFS,runc 使用 merged 层作为容器根文件系统。
-
权限检查点:
-
dockerd graphdriver 初始化 overlay2 → 检查 metacopy
-
containerd snapshot 挂载 merged → 需要 root 权限
-
runc 挂载 merged → 创建 namespace & cgroup,需要 root 权限
-
4️⃣ 元数据关联(config → snapshot → task → merged)
Docker config.json│▼
containerd metadata (BoltDB)snapshot_id ↔ task_id ↔ layer_id ↔ image blob│▼
overlay2 merged / upper / lower (graphdriver)│▼
runc 启动进程 → kernel namespace & cgroup
-
解释:
-
config.json:容器配置
-
BoltDB:containerd 维护 snapshot ↔ task ↔ layer 的映射
-
overlay2 merged:最终挂载文件系统
-
runc:执行容器进程,挂载 merged,创建 namespace & cgroup
-
5️⃣ 容器启动流程完整说明
-
docker CLI → dockerd
-
创建 config.json
-
初始化 graphdriver → overlay2 初始化、metacopy 检查
-
调用 containerd gRPC API
-
-
containerd
-
创建 snapshot → 挂载 OverlayFS
-
生成 task → 保存 snapshot 与 container 映射
-
调用 runc 执行 OCI spec
-
-
runc
-
创建 namespace、cgroup
-
挂载 merged 文件系统
-
启动容器进程
-
-
kernel
-
管理命名空间、cgroup、IO、进程调度
-
OverlayFS 在内核层处理 COW
-
6️⃣ 权限检查和报错点
| 阶段 | 检查点 | 可能报错 | 原因 |
|---|---|---|---|
| dockerd graphdriver init | metacopy-check | operation not permitted | overlay2 无法 chmod、SELinux/只读 FS |
| containerd snapshot mount | fs permission | permission denied | rootless / SELinux / 不支持的 FS |
| runc mount merged | root mount | permission denied | merged 挂载失败,容器无法启动 |
7️⃣ 解决方案总结
# 修复目录权限
sudo chown -R root:root /var/lib/docker
sudo chmod -R 700 /var/lib/docker# 临时关闭 SELinux
sudo setenforce 0# 确保 dockerd root 启动
sudo systemctl daemon-reload
sudo systemctl restart docker# 使用本地磁盘(overlay2 不支持 NFS)
✅ 这样,graphdriver、snapshot、task、merged 都有了完整解释:
-
graphdriver → Docker 层管理器,初始化 overlay2
-
snapshot → containerd 对文件系统层的抽象
-
task → containerd 管理的运行中容器实例
-
merged → 容器最终挂载的 OverlayFS 可写视图
它们之间的 数据流 + 权限依赖在启动流程中一目了然。
如果你需要,我可以帮你画一个 “graphdriver → snapshot → task → merged → runc → kernel” 权限检查完整流程图,把 metacopy、OverlayFS、task、merged 的关系可视化,非常直观。
你希望我画吗?