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"

五、差异对照表

维度podsandboxshim
插件类型 / 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,接口签名相同但语义和副作用完全不同。

posted @ 2026-10-13 22:40  rincloud  阅读(3)  评论(0)    收藏  举报