3. containerd 架构与核心组件

containerd 是 Kubernetes 最主流的容器运行时,其架构设计遵循“单一职责、可插拔、轻量级”原则。从控制面故障排查视角看,理解 containerd 守护进程、shim 进程、snapshotter、metadata 存储和 gRPC API 这五大核心组件,是定位容器启动失败、镜像拉取超时、节点 NotReady 等问题的前提。

故障排查前置认知: containerd 本身不直接管理网络、存储卷或容器日志——这些能力由 kubelet 通过 CRI 调用 containerd,再由 containerd 委托给 shim 和 snapshotter 完成。因此,控制面故障往往表现为 kubelet 与 containerd 之间的 gRPC 通信中断、shim 进程异常退出、或 snapshotter 挂载失败。

3.1 整体架构总览

下图展示了 containerd 的核心组件及其交互关系。控制面故障排查时,重点关注 gRPC API 层(kubelet 调用入口)、shim 进程(容器生命周期隔离单元)和 snapshotter(镜像层挂载引擎)。

containerd 核心架构组件关系图 containerd 核心架构组件关系图 kubelet (CRI 客户端) gRPC API (CRI / Namespace) containerd 守护进程 (containerd) 任务管理 · 镜像管理 · 元数据协调 shim 进程 容器生命周期隔离 snapshotter 镜像层挂载 / 快照 metadata 存储 BoltDB / 内存索引 故障排查关键路径 gRPC 超时 → 检查 containerd 守护进程健康;shim 丢失 → 检查容器残留;snapshotter 挂载失败 → 检查磁盘和 overlay 配置

3.2 containerd 守护进程(containerd)

containerd 守护进程是系统的核心协调者,以 systemd 服务形式运行(systemctl status containerd)。它负责:

  • gRPC 服务注册:监听 /run/containerd/containerd.sock(默认),暴露 CRI、Namespace、Tasks、Images 等服务。
  • 任务调度:将容器创建请求转发给 shim 进程,并跟踪容器状态。
  • 镜像管理:拉取、解压、索引镜像层,委托 snapshotter 完成层挂载。
  • 元数据协调:读写 metadata 存储,维护容器、镜像、快照的关联关系。
containerd 守护进程关键配置与故障排查点
配置项 默认值 故障排查关注点
root /var/lib/containerd 磁盘空间不足 → 镜像拉取/容器启动失败
state /run/containerd socket 文件丢失 → kubelet 无法连接
grpc.address /run/containerd/containerd.sock 权限错误 → kubelet 报 permission denied
oom_score -999 OOM 导致守护进程被杀 → 节点 NotReady
排查技巧: 使用 ctr version 和 ctr plugins list 快速验证 containerd 守护进程是否存活、插件是否正常加载。若 ctr 命令无响应,大概率是守护进程 hang 或 socket 文件损坏。

3.3 shim 进程

shim 进程是 containerd 架构中“容器运行时隔离”的关键设计。每个容器(或 Pod sandbox)对应一个独立的 shim 进程,其核心职责包括:

  • 生命周期代理:containerd 守护进程通过 shim 间接管理容器,即使 containerd 重启,shim 进程仍保持容器运行。
  • 标准 I/O 转发:将容器 stdout/stderr 通过 FIFO 或管道转发给 containerd。
  • 退出状态收集:容器退出后,shim 负责收集退出码并通知 containerd。
  • 运行时适配:不同的 shim 实现(如 containerd-shim-runc-v2)对接不同的底层运行时(runc、kata、gvisor)。

控制面故障中,shim 进程异常是最常见的“容器卡在 Terminating”或“Sandbox 状态不一致”的根因。

常见 shim 故障模式与诊断方法
故障现象 可能原因 诊断命令
容器状态为 Unknown shim 进程崩溃或 OOM ps aux | grep containerd-shim
Pod 一直 Terminating shim 未响应 SIGTERM ctr tasks kill <task-id>
kubelet 报 "failed to get sandbox status" shim socket 文件丢失 ls /run/containerd/io.containerd.runtime.v2.task/
容器启动超时 shim 创建失败(资源不足) journalctl -u containerd --no-pager | grep shim
关键注意: 不要直接 kill shim 进程来“清理”容器——这会导致 containerd 丢失容器状态,残留的容器进程变成孤儿。正确做法是通过 ctr tasks rm --force 或重启 containerd 服务来触发 shim 清理。

3.4 snapshotter

snapshotter 是 containerd 的“镜像层挂载引擎”,负责将镜像的每一层(layer)挂载为容器的根文件系统。默认使用 overlayfs snapshotter,其他选项包括 native、devmapper、nydus(加速镜像)。

