第 11 章 第二部分:架构原理

Runtime Injection:Nix 自包含的秘密

为什么需要自包含服务、Nix 构建方案、与 OpenHands/SWE-ReX 的对比、Checkpoint 加速

Nexus Nix Docker Runtime Injection 沙箱

问题:镜像维护的噩梦

Code Agent 场景的一个根本工程问题:LLM 输出的动作(执行命令、编辑文件)需要在目标环境中执行。这需要一个程序在环境中接收并执行动作。

主流方案是在容器内启动一个服务(OpenHands 和 SWE-Agent 都这么做)。但这带来了 Scale 难题:

以 SWE-Gym 为例:2438 个实例,每个对应一个不同的 Docker 镜像,总计约 6TB。如果你要在所有镜像上运行 Agent,就需要给 2438 个镜像全部安装运行时依赖——可能遇到依赖冲突、构建失败、维护成本爆炸。

OpenHands 的做法:为每个基础镜像构建新的运行时镜像。要求目标环境基于 Debian,需要安装指定版本的依赖。

SWE-ReX 的做法:两种模式——动态安装(pipx install)或构建新镜像。前者需要网络,后者和 OpenHands 一样要维护镜像映射。

Nexus 的解法:完全自包含的 /nix volume

核心思路:做一个不依赖任何外部系统就能运行的服务,放在一个公共 Docker volume 中。任何镜像挂载这个 volume 就能启动。

第一步:Nix 构建基础依赖

通过 Nix(声明式包管理器)构建所有操作系统级依赖:Python、uv、git、tmux、chromium、sshd 等。Nix 的关键特性是路径确定性——所有依赖存储在 /nix/store 下,路径基于内容哈希生成。

第二步:uv 构建 Python 环境

基于 Nix 提供的 Python,用 uv 创建 venv 并安装所有 pip 依赖。环境存储在 /nix/runtime/。

第三步:Docker volume 挂载

构建一个只包含 /nix 目录的数据镜像。使用时:

# 创建数据容器
docker run -d --name nexus-runtime nexus-runtime:latest true

# 任意镜像挂载 volume 并启动服务
docker run --volumes-from nexus-runtime -it alpine \
  /nix/runtime/nix-env/bin/bash /nix/runtime/nexus/deployment/runtime/start.sh

Alpine 镜像(musl-based)都能跑——因为 Nix 构建的所有东西都是自包含的,不依赖宿主的 glibc。

方案对比

维度OpenHandsSWE-ReXNexusDocker Sandboxesagent-sandboxmcp-boxWASM Sandbox
启动方式构建新镜像动态安装/构建镜像挂载 volumemicroVM 启动Podman rootfsNix 构建 OCI + Docker 运行Wasmtime/Wasmer 实例化
启动时间首次需构建镜像10-20秒+毫秒级秒级秒级秒级微秒-毫秒级(<5ms)
网络依赖构建时需要动态安装需要无无构建时需要构建时可选无(预编译 .wasm 模块)
镜像兼容性仅 Debian仅 glibc任意 x86 LinuxmacOS/Windows/Linux(sbx CLI 独立于 Docker Desktop)任意 Linux任意 Linux(Docker 可运行)任意 WASM 运行时(浏览器/服务器/边缘)
隔离级别容器容器容器microVM容器(rootfs)容器(零 capabilities + 只读根 + 无网络)语言级(线性内存+能力基础安全)
维护成本每个镜像单独构建每个镜像单独构建单一 volumeDocker 管理Nix 包合约单一 flake.nix单一 .wasm 模块
离线部署需预构建需预构建完全支持支持需预构建支持(预构建镜像)完全支持

mcp-box(GitHub)代表了 Nix + Docker 模式在安全敏感场景(MCP Server 执行)的深化——同样利用 Nix 的确定性构建 + Docker 隔离,但增加了零 Linux capabilities(--cap-drop=ALL)、只读根文件系统(--read-only)、tmpfs 临时空间、per-profile 网络策略(按 profile 配置,而非一律切断)等更严格的安全策略。官方口径是”只有显式挂载的目录可写,其余宿主路径不可达”,自我定位为 default-deny by design。比 Nexus volume 更安全,但牺牲了灵活性。

