从 kubelet 到沙盒:高级运行时与低级运行时的映射全景
一句话结论:kubelet 不直接创建容器,它只通过 CRI(Container Runtime Interface)下达指令;真正干活的是高级运行时(containerd / CRI-O)和低级运行时(runc / kata-agent / runsc)。沙盒选型的本质,就是在决定「谁来接 kubelet 的 CRI 调用」以及「容器进程最终跑在什么隔离边界里」。对具身智能公司而言,仿真训练、Agent 工具调用、强隔离 VM、真机设备接入这四类负载对应完全不同的运行时组合——不存在一个「万能沙盒」能同时满足。
这篇是 具身智能仿真场景的沙盒选型 的下层视角。上篇回答「该选哪个沙盒」,这篇回答「沙盒插在运行时栈的哪一层、跟 kubelet 怎么耦合」。
本文的架构描述逐条核对自 Kubernetes 官方文档、containerd 源码与文档、Kata/gVisor/Firecracker 官方文档与仓库。核对中发现原稿有十余处需要更正,已在文中以 ⚠️ 标注。
一、先立骨架:kubelet 之下的运行时栈分层
Kubernetes 的容器运行时体系是明确的两层结构,这个分层决定了后面所有场景的讨论框架:
- 高级运行时:对接 kubelet 的 CRI gRPC 接口,负责镜像管理、容器生命周期编排、存储快照、网络(CNI 调用)。代表是 containerd(内部的
cri插件)和 CRI-O。 - 低级运行时:高级运行时通过 OCI Runtime Spec 调用它,负责真正创建/销毁容器进程。传统上是 runc(namespace + cgroups + seccomp),沙盒场景下则可能是 Kata(VM 内的 kata-agent)、gVisor 的 runsc、或 Firecracker 的 guest agent。
说明:K8s 官方文档本身不使用「高级/低级运行时」这两个词,该分层是 CNCF 生态的通行表述——「Low-level Container Runtime: OCI-compliant implementations that can receive a runnable filesystem (rootfs) and a configuration file (config.json) to execute isolated processes… such as runc, crun, youki, gvisor, and kata. High-level Container Runtime: responsible for the transport and management of container images, unpacking the image, and passing it off to the low-level runtime…」
kubelet 与 containerd 的协作流程(对照 containerd 官方 CRI 架构文档):
- kubelet 通过 CRI
RuntimeService调 containerd 的cri插件创建 Pod sandbox; cri插件创建网络命名空间并调 CNI 配置网络;cri插件创建并启动 pause 容器(sandbox 容器);- kubelet 通过 CRI
ImageService拉取业务镜像; - kubelet 再调
cri在 Pod 内创建并启动业务容器。
⚠️ 两处需要精确化:
- CNI 不是 kubelet 调的,是 CRI 实现(containerd 的 cri 插件)调的。 K8s 的 CRI 网络规范原文:「Kubelet expects the runtime shim to manage pod’s network life cycle…
RunPodSandboxmust set up pod’s network.」- pause 容器属于 sandbox 创建阶段,不是之后单独的一步。 默认实现里 sandbox 就是 pause 容器,它在
RunPodSandbox内完成。
containerd 与低级运行时之间是 shim v2 协议:containerd 不直接 fork/exec 运行时引擎,而是通过长驻 shim 进程的 ttRPC socket 下发指令。
flowchart TD
subgraph Node["Kubernetes Node"]
K[kubelet] -->|"CRI gRPC<br/>RuntimeService / ImageService"| C[containerd<br/>cri 插件]
C -->|"CNI"| N[CNI 插件<br/>Calico/Cilium]
C -->|"shim v2 / ttRPC"| S[containerd-shim-runc-v2]
S -->|"exec"| R[runc<br/>低级运行时]
R --> P[容器进程<br/>namespace+cgroups+seccomp]
C -.->|镜像快照| SNAP[snapshotter<br/>overlayfs/nydus]
K -.->|Device API| DP[Device Plugin / DRA driver]
end⚠️ 更正(这条原稿的对比不准确):原稿写「containerd 为每个 pod sandbox 启动一个 shim 进程,通过 socket 长连接,而不是每次操作 fork 一个 runtime 二进制」。
两个问题:
- 「每个 pod sandbox 一个 shim」是
io.containerd.runc.v2这个 shim 实现的选择,不是 containerd 的强制语义。 containerd 官方原文:「containerd does not know or care about whether the shim to container relationship is one-to-one, or one-to-many. It is entirely up to the shim to decide.」而通用 Runtime v2 模型的表述是「containerd launches a shim process for each container」。是runc.v2shim 主动按io.kubernetes.cri.sandbox-id标签聚合,才让同一个 Pod 的所有容器共用一个 shim。- 「不再 fork runtime 二进制」不成立——长驻 shim 本身在每次 create/start/stop 时仍会 exec
runc。准确的表述是「containerd 不直接调用运行时引擎,而是通过长驻 shim 的 ttRPC socket 下发指令」。
这个分层的关键含义是:沙盒技术插在哪一层,决定了它跟 kubelet 的耦合方式。gVisor 和 Kata 插在 shim 层(containerd 换个 runtime handler 就能切换);Firecracker 可以走 firecracker-containerd 的 control plugin 路径,也可以走独立 shim 路径;而 AgentENV / CubeSandbox 这类自带控制平面的系统干脆绕过 kubelet,自建调度。
二、场景一:裸金属容器仿真训练
适用场景:Isaac Lab / MuJoCo Warp / Genesis 大规模 RL rollout,GPU 密集,容器内直接跑 CUDA / PhysX / RT Core 负载,不需要 VM 级隔离。
- 高级运行时:containerd(标准配置),配 nydus-snapshotter 做镜像按需加载;
- 低级运行时:runc(
io.containerd.runc.v2shim)。
GPU 不走虚拟化,通过 DRA driver 或 NVIDIA Device Plugin 注册到 kubelet 的设备管理器。DRA(K8s 1.34 GA,feature gate 在 1.35 起 locked)比旧 Device Plugin 多了拓扑感知:
flowchart TD
subgraph Node["GPU 裸金属节点"]
K[kubelet] -->|"CRI"| C[containerd cri]
K -->|"Topology Manager"| TM[NUMA 对齐]
TM --> DM[Device Manager]
DM -->|"gRPC 注册"| DRA[DRA driver<br/>kubelet plugin]
DRA --> CDI[CDI device ID]
CDI --> C
C --> S[shim-runc-v2] --> R[runc]
R --> P[仿真容器<br/>Isaac Lab / MuJoCo]
P -.->|CUDA 直访| GPU[物理 GPU]
C -.->|snapshotter| NYD[nydus-snapshotter<br/>EROFS 按需加载]
K -.->|HAMi 替换| HAMI[HAMi device plugin<br/>vGPU 时间片]
endDRA 的完整链路:scheduler 的 DynamicResources 插件把 Pod 匹配到 ResourceSlice 描述的硬件上并写回 ResourceClaim → kubelet 通过 gRPC 调 driver 的 NodePrepareResources → driver 返回 CDI device ID → containerd 消费。
⚠️ 更正一处措辞:原稿写「
NodePrepareResources生成 CDI spec」。实际上 driver 返回的是 CDI device ID(NodePrepareResourcesResponse里的repeated string cdi_device_ids);CDI spec 文件是厂商 driver 的 spec 生成器写进/etc/cdi或/var/run/cdi的,containerd 读取并注入。两者不是一回事。
CDI(Container Device Interface) 的全称与归属核实无误,仓库在 CNCF 的 cncf-tags 组织下。但有一个版本差异要知道:
⚠️ containerd 1.7 默认
enable_cdi = false(需手动开),2.0 起 CDI 默认启用——所以 2.0 的 config 参考里已经不再出现这个开关。跨版本排查设备注入问题时会踩到。
几个关键细节:
- HAMi 提利用率的路径是替换节点上的 NVIDIA device plugin(它本身就是 k8s-device-plugin 的 fork)。官方前置条件文档要求:把 GPU Operator 的
devicePlugin.enabled=false、关掉节点上其他 NVIDIA device plugin,避免nvidia.com/gpu被重复注册。切分粒度是nvidia.com/gpumem(MiB)和nvidia.com/gpucores(百分比),由libvgpu.so在 CUDA API 层做容器内软隔离。但时间片无故障隔离,一个 rollout OOM 可能波及共享同卡的其他副本。 - nydus-snapshotter 是 containerd 的外部插件进程(
containerd-nydus-grpc),以[proxy_plugins]的type = "snapshot"身份接入,实现的是 remote snapshotter 接口。它的完整机制见 containerd Snapshotter 接口深度解析。 - 断点续跑靠仿真器自身的
save_state(Isaac Lab、MuJoCo、Genesis 都支持),不靠虚拟化层快照——GPU 状态无法被 hypervisor 快照,这是仿真沙盒与通用沙盒最本质的差别。
三、场景二:Agent 工具调用沙盒
适用场景:具身 Agent 训练中的工具调用(代码执行、文件操作、API 调用),CPU 密集、生命周期短(秒到分钟)、高并发 fanout、不需要 GPU。
- 高级运行时:containerd,配
firecracker或gvisorruntime handler,由 Kubernetes SIG 的 agent-sandbox(Sandbox CRD + controller + webhook)统一管理生命周期与策略; - 低级运行时:按隔离强度分三档。
(1)gVisor runsc(containerd-shim-runsc-v1):Sentry 作为用户态内核拦截系统调用,Gofer 代理文件系统访问。开销在 syscall 密集型负载明显——官方原文:「This cost will principally impact applications that are system call bound」,纯 CPU 负载几乎无开销。部署最简单。
⚠️ 更正:原稿写「Sentry 与 Gofer 之间用 9P 协议」。现行协议是 LISAFS,9P 是历史实现。gVisor 官方文档:「Gofer instances communicate with their respective sentry using the LISAFS protocol.」仓库
pkg/lisafs/README.md解释了换的原因:「Historically, gVisor used a custom extension of the 9P2000.L protocol… 9P proved to be chatty in certain situations, inducing a lot of RPCs. LISAFS aims to be more economical.」(主仓库已无pkg/9p目录。)
(2)独立 firecracker-shim(社区实现 PipeOpsHQ/firecracker-shim):无中间 daemon,containerd 直接调 shim,shim 启动 Firecracker VMM,VM 内 fc-agent 再调 runc 跑容器。标准 CNI 可用,VM 池化预热后冷启动 <50ms,单 VM 内存开销 64—128MB。
这一条的组件名(
fc-agent+ 调 runc)核实属实——README 架构图是fc-agent → runc → container,源码cmd/fc-agent/main.go注释 “manages containers using runc”,常量runcBinary="/usr/bin/runc"。⚠️ 但项目本身要打个折扣:该仓库 2026-01 创建、约 8 star,很新很小,可以叫「社区实现」,不宜当成熟方案推荐。而且它自己文档里内存开销有 64—128MB 与 ~10MB 两个口径并存(前者是整机 VM 占用、后者是相对 runc 的增量),引用时要注明。
(3)firecracker-containerd(AWS 官方):shim + 编译进 containerd 的 control plugin。
⚠️ 更正:原稿写它是「daemon 架构,容器管理通过单独的 gRPC 接口而非标准 OCI shim」。实际是:
- 它是「A control plugin compiled in to the containerd binary」(需要专门构建的 containerd 二进制)+ 「A runtime implementing both the control API and the V2 runtime API, implemented as an out-of-process shim communicating over ttrpc」;
- 容器/任务生命周期走的正是标准 V2 runtime(shim)模型;那个 control plugin(
FC-Control)只管 VM 级 API(StartVM等),不接管容器管理;- 通信是 ttrpc 不是 gRPC。
维护状态也要说准:未归档、未标记废弃(GitHub API
archived: false,2026-10 仍有提交),近一年以依赖升级为主、无重大功能开发——是「明显放缓」,不是「停止维护」。
flowchart TD
subgraph Cluster["Agent 工具调用集群"]
AS[agent-sandbox controller<br/>Sandbox CRD / webhook] --> K
subgraph Node["K8s 节点"]
K[kubelet] -->|"CRI<br/>RuntimeClass=firecracker"| C[containerd]
C -->|"shim v2 / ttRPC"| FCS[containerd-shim-fc-v2]
FCS --> FC[Firecracker VMM]
FC -->|"virtio-vsock"| AG[fc-agent]
AG -->|"guest 内 exec"| R2[runc]
R2 --> P[工具容器<br/>python/shell]
K -.->|RuntimeClass=gvisor| GV[containerd-shim-runsc-v1]
GV --> SEN[Sentry 用户态内核]
SEN -->|"LISAFS"| GOF[Gofer]
C -->|"标准 CNI"| NET[Calico/Cilium<br/>egress NetworkPolicy]
end
end
AS -.->|策略注入| NET这个场景最容易混淆的一点:AgentENV 和 CubeSandbox 不在这个拓扑里。它们自带控制平面——CubeSandbox 的 CubeMaster 做集群调度、Cubelet 管节点上沙盒实例的生命周期、CubeShim 实现 containerd shim v2 接口做 VM 启动与 vsock 通信——K8s 只承载外层 Pod,内层 microVM 的调度不走 kubelet 的 CRI。
⚠️ 更正一处技术基座:原稿写「CubeHypervisor 基于 Cloud Hypervisor」。官方原文是「CubeHypervisor… The lightweight VMM built on RustVMM + KVM」。Cloud Hypervisor 只出现在致谢里(“Special thanks to Cloud Hypervisor, Kata Containers, virtiofsd…”)——是灵感血缘,不是直接基座。
kubelet 对内层 microVM 是不感知的——它只看到外层 Pod 的 requests/limits,内层 VM 的内存、VMM 开销、文件缓存、快照写入都不在 K8s 计量里,容量规划需要单独评估。
四、场景三:Kata VM 强隔离(含 GPU 直通)
适用场景:多租户不可信负载、需要 VM 级内核隔离、或需要 VFIO 设备直通(整卡 GPU、RDMA NIC)的场景。
- 高级运行时:containerd(或 CRI-O),配
kataruntime handler; - 低级运行时:kata-runtime(shim v2 形态的
containerd-shim-kata-v2),其下可选 QEMU / Cloud Hypervisor / Firecracker / Dragonball 作为 VMM 后端。
Kata 2.x 相对 1.x 的架构变化是本质性的:不再有独立的 kata-proxy 和 kata-shim 进程,而是每个 pod sandbox(VM)一个 containerd-shim-kata-v2 进程。官方 history 文档的对比表:
| 1.x | 2.x | |
|---|---|---|
| shim 进程 | multiple per container | 1 per VM(hosting any number of containers) |
| proxy 进程 | 1 per container connection | 0 |
| 独立 kata-shim | 1 | 0 |
这个 per-sandbox/VM 粒度意味着:一个 Pod 里的所有容器共享同一个 microVM 和同一个内核。
补两个精度:shim 实现的是 containerd shimv2 API(与 OCI runtime CLI「similar… in terms of the way the container lifecycle is split into different verbs」,但不完全等同 OCI runtime spec);与 guest 内 kata-agent 的通信是 ttRPC over VSOCK,I/O 流也走这条协议。
存储走 virtio-fs,是 virtio-9p 的替代——官方原文:「As of the 2.0 release of Kata Containers, virtio-fs is the default filesystem sharing mechanism… provides significant performance and POSIX compliance improvements over 9pfs.」virtiofsd 守护进程在 host 侧运行,每个 VM 一个。(runtime-rs 里 9pfs 已被移除。)
flowchart TD
subgraph Node["Kata 节点"]
K[kubelet] -->|"CRI<br/>RuntimeClass=kata"| C[containerd]
C -->|"shim v2"| KS[containerd-shim-kata-v2<br/>per sandbox/VM]
KS --> QEMU[VMM<br/>QEMU / CLH / Firecracker / Dragonball]
QEMU --> VM[MicroVM<br/>独立内核]
VM -->|"ttRPC over vsock"| AGENT[kata-agent]
AGENT --> R[runc in guest]
R --> P[业务容器]
C -.->|"virtio-fs"| VFS[virtiofsd host 侧]
VFS -.-> VM
KS -.->|"VFIO 直通"| GPU[整卡 GPU<br/>PCIe passthrough]
QEMU -.-> GPU
end关键细节:
- Kata 与 GPU 的关系是「两件可分离的事」:默认 QEMU + KVM 全 virtio 设备模型不带 GPU;开启 VFIO 直通后每 VM 独占一张物理卡,密度降到一卡一 guest,但拿到接近裸金属的性能。
- Kata 硬性要求 KVM,不支持纯软件翻译(TCG)——官方:「All supported hypervisors use KVM as the underlying hardware virtualization interface on Linux」;「Kata Containers requires nested virtualization or bare metal」。云 VM 上嵌套虚拟化不可用时,AgentENV 提供 PVM(shadow paging)模式作为替代(标记为 EXPERIMENTAL,需自装 PVM 内核),但那已经离开 Kata 路径。
- 选 VMM 后端的权衡:
⚠️ 更正:原稿写「CLH 是当前推荐默认」。官方默认/推荐是 Dragonball——
virtualization.md原文:「For Most Users: Use the default Dragonball VMM with the Kata Containers Rust runtime.」配置表里标configuration-dragonball.toml (default)。Dragonball 是「a special hypervisor created by the Ant Group that runs in the same process as the Rust-based containerd shim」——零 IPC 开销是它的卖点。
| 后端 | 定位 |
|---|---|
| Dragonball | 官方默认,Kata 内置 Rust VMM,与 shim 同进程 |
| QEMU | 功能最全(VFIO、热插拔、多架构);官方称它是 NVIDIA GPU 支持最好的后端 |
| Cloud Hypervisor | 性能与兼容性平衡 |
| Firecracker | 最轻,但设备模型极简 |
用 Kata 跑 Firecracker 后端是官方支持的,但有明确限制:无 virtio-fs、无设备热插拔、无 VFIO/直通、无 CPU/内存热插拔、CRI API 支持有限。所以「用 Kata 跑 Firecracker」得到的是 K8s 原生集成,失去的正是 Firecracker 设备极简性带来的那部分优势;反之直接用独立 firecracker-shim 得到轻量但失去 Kata 的多 hypervisor 抽象——这是两条不同的集成路径,不是谁替代谁。
⚠️ 更正一处硬件支持表述:原稿写「Kata 官方硬件支持列表明确包含 Nvidia GPU、FPGA、RDMA、SR-IOV」。核实结果:GPU / SR-IOV / RDMA 有据(设计需求文档:「The Kata Containers runtime MUST provide containers with secure pass through for generic devices such as GPUs, SRIOV, RDMA, QAT」),但 FPGA 无据——全仓库检索只在某内核配置文件里出现过一次
# CONFIG_FPGA is not set,没有任何官方文档把它列为支持。而且官方并没有一份统一的「硬件支持列表」文档,出处是设计需求文档。
Kata、gVisor、runc 可以在同一集群以不同 RuntimeClass 共存(官方专门有 “Mixing VM based and namespace based runtimes” 一节),Pod spec 里 runtimeClassName 一个字段切换。RuntimeClass 机制 1.20 GA。
五、场景四:真机设备接入
适用场景:机械臂、遥操作设备、摄像头等真机硬件的调度与数据回流,以及数据工厂流水线的高吞吐网络。
- 高级运行时:containerd 标准配置;
- 低级运行时:runc(不需要沙盒增强,但要配合设备注入)。
真机接入不走 RuntimeClass,走 kubelet 的设备与网络扩展点:
- 设备层:自定义 Device Plugin(或 DRA driver)把机械臂/CAN 总线/摄像头注册为 Extended Resource 或 ResourceClaim。旧 Device Plugin 只能静态整数分配;DRA 支持按属性匹配、拓扑对齐、与其他 DRA 资源(GPU、高速 NIC)联合调度。
dra-driver-cpu这类项目甚至用 DRA 替代 kubelet 内置的 CPUManager——官方明确「The kubelet’s CPUManager and this DRA driver are mutually incompatible, and only one can be enabled at a time on any given node」。 - 网络层:
sriov-network-device-plugin发现并注册 SR-IOV VF / PF / auxiliary(SF) 三类设备;Multus 作为 meta-plugin 给 Pod 挂多个网络接口。
flowchart TD
subgraph Node["真机接入节点"]
K[kubelet] -->|"CRI"| C[containerd] --> S[shim-runc-v2] --> R[runc]
R --> P[仿真回放/数据流水线容器]
K -->|"Device Manager"| DP[自定义 Device Plugin<br/>rlinf.io/device-franka]
DP -->|注册| ARM[机械臂/CAN/摄像头]
K -->|CDI 注入| C
P -.->|设备节点直访| ARM
P -.->|"SR-IOV VF<br/>net1 接口"| VF[SR-IOV VF]
VF --> PF[PF 物理网卡] --> SW[高吞吐数据面]
M[Multus CNI<br/>meta-plugin] -.->|多接口编排| P
end关键细节:
- Multus 不是独立 CNI,是 CNI 多路复用器——官方原文:「Multus acting as a “meta-plugin”, a CNI plugin that can call multiple other CNI plugins」,且要求先装一个默认网络 CNI。
⚠️ SR-IOV 这条要分模式说(原稿说得太绝对)。SR-IOV CNI 有两种驱动模式:
模式 VF 绑定 是否绕过内核网络栈 kernel driver(默认/最小可用配置) 内核驱动,进入 Pod netns 作为内核网卡 否,走内核栈 DPDK userspace(uio/vfio) vfio-pci/uio,Pod 拿到 PCIe 设备节点是,数据面在用户态 所以「绕过内核网络栈、Pod 直接拿到 VF 的 PCIe 设备节点」只在 DPDK/vfio 模式成立。另外「延迟微秒级」是通行描述,但我没找到官方量化的原文,宜标为量级参考。
NetworkPolicy 那条也要补:标准 K8s NetworkPolicy 由主 CNI 在默认接口(eth0)上实施,secondary 网络(含 SR-IOV)确实不在标准 NetworkPolicy 覆盖范围内;但不是「完全管不到」——可以用上游的 MultiNetworkPolicy CRD 单独给 secondary 接口加策略。
- kubelet 的 Topology Manager 在这里发挥作用:从各 Hint Provider 收集 NUMA hint 并对齐,scope 取
container(默认)或pod,policy 取none(默认)/best-effort/restricted/single-numa-node。对齐对象是 CPU(经 CPU Manager)、内存/大页(Memory Manager)、设备(Device Manager)。GPU 和 SR-IOV NIC 不是 Topology Manager 直接识别,而是其 device plugin 在Allocate里返回TopologyInfo、经 Device Manager 参与对齐。
六、全场景对比
| 维度 | 裸金属容器仿真 | Agent 工具调用沙盒 | Kata VM 强隔离 | 真机设备接入 |
|---|---|---|---|---|
| 高级运行时 | containerd(标准) | containerd + agent-sandbox controller | containerd(RuntimeClass=kata) | containerd(标准) |
| 低级运行时 | runc | runsc / fc-agent+runc / kata-agent | kata-runtime(shim v2,per VM) | runc |
| 与 kubelet 耦合点 | CRI + Device Manager + CDI | CRI + RuntimeClass | CRI + RuntimeClass + VFIO | CRI + Device Manager + Multus |
| GPU 路径 | 物理直访 / HAMi 时间片 / DRA 切片 | 无(CPU 密集) | VFIO 整卡直通 | 不涉及 |
| 沙盒边界 | namespace + cgroups + seccomp | 用户态内核 / microVM | microVM + 独立内核 | namespace + cgroups |
| 存储增强 | nydus-snapshotter 按需加载 | guest 内文件系统 / Kata virtio-fs | virtio-fs(virtiofsd 在 host) | 标准 overlayfs |
| 启动延迟 | 秒级 | <50ms(VM 池化预热后) | 分钟级 | 秒级 |
| 适合负载 | RL 仿真、CUDA 训练 | 代码执行、工具调用 | 多租户、不可信代码 | 真机调度、数据流水线 |
| 不适合 | 强隔离多租户 | GPU 负载 | 高密度 GPU 仿真 | 强隔离 |
七、选型决策要点
第一,不要找一个万能沙盒,找一组 RuntimeClass。 上面四个场景可以在同一集群共存:仿真 Pod 用默认 runtime、Agent 工具调用 Pod 用 firecracker 或 gvisor、多租户 Pod 用 kata、真机 Pod 用默认 runtime + 自定义 device plugin。K8s 的 RuntimeClass 机制(1.20 GA)就是为这种混合负载设计的。
第二,区分「标准 RuntimeClass 路径」与「自带控制平面路径」。 firecracker-containerd、独立 firecracker-shim、Kata+Firecracker 都走 kubelet → CRI → containerd → shim 链路,K8s 调度、NetworkPolicy、metrics 全部原生生效;AgentENV / CubeSandbox 这类系统自带 Master/Scheduler/Node 组件,K8s 只承载外层 Pod,内层 microVM 的生命周期、容量、网络策略都要独立建设。前者运维负担小但灵活性受限,后者需要平台团队持续投入——没有银弹。
第三,GPU 负载先定 GPU 路径,再定沙盒路径。 仿真主流是裸金属容器 + 设备插件直访;强隔离多租户才考虑 VFIO 直通(Kata);MIG-backed vGPU 是「想保留 VM 形态又要硬件隔离」的折中;virtio-gpu(Venus/VirGL)只翻译图形 API,不覆盖 CUDA,仿真栈直接排除。GPU 路径定了,沙盒技术选型的可行集就自动收敛了——这是具身场景与通用容器场景最大的不同。
第四,快照与断点续跑是分层解决的。 仿真 rollout 的状态恢复靠仿真器 save_state(GPU 状态 hypervisor 快照不了);Agent 工具调用沙盒的暂停恢复靠 microVM snapshot(CPU + 内存状态)。两者的快照机制不通用,混用会掉坑。
一句话总结:kubelet 之下,高级运行时管「怎么调度和编排」,低级运行时管「跑在什么隔离边界里」;具身智能公司的沙盒架构不是选一个技术,而是按负载类型把 runc、gVisor、Firecracker、Kata 各归其位,用 RuntimeClass 和 Device Plugin 把它们编成一个整体的调度拓扑。
相关阅读
- 沙盒的「第二控制平面」:AgentENV 与 CubeSandbox 为什么要绕过 kubelet 自建调度器——下篇:当沙盒生命周期压到毫秒级,调度器为什么必须从 K8s 里独立出来
- 具身智能仿真场景的沙盒选型——上篇:为什么仿真主力是裸金属容器而非 microVM,虚拟化层 GPU 转发的四条路径边界
- Agent 沙盒基础设施实践:从 DSec 与 AgentENV 看调度层的选型与落地——多级运行时的完整拆解
- containerd Snapshotter 接口深度解析——nydus / remote snapshotter 的机制
- 从冯·诺依曼到 Agent 沙箱:虚拟化隔离技术栈的一次完整拆解——隔离谱系
- K8s GPU 复用与 HAMi 异构架构全解——HAMi 的切分机制
- DRA 拓扑感知调度——DRA 的调度侧机制
核实说明:本文架构描述逐条核对自一手来源——Kubernetes 官方文档(CRI、RuntimeClass、Topology Manager、Device Plugin、DRA)与 feature gate 定义、containerd 官方文档与源码(
docs/runtime-v2.md、docs/sandbox-api.md、cri/docs/architecture.md、docs/containerd-2.0.md)、CRI proto、CDI 规范仓库、Kata Containers 官方仓库(docs/design/architecture/history.md、virtualization.md、hypervisors.md、storage.md、各 how-to)、gVisor 官方文档与pkg/lisafs/README.md、Firecracker 官方仓库与 FAQ、AWS firecracker-containerd 仓库、HAMi / nydus-snapshotter / Multus / SR-IOV CNI / sriov-network-device-plugin / dra-driver-cpu / CubeSandbox 各项目 README。原稿更正汇总:CNI 的调用方(containerd 非 kubelet)、pause 容器归属阶段、shim 的 per-pod 粒度是 runc.v2 的实现选择而非 containerd 语义、「不再 fork runtime 二进制」不准确(shim 仍 exec runc)、DRA driver 返回的是 CDI device ID 而非「生成 CDI spec」、CDI 默认值随 containerd 版本变化、gVisor 的 Sentry↔Gofer 协议是 LISAFS 非 9P、firecracker-containerd 的架构描述(shim + control plugin,ttrpc 非 gRPC,容器走标准 V2 runtime)、Kata 默认 VMM 是 Dragonball 非 Cloud Hypervisor、Kata 硬件支持列表中的 FPGA 无据、SR-IOV「绕过内核网络栈」仅 DPDK/vfio 模式成立、NetworkPolicy 可用 MultiNetworkPolicy 覆盖、CubeHypervisor 是 RustVMM + KVM 非「基于 Cloud Hypervisor」。另外为
PipeOpsHQ/firecracker-shim标注了项目成熟度与文档口径不一致。