sandboxer = 'podsandbox' 和sandboxer = 'shim' 两种情况这个create 有区别么? 给出调用链
sandboxer = 'podsandbox' 和sandboxer = 'shim' 两种情况这个create 有区别么? 给出调用链
我已经完整梳理了两条路径。以下是分析结果。
结论(先说重点)
是的,有本质区别。 虽然两者的签名完全相同(都是 sandbox.Controller.Create),但:
sandboxer = "podsandbox"的Create只做元数据登记(保存到内存 store),不创建任何容器/进程;真正的"pause 容器"是在随后的Start里才创建的。sandboxer = "shim"的Create是"重"操作:它会创建 bundle、启动一个新的 shim 进程,并通过 TTRPC 调用 shim 实现的CreateSandbox真正把沙箱建起来。
Sandboxer 字段本质上就是 controller 在插件 map 里的 key,用来选实现。
一、两个 Controller 实现分别在哪里
Controller 这个接口在同一个进程内有 两个插件实现,注册为两种不同的 plugin type:
| sandboxer 名字 | 插件类型() | 实现 | 文件 |
|---|---|---|---|
podsandbox |
PodSandboxPlugin = "io.containerd.podsandbox.controller.v1",ID:"podsandbox" |
podsandbox.Controller |
internal/cri/server/podsandbox/controller.go:45 |
shim |
SandboxControllerPlugin = "io.containerd.sandbox.controller.v1",ID:"shim" |
controllerLocal |
plugins/sandbox/controller.go:45 |
二、CRI 的调用链(RunPodSandbox)
criService.RunPodSandbox internal/cri/server/sandbox_run.go:60
├─ ociRuntime := c.config.GetSandboxRuntime(...) // runtime 配置里的 sandboxer,默认 "podsandbox"
├─ sandboxInfo.Sandboxer = ociRuntime.Sandboxer :129
├─ sandbox.Sandboxer = ociRuntime.Sandboxer :161
├─ c.client.SandboxStore().Create(ctx, sandboxInfo) :167 // 存沙箱元数据到 metadata store
│ ... (CNI setup / 写回 extension) ...
└─ c.sandboxService.CreateSandbox(ctx, sandboxInfo, :287
sb.WithOptions(config), sb.WithNetNSPath(...))
criSandboxService.CreateSandbox internal/cri/server/sandbox_service.go:51
├─ c.SandboxController(info.Sandboxer) // 按 Sandboxer 名去 map 里取
└─ ctrl.Create(ctx, info, opts...) // 落到具体实现
这个 map 从哪来:
plugins/cri/cri.go: getSandboxControllers() :257
├─ ic.GetByType(plugins.SandboxControllerPlugin) → sc["shim"] = controllerLocal
└─ ic.GetByType(plugins.PodSandboxPlugin) → sc["podsandbox"] = podsandbox.Controller
↓
options.SandboxControllers → service.go:229 → newCriSandboxService(...)
所以 info.Sandboxer 的值("podsandbox" / "shim")直接决定走哪个 Create。
三、两条分支的具体行为
分支 A:sandboxer = "podsandbox"
podsandbox.Controller.Create internal/cri/server/podsandbox/sandbox_run.go:335
├─ info.GetExtension(MetadataKey, &metadata) // 从扩展里取出 CRI 的 sandbox.Metadata
├─ podSandbox := types.NewPodSandbox(..., StateUnknown)
├─ podSandbox.Metadata = metadata / Runtime = info.Runtime
└─ c.store.Save(podSandbox) // 只写进内存 store
- 不做镜像拉取、不建容器、不建 task、不起进程。纯内存登记,供后面
Start使用。 - 真正的沙箱实体(pause 容器)在
podsandbox.Controller.Start(同文件:62)里完成:取 pause 镜像 → 生成 OCI spec →c.client.NewContainer→container.NewTask→ NRI →task.Start→ 后台waitSandboxExit。
分支 B:sandboxer = "shim"
controllerLocal.Create plugins/sandbox/controller.go:123
├─ 解析 CreateOpt (Rootfs/Options/NetNSPath/Annotations)
├─ c.shims.Get(sandboxID) // 已存在则 ErrAlreadyExists
├─ v2.NewBundle(root, state, sandboxID, info.Spec) :134 // 建 bundle 目录
├─ c.shims.Start(ctx, sandboxID, bundle, CreateOpts{ :144 // ★ 启动 shim 进程
│ Spec, RuntimeOptions, Runtime})
├─ svc := sandbox.NewClient(shim.Client()) :154 // 连 shim 的 TTRPC
└─ svc.CreateSandbox(ctx, &CreateSandboxRequest{ :159 // ★ 让 shim 真正建沙箱
SandboxID, BundlePath, Rootfs, Options, NetnsPath, Annotations})
出错则 c.cleanupShim(...) :167
Create阶段就 eager 地 起 shim、建 bundle、调 shim 的CreateSandbox。- 后续
controllerLocal.Start(:174)只是再调一次 shim 的StartSandbox。 - 沙箱怎么建完全由 shim(实现
runtime/sandbox/v1的 SandboxService)自己决定。
四、另一条入口(外部 containerd client,非 CRI)
CRI 走的是"进程内本地 map"。如果是外部 client 或 proxy plugins,调用链不同但最终落到同一个 Controller:
client.NewSandbox client/sandbox.go:128
├─ c.defaultSandboxer(ctx) // 默认 defaults.DefaultSandboxer = "shim"
├─ SandboxStore().Create(...)
└─ c.SandboxController(sandboxer).Create(ctx, newSandbox) :156
↓
remoteSandboxController.Create core/sandbox/proxy/controller.go:47
└─ gRPC api.ControllerClient.Create(ControllerCreateRequest{Sandboxer: name, ...})
↓
controllerService.Create plugins/services/sandbox/controller_service.go:113
├─ s.getController(req.Sandboxer) :103 // 按名字取(map 由 PodSandboxPlugin + SandboxControllerPlugin 合并)
├─ ctrl.Create(ctx, sb, WithOptions/WithNetNSPath/WithRootFS/WithAnnotations)
└─ publish "/sandboxes/create"
五、差异对照表
| 维度 | podsandbox | shim |
|---|---|---|
| 插件类型 / ID | PodSandboxPlugin / "podsandbox" |
SandboxControllerPlugin / "shim" |
Create 实现位置 |
internal/cri/server/podsandbox/sandbox_run.go:335 |
plugins/sandbox/controller.go:123 |
Create 干什么 |
读 Metadata 扩展 → 建内存 PodSandbox → store.Save |
建 bundle → 启动 shim 进程 → TTRPC CreateSandbox |
| 是否起进程 | 否(惰性) | 是(立即起 shim) |
| 谁建真正的沙箱 | Start 里创建 pause 容器 + task |
shim 在 CreateSandbox 里自建 |
Start 阶段 |
重(拉 pause 镜像、建容器/task/启动) | 轻(StartSandbox) |
| 依赖 | CRI in-memory store + event monitor | ShimManager + bundle + shim 的 SandboxService |
一句话总结:podsandbox 的 Create 是"登记",shim 的 Create 是"启动"。二者名字 Sandboxer 只是从 sandboxControllers map 里选实现的 key,接口签名相同但语义和副作用完全不同。

浙公网安备 33010602011771号