⚠️ 一处必须澄清的归属:mcp-box 官方 README 原文——“Nix is used for deterministic image builds when present, but it is entirely optional. Without Nix, mcp-box pulls the same pinned OCI image definitions from GHCR and runs them under the same Docker isolation model. Docker is the only hard requirement.” 也就是说,mcp-box 证明的是”容器隔离 + 默认拒绝对 MCP Server 有效”,不能算作 Nix 普适性的证据。它真正说明的是另一件事(见下):Nix 在这里是可插拔的。

WASM Sandbox 代表了一个不同的隔离哲学——不是从完整 OS 开始层层收紧(Docker),也不是从一无所有开始按需构建(Nix),而是通过语言运行时在编译期和运行期双重保障安全。核心特征:线性内存隔离(无法逃逸到宿主机地址空间)、能力基础安全(零环境权限+显式能力注入)、跨平台一致性。代表实现包括 agent-sandbox(Rust+Wasmtime,内置 80+ CLI 工具+Shell+JS 运行时)、BoxAgnts 工具系统(每个工具是独立 WASM 模块)、Wassette(Microsoft 开源,WASM+MCP 协议)。但 WASM 沙箱目前有三大局限:Python 执行需 Pyodide 先编译为 WASM(“解释器之上的解释器”性能损耗)、重度 C 绑定库(numpy/pandas/torch)难以编译进 WASM、WASI 标准仍在 Preview 1→2 剧烈变动期。这些局限使 WASM 适合”Agent 工具调用”场景(每次调用实例化一个 WASM 模块,执行完毕后销毁),但无法替代 Docker/微VM 的”全 OS 语义”需求(文件系统操作、多进程管理、GPU 计算)。

Docker Sandboxes 的 2026-08 进展:Docker Sandboxes 于 2026-08-11 已支持 macOS/Windows/Linux 三平台,sbx CLI 免费(含商用),且独立于 Docker Desktop。两个关键设计值得关注:(1) Docker-in-sandbox——每个 sandbox 自带独立 Docker daemon,规避传统 Docker-in-Docker 的权限逃逸风险;(2) 凭证代理注入——宿主侧代理持有真实凭证,sandbox 内 agent 只接触占位符,代理在出站请求时拼接真实 Authorization header,避免把 API Key 暴露给不可信的 agent 进程。

Checkpoint 加速

Nix Agent 生态验证

Nexus 的 Nix 方案并非孤例——Nix 在 AI Agent 生态中的应用正呈现四个层次:

  1. 运行时依赖构建(Nexus /nix volume)——构建 Python/uv/git 等系统依赖,注入任意 Docker 镜像。这是当前 Nexus 的核心用法。

  2. Agent 完整部署(Hermes Agent)——NousResearch 的 Hermes Agent 完全基于 Nix 部署:nix profile install github:NousResearch/hermes-agent 一行安装,提供 NixOS 服务模块声明式管理。这比 Nexus 的 volume 挂载更简洁——Nix 不仅是运行时注入手段,更是 Agent 的完整包管理器。

  3. MCP Server 沙箱化(mcp-box)——Docker 严格隔离 + 默认拒绝;Nix 在其中只用于确定性镜像构建,且完全可选(无 Nix 时从 GHCR 拉同一套 pinned OCI 镜像)。

  4. 微VM 原生部署(microvm.nix)——将 Nix 声明式构建与微VM 强隔离结合。通过 virtiofs 共享 /nix/store(避免每次重建镜像)、sops-nix 注入密钥、unbound DNS 日志+nftables 连接日志实现网络可观测性。代表案例:OpenClaw 微VM 部署(2026)和通用 Coding Agent VM 方案。

microvm.nix 对 Nexus 的启示:Nexus 的 /nix volume 方案挂载到 Docker 容器(容器级隔离),而 microvm.nix 挂载到微VM(hypervisor 级隔离)。两者的共同前提——Nix 的路径确定性和自包含——使得从容器级升级到微VM 级仅需替换运行时(Docker→microvm.nix),无需修改 /nix 内容。这是 Nexus 沙箱安全性的可选升级路径。

四个层次验证了 Nix 自包含特性的普适性:从”运行时注入”(仅构建依赖)扩展到”全生命周期管理”(部署 + 配置 + 更新 + 回滚)。Agentbox(基于 NixOS Flakes 构建 ARM Agent 容器,1.4GB headless runtime,支持云端 API 和本地 GPU 双模式)进一步证明 Nix 可承载异构硬件场景的 Agent 部署。

