05 隔离后端选型
本章导读|预计 20 分钟
这一章做两件事:先选一条隔离边界,再看被它倒逼出来的四个配套机制。 读完你应该能回答:我的场景落在哪一类边界上,以及配套的四个机制各自要看什么。
5.1 两层结构:一条边界 + 四个配套机制
Section titled “5.1 两层结构:一条边界 + 四个配套机制”先说一个容易被跳过的结论。
隔离不是一个从「弱」到「强」的滑块。旧版这一章把选型压成一条强度轴——Docker < gVisor < microVM < 完整 VM——这条轴有两处失真:
- 它抹掉了「OS 系统调用策略」这一整档:macOS Seatbelt、Linux bubblewrap、Landlock,以及 Anthropic 的
srt,是一条独立的路线,不是容器轴的某个刻度点; - 它把 bubblewrap 误读成「弱隔离」。bwrap 的定位是「给已有进程加围栏」,和容器根本不在同一个维度上比——这一点下面单独讲。
更准的结构是两层。
第一层,五类互斥的隔离边界(选一个)。它们之间的区别是「边界画在哪」:
| 边界 | 边界画在 |
|---|---|
| microVM | 环境 ↔ hypervisor |
| 用户态内核(gVisor) | 应用 ↔ 用户态内核 |
| 容器 + 加固 | 进程视图 ↔ 宿主内核(同一个内核,靠命名空间与策略切分) |
| OS 系统调用策略 | 进程 ↔ 宿主内核能做的事(不上容器,只收窄这个进程的能力面) |
| WASM | 代码 ↔ 语言运行时 |
第二层,四个配套机制(都要有):快照与分叉 / 网络控制 / 凭据隔离 / 编排与接入。
第二层不是可选装饰。它是被第一层倒逼出来的:选了 microVM,就欠下「启动重,需要预热池或快照来补偿」这笔账;选了 WASM,就欠下「没有原生文件与网络,能力必须靠 host 逐项授予」这笔账。选完边界,这四件事基本已经被规定。
下面先把五类边界逐一看清,再来看四个机制各自要看什么。
5.2 五类隔离边界
Section titled “5.2 五类隔离边界”一句话先立住:这五类是互斥的,一个沙箱方案通常属于其中一类(可在边界之外叠加加固,但不是另一类)。代表项目与定位取自 2026-10-21 采集、2026-10-22 复验的 GitHub REST API 快照。
5.2.1 microVM
Section titled “5.2.1 microVM”怎么隔离:每个沙箱一台轻量虚拟机,有独立的 guest 内核。Linux 上走 KVM,macOS 上走 Hypervisor.framework。宿主只暴露最小设备面(virtio 的块设备、网卡、串口),攻击面因此比通用 hypervisor 小得多。
代表项目:firecracker-microvm/firecracker(37.5k stars,microVM 事实标准)· libkrun 系(microsandbox 8.8k、smolvm 6.8k)· Cloud Hypervisor。承载它的沙箱产品有 E2B(14.5k)与 OpenSandbox(16.0k)。
代价:要 KVM(或 macOS 的 HVF)。取不到 KVM 的宿主就用不了——多数托管容器环境、部分 CI、嵌套虚拟化受限的云主机都属于这一类。此外每实例有 guest 内核的内存开销,GPU 直通麻烦(极简 microVM 通常不支持),启动路径比容器重。
「完整 VM」放哪:QEMU/KVM 完整 VM 属于这一档的重量级端——同一个隔离边界(独立 guest 内核 + hypervisor),只是设备面更全、支持 GUI 与 GPU,代价是启动到秒级。它不是第六类。
5.2.2 用户态内核(gVisor)
Section titled “5.2.2 用户态内核(gVisor)”怎么隔离:runsc 用一个 Go 写的 Sentry 进程接管 guest 的系统调用,自己实现一套内核语义;宿主内核只看到 Sentry 发出的极少接口。也就是说,应用以为自己在对内核说话,其实在跟一个用户态进程说话。
代表项目:google/gvisor(19.7k)· Dormice(gVisor / Docker 双后端,打 E2B 兼容牌)· GKE Sandbox · Isola。
代价:syscall 兼容性。没实现的系统调用直接返回 ENOSYS(部分 ioctl 与特殊文件系统操作落在这一类),某些语言运行时或依赖会踩;ptrace 模式下 syscall 密集的负载明显变慢。哪几个 syscall 缺失、慢多少,取决于你的负载——调研里没有本地基准,这一项要自己实测(这是归纳,不是来源的说法:调研只记录了「官方宣称」级别的说法,没有实测数据)。
5.2.3 容器 + 加固
Section titled “5.2.3 容器 + 加固”怎么隔离:共享宿主内核,靠 namespaces + cgroups v2 + seccomp-bpf + capabilities 裁剪 + 只读 rootfs + AppArmor/SELinux 把进程的视图与权限切分。注意最后一个词:加固。容器本身给的是「环境」,安全全部来自你叠上去的策略。
代表项目:Docker / Podman · dify-sandbox · 多数「能跑就行」的方案。(旧版 Daytona 用 Sysbox 做加固,但该仓库 2026-06 起转闭源,见第 8 章。)
代价:共享宿主内核,内核漏洞即逃逸;强度取决于配置,默认不是安全的。三种典型失手:
--privileged:等于把宿主权限直接交给容器;- 挂载
docker.sock:容器能创建新容器,等于拿到宿主的控制权; - 内核 0-day:容器之间没有内核级边界,一个租户能攻击另一个。
单租户、可信代码,这一档够用且最省。多租户场景下,A 客户的代码不该有机会碰到 B 客户——容器给不了这个保证,microVM 可以:逃逸要同时攻破 guest 内核与 hypervisor 两层。
5.2.4 OS 系统调用策略
Section titled “5.2.4 OS 系统调用策略”这是旧版整章缺失的一档,也是本章要补的关键空白。
怎么隔离:不上容器,直接给一个进程套策略,把它的能力面收窄:
- macOS Seatbelt:系统自带的沙箱机制(
sandbox_init/ seatbelt profile),按 profile 限制进程能做的操作; - Linux bubblewrap:user namespace + bind mount + seccomp,
bwrap一条命令就能把进程关进一个受控的挂载与 syscall 视图; - Landlock:Linux 内核提供的 LSM,让进程(包括非特权进程)把自己声明过的文件系统访问权限收窄;
- Anthropic
srt(anthropics/sandbox-runtime,5.6k):把三者拼起来——macOS 用 Seatbelt、Linux 用 bubblewrap,再外加一个网络过滤代理,不依赖容器即可限制任意进程的文件系统与网络。
代表项目:Anthropic srt · nono(per-tool-call brokered sandboxing)· hivebox · yoloai。
代价:仍然是同一个宿主内核,只是把进程能做的事情收窄了。策略写错就是漏,而且难审计——它是声明式的,边界没有运行时可观测的形态。
它和容器档的区别(这一条最容易混):容器改变的是进程看到的世界(隔离的 rootfs、网络视图、pid 视图),OS 策略改变的是进程能做的事(哪些 syscall、哪些路径)。所以两者不是强度上的高低,而是形态上的不同,而且可以叠加——在 bwrap 里跑不跑容器都行。
定位纠正:bubblewrap 常被归进「弱隔离」那一列,这是误读。它这一档的主流用途就是「给已有 agent 加围栏、不上容器」:你已经在宿主机上跑着 Claude Code 一类的工具,只想给它加一层围栏,不想额外管理镜像与生命周期。这就是它存在的理由,也是它和容器不在同一档的原因。
5.2.5 WASM
Section titled “5.2.5 WASM”怎么隔离:代码编译成 wasm,在 Wasmtime / V8 isolate 里执行,能力靠 host 显式授予(WASI 的能力模型:没拿到 fd 就碰不到文件与网络)。边界因此画在「代码 ↔ 语言运行时」之间。
代表项目:rivet-dev/agentos · Cloudflare 系方案。
代价:没有通用的 POSIX 环境,跑不了任意二进制。syscall 面不全,生态兼容性在五类里最差。把 Python / Node 生态搬进 WASM 的改造代价,经常高于隔离本身带来的收益——这一档要当心「轻量」这个词,它轻的是运行时,不一定是你的工作量。
5.3 常被混为一谈的一组:gVisor 与 microVM
Section titled “5.3 常被混为一谈的一组:gVisor 与 microVM”两者都加强隔离,但走的是不同路线,一个是边界画在应用之下,一个是边界画在环境之外:
| gVisor | microVM(Firecracker) | |
|---|---|---|
| 思路 | 用户态内核:拦截并重新实现系统调用 | 独立内核:每个环境一个精简内核 |
| 隔离边界 | 应用 ↔ 用户态内核 | 环境 ↔ hypervisor |
| 攻击面 | gVisor 自身的实现(较大) | hypervisor(较小) |
| 兼容性 | 部分系统调用未实现 → 可能跑不起来 | 接近原生 Linux |
| 资源开销 | 较低 | 每个 VM 有内核开销 |
| 启动 | 中 | 快(优化后 ~百 ms) |
| 要 KVM 吗 | 不要 | 要(Linux)/ HVF(macOS) |
怎么选:兼容性要求高、要求「像真机」→ microVM;想省内存、能接受偶发的 syscall 不兼容、又不想管 VM → gVisor。取不到 KVM 的宿主上,gVisor 往往是唯一能拿到「比裸容器强」的手段。
5.4 横向对照表:除隔离强度还要看什么
Section titled “5.4 横向对照表:除隔离强度还要看什么”隔离强度只是第一眼。真正决定「这个后端能不能用」的是下面四列,按五类边界横向排开:
| 边界 | 取 KVM / GPU 能力 | syscall 兼容性 | 内核漏洞面 | 运维复杂度 |
|---|---|---|---|---|
| microVM | 需要 KVM 或 HVF;GPU 直通麻烦,极简 microVM 通常不支持 → 要 GPU 就上完整 VM / Kata / 托管 GPU 沙箱 | 最好(guest 内核就是 Linux) | 最小:逃逸要跨 guest 内核 + hypervisor 两层 | 最高:镜像、VM 编排、池化与回收 |
| 用户态内核(gVisor) | 不需要 KVM;不支持特殊 ioctl,GPU 场景基本排除 | 中:未实现的 syscall 返回 ENOSYS |
小:宿主内核面窄,但 gVisor 自身实现即攻击面 | 中:作为 RuntimeClass 接入现有容器工具链 |
| 容器 + 加固 | 不需要 KVM;GPU 可直通(nvidia-container-toolkit) | 最好(原生内核) | 最大:与宿主共享内核 | 最低:生态与工具链最成熟 |
| OS 系统调用策略 | 不需要 KVM;策略只约束进程能力,与 GPU 无关 | 最好(仍是宿主内核,只是能力被收窄) | 同容器:共享内核,但进程权限面更小 | 低到中:单进程起步很容易,跨平台差异(Seatbelt ↔ bwrap/Landlock)要分别维护 |
| WASM | 不需要 KVM;没有 GPU 概念 | 最差:只有 WASI 子集 | 最小(边界在语言运行时层) | 中:要重编译 / 移植生态 |
两条读表的要点:
- 「隔离强度 ↔ 兼容性」的反向关系对容器、gVisor、WASM 成立(拦得越多、越可能跑不起来),有两处例外:microVM 靠独立内核拿到强隔离、又保住接近原生的 syscall 兼容,这是它成为生产多租户首选的主要原因;OS 系统调用策略用的是真内核,兼容性不受影响,被收窄的是进程的能力面。
- 「运维复杂度」和「安全上限」的方向常常相反。小团队选托管方案不算偷懒,它是在买运维这一列。
5.5 选择口诀与决策树
Section titled “5.5 选择口诀与决策树”可信代码 → 容器 + 加固;不可信 / 多租户 → microVM 或 gVisor;只要轻量函数 → WASM;要完整电脑 → 完整 VM;只想给已有进程加围栏 → bwrap / Seatbelt。
更细一点的判断顺序:
要跑任意代码吗?├─ 否 → 不需要沙箱(见第 9 章)└─ 是 ├─ 需要完整 OS / GUI / 桌面应用吗? │ ├─ 是 → 完整 VM(computer-use) │ └─ 否 │ ├─ 只是短小、确定性的函数吗? │ │ ├─ 是 → WASM │ │ └─ 否 │ │ ├─ 用户之间互不信任 / 面向公众吗? │ │ │ ├─ 是 → microVM(Firecracker)或 gVisor │ │ │ └─ 否 → 容器 + 加固够用;agent 已经在宿主上跑、不想上容器 → bwrap / Seatbelt一个补充分支:取不到 KVM 时(托管容器、受限 CI),上不到 microVM,就在「加固容器 + 严格 egress 代理」和 gVisor 之间选。
5.6 两条升级路径,不是一个方向
Section titled “5.6 两条升级路径,不是一个方向”旧版只写了「容器 → gVisor → microVM → 完整 VM」这一条。它其实是强度路径的一半,另外还有一条形态路径,两条轴不要混:
路径一 · 强度路径——边界有多硬:
本地开发 / 可信代码 容器 + 加固(+ 默认断网) │ 出现多租户 / 不可信输入小规模上线 gVisor(不想管 VM)或 加固容器 + egress 代理 │ 安全成为产品生命线生产多租户 microVM(Firecracker)+ 预热池 │ 需要完整 OS / GUI / GPU完整 VM microVM 的放大版(同一档,设备面更全)路径二 · 形态路径——agent 要不要放进盒子里:
agent 在沙箱外(沙箱只当工具执行器) │ agent 需要自己的 shell / 文件系统 / 长期状态,或要放任它在仓库里跑agent 在沙箱内(容器或 microVM 里装 harness + 凭据) │ 只差「给这个进程加围栏」,不想为它管理镜像与生命周期OS 系统调用策略(bwrap / Seatbelt / Landlock)直接套在已有进程上要点:不要一步到位。先用加固容器把产品跑通,等出现多租户 / 不可信需求时再沿强度路径升级。升级时控制面接口不变,只换数据面实现——这正是第 4 章 4.2 讲「控制面与数据面分离」的价值。
形态路径则是另一件事,它决定出网要求、观测点和凭据模型(第 7 章 7.1 会从场景角度展开这条分叉)。bwrap 出现在形态路径的末端而不是强度路径的起点,这正是它容易被误读成「弱隔离」的原因——它解决的不是「边界够不够硬」,而是「agent 要不要进盒子」。
5.7 四个配套机制:按边界选型时各看什么
Section titled “5.7 四个配套机制:按边界选型时各看什么”这一节只回答一个问题:**选完边界之后,这四个机制各自要看哪一项。**四项的机制实现都在第 4 章(4.6–4.11,第四项见 4.11);这一节讲的是同一件事在选型时的判据。
1. 快照与分叉。 microVM 系强依赖它。缺了会怎样:microVM 的「重启动」没有补偿手段,只能靠预热池硬扛闲置成本。选型时要看两项:这一档支不支持「存内存状态」(microVM 支持得最完整,容器侧只能靠 CRIU),以及 fork 上限够不够(E2B 文档写的是 100 份)。怎么搭见第 4 章 4.6,快照与预热池的区别见第 4 章 4.7。
2. 网络控制。 所有边界都需要,但通道要按档各自搭:WASM 一档没有原生网络,能力靠 host 逐项授予(见 5.2.5)。缺了会怎样:第 6 章那条「默认断网 + 白名单」的防线落不了地,出网只能全通或全断。选型时要看:这一档支不支持域名级 egress 白名单,以及能不能给每个沙箱配入站子域名。通道与过滤怎么搭见第 4 章 4.9。
3. 凭据隔离。 agent 在沙箱内时依赖最强。缺了会怎样:注入一旦成功,凭据就是现成的外泄物,第 6 章的头号风险直接兑现。选型时要看:凭据在哪个环节注入,沙箱里能不能读到真值。真 key 不进沙箱的搭法(vault、代理注入、占位符)见第 4 章 4.10。
4. 编排与接入。 边界复杂度决定这一层的重量。microVM 最依赖编排——CRD + controller 管生命周期、RuntimeClass 选后端、镜像懒加载(overlaybd / Nydus)压冷启动;WASM 依赖的是编译与部署管线,不是 VM 编排。缺了会怎样:microVM 的池化与回收做不起来,闲置环境堆积、账单失控。接入侧各档通用:REST/gRPC + E2B 兼容 API(已成事实标准)、MCP server、PTY over WebSocket、浏览器用 CDP、桌面用 VNC/RDP。这一项怎么搭见第 4 章 4.11;生命周期与回收的机制面见 4.4、4.5,编排与接入的产品落点见第 8 章 8.1。
5.8 场景速查
Section titled “5.8 场景速查”| 场景 | 推荐边界 | 理由 |
|---|---|---|
| 内部团队的数据分析 Agent | 容器 + 加固(+ 默认断网) | 可信用户、代码大体可控,够用且便宜 |
| 面向公众的在线代码执行平台 | Firecracker microVM | 不完全信任用户,安全 = 产品生命线 |
| 浏览器自动化 / computer-use | 完整 VM(或容器 + Playwright) | 需要完整 OS 与 GUI |
| 边缘轻量函数 | WASM | 启动极快、资源极小 |
| 本地教学 / 原型 | bwrap(OS 系统调用策略) | 零依赖、无需 root、不用容器 |
| 已经在宿主上跑的 coding agent,只想加围栏 | srt / bwrap / Seatbelt |
形态路径:不搬进容器,只收窄进程能力面 |
| 取不到 KVM 又要多租户 | gVisor | microVM 上不去时,这是比裸容器强的一档 |
5.9 常见误区
Section titled “5.9 常见误区”| 误区 | 纠正 |
|---|---|
| 「隔离是一条强度轴:Docker < gVisor < microVM < 完整 VM」 | 那是把「边界画在哪」和「边界有多硬」压成了一维。先按五类边界定位,再看 5.4 的四列比强度 |
| 「bubblewrap 就是弱隔离」 | bwrap 属于 OS 系统调用策略档:形态是给进程加围栏,不是给环境装容器。它常和容器叠加使用,两者可同时在场 |
| 「上了 microVM 就不用加固了」 | 只读根、去 capabilities、seccomp、默认断网,在任何一档都要做。microVM 只是把逃逸的代价抬高 |
| 「快照 = 预热池」 | 一个存状态(用于回溯与分支),一个省冷启动。只有在时刻对得上时才能互相替代,细节见第 4 章 4.7 |
| 「WASM 是免费的轻量隔离」 | 代价是把生态搬进 WASM:跑不了任意二进制,改造工作量常在隔离收益之上 |
| 「装了 gVisor 就一定比容器安全」 | syscall 兼容缺口会让某些负载直接失败。兼容性问题常常先于攻击出现 |
动手练习 5
Section titled “动手练习 5”给下面三个场景各选一类边界,并说明理由:
- 内部团队用的数据分析 Agent
- 面向公众的在线代码执行平台
- 浏览器自动化 Agent
再进阶两步:
- 给「既想省钱、又要多租户」的团队设计一条强度路径上的分阶段升级方案。
- 换一个已经在宿主机上跑的 coding agent:它只需要一层围栏、不值得搬进容器。说出你走的是哪条路径、为什么,以及这一档的两个代价。