containerd 与 shim

定义

containerd 是一个守护进程:它管理镜像、容器元数据,并实现 CRI,因而可以直接被 kubelet 使用。containerd 在守护进程内部完成全部隔离与进程启动;它通过 runtime-v2 shim 把一次容器(或一类 RuntimeClass)交给底层运行时。

shim 是一个小进程。它的职责是:与 containerd 保持约定好的 API,转译 start / kill / wait / delete,并盯住底层进程或虚拟机的真实状态。守护进程重启时,shim 仍可继续持有那次执行,从而避免把容器状态完全绑在守护进程的内存里。

问题背景

若 containerd 直接 clone 出所有容器进程,则守护进程崩溃会牵连全部容器,也难以为不同工作负载换不同的底层运行时。引入 shim 之后,containerd 成为「镜像与元数据的管理者」,具体执行可以是 runc、gVisor,或 A3S Box / A3S OCI Runtime。

机制说明

两条进入 Box 的路径

要把 Kubernetes 工作负载落到 Box,存在两条工程路径。

路径 调用链 Box 中的代码
直接 CRI kubelet → Box CRI 服务器 → LocalExecutionManager src/cri/
containerd shim kubelet → containerd → runtime-v2 shim → Box containerd-shim/

第一条路径让 kubelet 把 Box 当成运行时。第二条路径让已有 containerd 节点通过 RuntimeClass 选择 Box,而不替换整套 CRI。二者都是适配层;产品状态与隔离实现仍在 src/runtime/

OCI Runtime 自己的 shim

A3S OCI Runtime 仓库也包含 crates/containerd-shim。那是 Runtime 作为底层执行器时的入口,与 Box 仓库根目录的 containerd-shim/ 不是同一二进制。阅读代码时先确认仓库:Box 的 shim 面向产品生命周期;Runtime 的 shim 面向 bundle 执行。

与 a3s-box-shim 的名称碰撞

src/shim/ 中的 a3s-box-shim 是 MicroVM 的 libkrun 子进程,不是 containerd runtime-v2 shim。libkrun 的 krun_start_enter() 会接管当前进程,因此必须单独启动一个进程当 VMM,以免 CLI 或 SDK 进程被接管。名称都叫 shim,职责完全不同。详见 一条 run 命令的调用链

在 Box 中的位置

  • containerd 集成:仓库根 containerd-shim/
  • 部署样例:deploy/shim/deploy/helm/
  • MicroVM 进程隔离 shim:src/shim/src/main.rs
  • 平台状态仍标注为预览,不声明完整 CRI 符合性。

验证命令

在已配置 RuntimeClass 的集群中,创建使用该 RuntimeClass 的 Pod,然后在节点上检查是否出现对应的 shim 进程与 box 记录。没有集群时,比较 containerd-shim/srcsrc/shim/src 的 crate 说明即可区分两条「shim」路径。

相关与易混

  • 相关:CRIKubernetesOCI 标准与 bundle
  • 易混:containerd 不是 Docker Desktop,也不是 Kubernetes 控制面。Docker 引擎在较新版本中可以在下方使用 containerd。看到「shim」时,先判断它属于 containerd、OCI Runtime,还是 Box 的 libkrun 子进程。