其中第 3 层需要按上面的限定来读:mcp-box 说明的不是 Nix 的普适性,而是Nix 是可插拔的——它在没有 Nix 时用 pinned OCI 镜像达到同样的确定性。这与 Nexus 的 /nix volume 是两条不同的确定性路线:前者靠镜像哈希,后者靠内容哈希路径,可以互为对照而非互相印证。

Nix 的自包含特性还带来一个额外收益:容器 checkpoint 可以跨镜像复用。

在容器 + 无外部挂载的语境下,传统方案确实做不到——不同镜像的库路径不同,checkpoint restore 会失败。但这个全称判断现在需要加限定:对带外部挂载的沙箱,该限制已被上游解除——CubeSandbox v0.7.1(2026-09-11,#1654 / #1656)起,Host Mount 与 Volume Plugin 的沙箱同样支持快照 / 恢复 / 回滚 / 克隆;v0.7.2(2026-09-24)另新增 JuiceFS 卷插件,提供完整 POSIX 语义的共享持久卷。而 Nix 的路径是确定的(基于内容哈希),所以:

  1. 启动 Runtime Server,等待初始化完成
  2. 做 container checkpoint
  3. 在任意挂载了相同 /nix volume 的容器中 restore

这可以节省 几秒到十几秒 的启动时间——Python 解释器启动、import、FastAPI 路由注册全部跳过。

Checkpoint 产业化进展

CRIU(Checkpoint/Restore In Userspace)版本线:v4.1(CRISC-V,2025-03-25)→ v4.1.1(2025-07-29)→ v4.2(CRIUTIBILITY,2025-11-13)→ v4.2.1(2026-07-21,最近一次发布;2026-10-06 复测 releases.atom 仍为 v4.2.1,无新版本)。AI/ML 工作负载的 checkpoint 已成为产业焦点:

  • KubeCon EU 2025 专题讨论 AI 工作负载的 checkpoint/restore,涵盖 GPU 迁移和大规模 Agent 批量执行场景
  • ISC 2025 高性能容器工作坊讨论 GPU checkpoint 在 AI 推理中的应用
  • PhoenixOS 论文提出并发 OS 级 GPU checkpoint,探索 GPU 状态的即时保存与恢复

⚠️ 不要把 CRIU 的版本线读成沙箱快照能力的进度条。 本章下面列举的产业落地证据(CubeSandbox 等)并不依赖 CRIU——microVM 侧的快照走的是 CoW 文件系统 + 内存回收(整机状态的复制与恢复),与 CRIU 的进程级 checkpoint 是两条技术路线。CRIU 停更不代表沙箱快照停滞,反之亦然。(此为本书分析推论 📌。)

这些进展说明 checkpoint 不仅节省启动时间,更在大规模 Agent 批量执行中发挥关键作用——fault tolerance(故障恢复)和 preemption recovery(抢占恢复)成为核心场景。当训练集群需要同时管理数千个沙箱实例时,checkpoint 能让被抢占的实例快速恢复执行,而非从零重启。

2026 年,checkpoint 已从会议议题变成产品能力。 腾讯云 CubeSandbox(v0.5.0,2026-07-03)给出了目前最完整的落地:CubeCoW 引擎基于 XFS reflink + FICLONE ioctl,快照是 O(1) 的元数据操作配合增量脏页持久化,因此保存一个 2GB rootfs 状态、克隆一个运行中沙箱、回滚到历史状态都在秒级;AutoPause/Resume 让空闲沙箱自动快照挂起(零资源消耗)并在下次请求时百毫秒级透明唤醒;跨机暂停与恢复(Preview) 配合 S3 快照后端,使已暂停的沙箱可在集群内任意兼容节点恢复。

值得留意的是,它的可行前提与本章 /nix volume 的论证同构:CubeSandbox 能跨机恢复,是因为沙箱状态被完整封装在可复制的镜像里;Nexus 的 checkpoint 能跨镜像复用,是因为 Nix 的 /nix/store 路径由内容哈希决定。两者是同一条原理——确定性路径 → 状态可迁移——在两个层面的实现。(此为本书基于官方材料的分析推论,非厂商原话。)

这也把 checkpoint 的价值从本章原写的”节省几秒到十几秒启动时间”扩展到三个新场景:① 分叉探索分支——从同一检查点克隆多条 rollout 路径(RL 训练直接需要);② 跨机迁移——节点维护或故障不再困住长跑任务;③ 空闲降本——长跑评测中的空闲沙箱可挂起到零资源消耗。第 ① 点对 Nexus 尤其相关:Nexus 的主要用途之一就是 RL 训练环境。

方向性判断(本书推论 📌,非厂商原话):把 CubeSandbox 的 v0.7.1 外部挂载快照与 v0.7.2 的 JuiceFS 卷插件放在一起看,“共享只读卷 + 快照”这一形态正从Nexus 的自研技巧下沉为沙箱层的通用能力——JuiceFS 插件本质上就是”一份共享文件系统挂给一堆沙箱”,与 /nix volume 同一形态,只是换到了 microVM 侧且带快照。因此 Nexus 真正难以被替代的不是”能 checkpoint”,而是”零网络依赖 + 任意 x86_64 Linux 镜像可直接挂载”这一条。(同一结论已同步写入 Ch10 文末,两处须一起读。)

沙箱方案选择决策树

不同场景对沙箱的需求差异巨大。基于上述五种方案的特性,以下决策树帮助选择:

需要运行不可信代码(LLM 生成的工具调用)?
  ├─ 是 → 需要完整 OS 环境(文件系统/多进程/GPU)?
  │        ├─ 是 → 需要最强隔离(零信任环境)?
  │        │        ├─ 是 → Docker Sandboxes / microvm.nix(microVM 隔离)<!-- edit: 2026-09-15 补限定:microVM 只解决内核逃逸,不解决宿主文件挂载语义 -->
  │        │        └─ 否 → Nexus /nix volume(自包含,零网络依赖)
  │        └─ 否 → WASM Sandbox(<5ms 冷启动,语言级隔离)<!-- edit: 2026-07-22 新增 WASM 分支 -->
  └─ 否 → 标准容器/动态安装方案...

关键考量:

  • 隔离 vs 速度:microVM 隔离性最强但启动最慢(秒级 vs 毫秒级)
  • 离线 vs 在线:Nix volume 和 bubblewrap 支持完全离线,其他方案需要网络
  • 维护 vs 灵活:单一 volume 维护成本最低,但灵活性不如动态安装
  • 内核逃逸 vs 挂载语义(2026-09-15 新增):选了 microVM 不等于拿到”最强隔离”。microVM 解决的是内核逃逸(独立 Guest 内核),不解决宿主文件的挂载语义。CVE-2026-18171(CVSS v4.0 5.7 / MEDIUM,2026-08-12 披露,已回 NVD 官方 API 核实)中,Docker Sandboxes 只把只读意图应用到客机内的容器 bind,底层 virtio-fs 的宿主侧授权却以”无访问模式”加入共享允许列表,攻击者经另一条可写导出路径即可改写运维本以只读方式挂载的宿主目录。结论:上了 microVM 之后,仍需审计”同一宿主路径在容器内的所有可达路径”。Ch10 的五层纵深防御框已同步补注。
  • 进程收殓(2026-10-06 新增):本章通篇没有讨论”客户端断开后沙箱内进程如何收殓”。上游运行时专门修过一类问题——agent-sandbox v1.0.3(#1379)把 sandboxd 的默认进程取消方式改为进程组终止(-PGID),修的正是客户端断开后孤儿子孙进程泄漏。Nexus 的 RemoteRuntime 同样存在”Host 断开 / 重连”路径(见 Ch12 RPCReplayGuard),该路径下沙箱内由 Executor 派生的子进程如何收殓,本章未体现。📌 需对照 nexus/runtime/server 的实际进程管理代码核实——这是内部事实,外部不可核,因此只登记为待核查项,不作缺陷断言。

沙箱编排标准化与安全动因

除表格中的七种方案外,2026 年还有两个值得关注的进展。

其一,Kubernetes 原生 agent-sandbox controller 已于 2026-08-28 发布 v1.0.0(最近一次发布 v1.0.5,2026-10-01;版本线 v0.5.5 → v0.5.6 → v1.0.0(2026-08-28)→ v1.0.1(2026-09-03)→ v1.0.2(2026-09-11)→ v1.0.3(2026-09-17)→ v1.0.4(2026-09-24)→ v1.0.5(2026-10-01,核于 2026-10-06)),隶属 SIG Apps。这改变了它的选型含义:它不再是”要不要赌一个新项目”,而是”要不要对齐一个已经定版的生态标准”。它引入原生 Sandbox CRD 作为核心抽象,并在 extensions 模块提供 SandboxTemplate(可复用模板)、SandboxClaim(从预热池申领)、SandboxWarmPool(预热池管理)。其定位是沙箱编排器而非隔离实现:低级容器隔离委托给 gVisor 或 Kata Containers 等”Sandbox Runtime”,通过 RuntimeClass 配置 Pod 来达成。这恰好印证了它与表格中 agent-sandbox(Podman rootfs)的分层差异——前者是编排层标准,后者是单机沙箱实现。

⚠️ 一条可复用的引用判据(2026-10-06):该项目的发布节奏是约每周一个 patch——2026-08-28 到 2026-10-01 的 34 天里发了 v1.0.0 到 v1.0.5 六个版本。任何”当前最新版本”的表述在本书出版周期内的存活期都以周计。因此本章此后一律写”最近一次发布为 YYYY-MM-DD,核于 YYYY-MM-DD”,不写”最新”。

GA 对 Nexus 的含义:此前”对接 K8s 运行时”是一个可选优化,现在它是有标准可依的对接——SandboxClaim + SandboxWarmPool 的组合正好对应 Ch10 §池化调度与批量交付 里 Nexus 缺的预热池化能力,且 API 已经冻结。

v1.0.3–v1.0.5 把可对接的层次从编排扩到了执行(均取自官方 release notes 正文):

  1. 执行层已就位——v1.0.5(2026-10-01)起 TypeScript SDK 具备完整运行时层:经 gRPC 的 sandbox.commands.run()、文件系统操作(read / write / exists / list / delete)、sandbox.health() 与 sandbox.metadata(),另有流式文件传输;v1.0.4(2026-09-24)起 Python 侧支持 async sandboxd。含义:上文”对接 K8s 运行时”此前讨论的只是编排层(claim / warmpool),现在连执行层(跑命令、传文件)都有官方 SDK——Nexus 若要对接,不必只借编排层。
  2. RL 成为一等集成对象——v1.0.4 增强了 RL SDK 的并发隔离,v1.0.5 又新增 OpenAI Agents 集成(#1388,含 workspace hydration 与 session resumption),并给出 Ray RLlib PPO 端到端示例。本章与 Ch10 都把 RL 训练列为 Nexus 主要用途之一;这条让”K8s 沙箱编排”从编排标准进一步变成 RL 训练环境的事实底座。
  3. 进程组清理——v1.0.3(2026-09-17,#1379)把 sandboxd 默认的进程取消方式改为进程组终止(-PGID),修的是”客户端断开后子孙进程泄漏”。这条对 Nexus 是一个本章未覆盖的对照项,见决策树的「进程收殓」一条。

另有两个官方细节值得记下。一是 Sandbox Router——一个把 SDK 与外部客户端流量路由到 sandbox pod 的 HTTP 反向代理;它的存在理由对 Nexus 有直接用处:在 Kata Containers / gVisor 这类 runtime 下无法直接 port-forward,必须走 Router。Nexus 的 RemoteRuntime 同样靠 HTTP 端点通信,若未来对接 Kata/gVisor,会遇到完全相同的问题,Router 是现成答案。二是安装可分两套 manifest:核心(sandbox-with-extensions.yaml)与扩展(extensions.yaml,API group 为 extensions.agents.x-k8s.io)。

⚠️ 若按上文建议走 Router,须先处理 v1.0.2(2026-09-11)的两条破坏性变更(官方 release notes 的 Breaking Changes / Action Required 小节):

  1. sandbox-router 的公开 authz.Authorizer 接口签名由 (namespace, name) 两个字符串参数改为单个 authz.AuthorizationTarget 结构体(#1497)——自定义实现必须改 Authorize 方法。
  2. Go sandbox-router 的部署 manifest 从 default 命名空间迁至 agent-sandbox-system(#1537,理由是特权分离并对齐 SDK 默认与 NetworkPolicy)——裸 manifest 部署者须同步修改脚本。

两条都属于”升级后静默失效”类型:前者编译期报错还算友好,后者会让你 apply 到旧命名空间而 Router 实际不在那里。

其二,容器隔离的安全边界正被重新审视:CVE-2025-59528(Flowise CustomMCP 节点远程代码执行,CVSS v3.1 baseScore 10.0 / CRITICAL)暴露约 12,000-15,000 个互联网实例,60% 攻击流量转向 MCP endpoint 侦察。其成因具有普遍性——CustomMCP 节点允许用户为连接外部 MCP server 输入配置,却对该配置解析不当,导致攻击者可在宿主机上执行任意代码。共享内核容器在不可信 agent 代码场景下的隔离不足,是 microVM/WASM 等强隔离方案兴起的重要安全动因。