2. Containerd 架构深度解析:gRPC API、Shim 进程、Snapshotter、运行时的协作流程
在集群节点扩容场景中,理解 Containerd 的内部协作机制是进行资源分配与性能调优的前提。本章将深入剖析 Containerd 的核心组件——gRPC API、Shim 进程、Snapshotter 以及 运行时(runc/runsc)——之间的数据流与协作关系,揭示从用户请求到容器进程启动的完整链路。
2.1 整体架构与协作流程概览
Containerd 采用模块化设计,各组件通过 gRPC 协议进行通信。下图展示了从客户端发起请求到容器运行的核心协作流程:
关键认知:Shim 进程是 Containerd 架构中最重要的设计之一,它使得容器运行时与 Containerd 主进程解耦,即使主进程重启,容器也不会受到影响。
2.2 gRPC API 层:统一的通信入口
gRPC API 是 Containerd 对外暴露的唯一接口,所有客户端(如 ctr CLI、kubelet)都通过此接口与 Containerd 交互。API 定义在 containerd/services 包中,主要服务包括:
| 服务名称 | 核心 RPC 方法 | 功能描述 |
|---|---|---|
| Namespaces | Create, List, Delete |
管理容器命名空间,实现多租户隔离 |
| Containers | Create, Get, Update |
容器元数据管理,不涉及运行时状态 |
| Tasks | Create, Start, Kill, Exec |
容器进程生命周期管理,核心操作入口 |
| Snapshots | Prepare, Commit, Mounts |
管理容器镜像层快照,提供根文件系统 |
| Images | Pull, Push, List |
镜像拉取、推送与存储管理 |
性能调优要点:在集群节点扩容时,gRPC API 的并发处理能力是关键瓶颈。建议监控
containerd grpc 指标中的请求延迟和错误率,适当调整 grpc.max_recv_msg_size 和 grpc.max_send_msg_size 参数。
2.3 Snapshotter:容器根文件系统的构建者
Snapshotter 负责管理容器镜像的层(Layer)数据,并为每个容器准备可写层(Rootfs)。Containerd 默认使用 overlayfs 快照器,它利用 Linux 内核的 OverlayFS 实现高效的层叠文件系统。
Snapshotter 的工作流程分为以下步骤:
- Prepare:根据镜像配置,准备一个挂载点,将镜像层和容器层组合成可用的根文件系统。
- Mounts:返回挂载信息(如 lowerdir、upperdir、workdir),供后续运行时使用。
- Commit:将容器运行期间产生的变更提交为新的快照层(通常用于构建新镜像)。
- Remove:容器销毁后,清理对应的快照数据。
扩容风险提示:当节点上同时启动大量容器时,Snapshotter 的
Prepare 操作会密集触发文件系统挂载。如果磁盘 I/O 能力不足,可能导致容器启动超时。建议使用高性能 SSD 并监控 containerd_snapshots 指标。
2.4 Shim 进程:容器生命周期的守护者
Shim 进程(containerd-shim)是 Containerd 架构中最具特色的组件。它作为 Containerd 主进程与容器运行时之间的中间层,承担以下职责:
- 生命周期管理:每个容器对应一个独立的 Shim 进程,负责监控容器进程状态。
- IO 重定向:将容器的标准输入/输出/错误流重定向回 Containerd 主进程。
- 退出状态上报:当容器进程退出时,Shim 捕获退出码并通知 Containerd。
- 解耦设计:即使 Containerd 主进程重启或崩溃,Shim 进程依然存活,容器不受影响。
Shim 进程的启动流程如下:
- Containerd 主进程通过 gRPC 收到
Create任务请求。 - 主进程 fork 出一个新的 Shim 进程,并传递容器配置信息。
- Shim 进程调用运行时(如 runc)创建并启动容器。
- Shim 进程持续运行,通过 Unix Domain Socket 与 Containerd 主进程通信。
- 容器退出后,Shim 进程上报退出状态,然后自行退出。
2.5 运行时(runc / runsc):容器进程的执行者
运行时是容器技术的底层执行引擎,负责真正创建和运行容器进程。Containerd 支持多种运行时,最常用的是 runc(标准 OCI 运行时)和 runsc(gVisor 沙箱运行时)。
| 特性 | runc | runsc (gVisor) |
|---|---|---|
| 隔离级别 | 内核命名空间 + cgroups | 用户态内核(Sentry) |
| 性能开销 | 接近原生(< 5%) | 较高(20% - 50%) |
| 安全特性 | 依赖内核安全机制 | 额外系统调用拦截 |
| 适用场景 | 通用生产环境 | 多租户、高安全要求 |
| OCI 兼容性 | 完全兼容 | 大部分兼容 |
2.6 完整协作流程:从请求到容器运行
以下是一个完整的容器创建请求在 Containerd 内部的流转过程:
- 客户端发起请求:kubelet 或 ctr 通过 gRPC 调用
Tasks.Create方法。 - 核心服务层处理:Containerd 主进程解析请求,验证命名空间和容器元数据。
- Snapshotter 准备根文件系统:调用
Snapshots.Prepare方法,挂载 OverlayFS 并返回挂载点路径。 - 创建 Shim 进程:主进程 fork 出
containerd-shim,传递容器 ID、挂载信息、运行时配置等。 - Shim 调用运行时:Shim 进程根据配置调用 runc(或 runsc),执行
runc create和runc start。 - 运行时创建容器:runc 利用 cgroups 和命名空间创建隔离环境,挂载根文件系统,启动容器进程。
- 状态上报:Shim 进程持续监控容器状态,通过 gRPC 流式接口向 Containerd 主进程上报。
- 返回响应:Containerd 主进程向客户端返回容器创建成功响应。
扩容场景优化建议:在节点扩容时,建议预先调整以下参数以提升容器创建速度:
-
-
- 使用
-
containerd.toml 中 [grpc] max_recv_msg_size 增大到 32MB-
[plugins."io.containerd.grpc.v1.cri"] 中 max_container_per_log_line_size 适当调大- 使用
overlayfs 快照器并确保内核支持 metacopy 特性
2.7 组件协作的故障排查要点
当容器启动失败或性能异常时,可以按照以下链路进行排查:
| 故障现象 | 可能原因 | 排查命令 / 方法 |
|---|---|---|
| gRPC 调用超时 | Containerd 主进程负载过高 | ctr events 查看事件流,containerd metrics 查看延迟 |
| Snapshotter 挂载失败 | 磁盘空间不足或 overlayfs 内核模块未加载 | df -h 检查磁盘,lsmod | grep overlay |
| Shim 进程异常退出 | 容器配置错误或运行时崩溃 | journalctl -u containerd 查看日志,crictl inspect 检查容器状态 |
| 运行时创建容器失败 | cgroups 配置冲突或内核参数限制 | runc list 查看运行时状态,dmesg 查看内核日志 |