从控制面故障排查角度看,snapshotter 问题通常表现为:

  • 镜像拉取成功但容器启动失败:snapshotter 挂载时报错,如 mount: no such device(overlay 内核模块未加载)。
  • 磁盘空间泄漏:未正确清理的 snapshots 占用大量磁盘,导致节点磁盘压力。
  • 快照层损坏:异常断电或并发写入导致 metadata 不一致。
snapshotter 镜像层挂载流程 snapshotter 镜像层挂载流程 镜像层 L1 镜像层 L2 镜像层 L3 snapshotter overlay 挂载 写时复制 快照链管理 垃圾回收 容器根文件系统 merged (lower+upper) 故障排查:mount: no such device → 检查 lsmod | grep overlay;磁盘泄漏 → ctr snapshots list 查看未释放快照
排查命令速查:
ctr snapshots list — 列出所有快照
ctr snapshots info <snapshot-id> — 查看快照详情
mount | grep overlay — 检查 overlay 挂载是否正常
df -h /var/lib/containerd — 检查 snapshotter 数据目录磁盘使用率

3.5 metadata 存储

containerd 使用 BoltDB(嵌入式键值数据库)作为 metadata 存储,文件位于 /var/lib/containerd/containerd.db。它维护以下核心元数据:

  • 容器元数据:ID、状态、标签、创建时间、shim 进程 PID。
  • 镜像元数据:镜像名称、摘要、层索引、大小。
  • 快照元数据:快照链关系、父快照引用、挂载点。
  • 命名空间:Kubernetes 使用 k8s.io 命名空间隔离 Pod 容器。

metadata 存储损坏是控制面故障中的“隐形杀手”——containerd 守护进程可能仍在运行,但所有容器操作都返回错误。

metadata 存储故障模式与恢复策略
故障表现 日志特征 恢复操作
containerd 启动失败 bolt: database is locked 检查是否有残留 containerd 进程;删除 containerd.db 锁文件
容器列表为空但实际有容器运行 metadata: bucket not found 使用 containerd.db 备份恢复;或重建数据库(会丢失状态)
镜像拉取后无法引用 metadata: key already exists 清理镜像缓存:ctr images rm 后重新拉取
快照链断裂 snapshot: parent snapshot not found 删除容器后清理快照:ctr snapshots rm
重要: 不要在生产节点上直接删除 containerd.db 文件——这会丢失所有容器和镜像元数据,导致 kubelet 无法管理已有 Pod。优先尝试从备份恢复,或使用 containerd --config 指定只读模式导出数据。

3.6 gRPC API

containerd 通过 gRPC API 对外提供服务,kubelet 通过 CRI(Container Runtime Interface)调用这些 API。gRPC API 是控制面故障排查的“第一入口”——通信中断会直接导致节点 NotReady。

核心 gRPC 服务包括:

  • RuntimeService(CRI):RunPodSandbox、CreateContainer、StartContainer、Status。
  • ImageService(CRI):PullImage、ListImages、ImageStatus。
  • TasksService(containerd 原生):Create、Start、Kill、Delete。
  • SnapshotsService(containerd 原生):Prepare、Mount、Remove。

gRPC 故障通常表现为 kubelet 日志中的 rpc error: code = Unavailable 或 code = DeadlineExceeded。

调试工具:
crictl info — 验证 containerd CRI 是否响应
crictl ps -a — 列出所有容器(包括已退出)
grpcurl -plaintext -unix /run/containerd/containerd.sock list — 枚举所有 gRPC 服务
journalctl -u kubelet --no-pager | grep "rpc error" — 快速定位 gRPC 通信错误

3.7 组件协作故障排查路径

当控制面出现容器运行时相关故障时,建议按以下路径逐层排查:

  1. 检查 containerd 守护进程:systemctl status containerd、ctr version。
  2. 检查 gRPC 通信:crictl info、ls -l /run/containerd/containerd.sock。
  3. 检查 shim 进程:ps aux | grep shim、ctr tasks list。
  4. 检查 snapshotter:mount | grep overlay、ctr snapshots list。
  5. 检查 metadata 存储:ls -lh /var/lib/containerd/containerd.db、dmesg | grep containerd。
一句话总结: containerd 的五大组件——守护进程(协调者)、shim(隔离单元)、snapshotter(挂载引擎)、metadata 存储(状态持久化)、gRPC API(通信入口)——构成了容器运行时的完整生命周期管理链路。控制面故障排查时,沿着这条链路逐层检查,能快速定位根因。