🎯 一句话总结:forkd把一个已经启动并预热的Firecracker microVM保存成快照,再用写时复制快速生成大量隔离子机。它适合代码解释器、并行评测和多Agent执行,当前仍处于Alpha阶段,需要Linux、KVM和严格的网络权限配置。


📌 forkd是什么

forkd AI Agent microVM沙箱

forkd是一个面向AI Agent并行任务的microVM沙箱运行时。父虚拟机只启动一次,提前加载Python依赖、JIT运行时、模型权重或浏览器;子虚拟机从父快照恢复,共享尚未发生变化的内存页。

每个子机都是独立的Firecracker进程,由KVM提供虚拟化隔离。子机修改内存时,Linux内核通过MAP_PRIVATE执行写时复制,变化后的页面才形成独立副本。

能力实现方式
隔离每个子机独立Firecracker + KVM
快速启动从预热父快照恢复
内存复用Copy-on-Write页面共享
运行环境完整Linux、TCP网络、apt与HTTPS
资源限制cgroup v2,目前重点支持memory.max
接口CLI、REST、Python、TypeScript、MCP
运维systemd、Prometheus指标、JSON审计日志
许可证Apache 2.0

项目当前README标记为Alpha。磁盘格式和API在1.0之前仍可能变化,生产系统应固定版本并保留迁移方案。


⚙️ 为什么能快速分叉

forkd分叉运行中Agent的官方演示

传统虚拟机要重复启动内核、挂载磁盘、加载解释器并导入依赖。forkd把这些工作放在父机阶段完成:

启动父microVM
加载Python、依赖、模型或浏览器
暂停并保存内存、磁盘和设备状态
多个子Firecracker进程映射同一快照
子机只复制自己修改的页面

BRANCH允许对正在运行的沙箱制作分支。Agent可以在执行高风险命令前保存状态,再让多个子机分别尝试不同方案。

v0.4的Live Branch要求父沙箱以live_fork=True启动。它使用memfd共享内存,并通过UFFD_WP跟踪写入页面。官方基准在1.5 GiB源虚拟机上记录了56ms p50、64ms p90的暂停窗口;内存复制在父机恢复后继续进行。

from forkd import Controller

c = Controller()
parent = c.spawn_sandboxes(
    "pyagent",
    n=1,
    per_child_netns=True,
    live_fork=True,
)[0]

branch = c.branch_sandbox(
    parent["id"],
    tag="checkpoint-1",
    mode="live",
    wait=False,
)

# wait=False返回时,快照可能仍处于writing状态
# 确认status=ready后再从该tag创建子机
grandchildren = c.spawn_sandboxes(branch["tag"], n=5)

wait=False用于缩短调用等待时间,并不代表后台快照已经完成。程序需要轮询快照状态,避免从尚未就绪的分支继续启动。


🛠️ 安装与第一次运行

前置条件

项目要求
操作系统x86_64 Linux,推荐Ubuntu 22.04或更新版本
虚拟化CPU支持硬件虚拟化,主机可访问/dev/kvm
cgroupcgroup v2
Live BranchLinux 5.7以上,并启用userfaultfd或提供CAP_SYS_PTRACE
容器环境云主机需提供裸金属KVM或明确支持嵌套虚拟化

普通共享VPS和多数受限容器无法直接访问KVM。执行安装前先确认云平台允许嵌套虚拟化。

一键路径

项目README当前给出的预构建版本为v0.5.3:

curl -sSL https://github.com/deeplethe/forkd/releases/download/v0.5.3/forkd-v0.5.3-x86_64-linux.tar.gz \
  | sudo tar -xz -C /usr/local/bin/

sudo -E forkd quickstart

quickstart会检查KVM、Firecracker、Guest Kernel、网络和快照目录。它会说明准备执行的配置;默认需要明确同意,传入--yes才会自动确认。

安装脚本和二进制具有主机级权限。正式服务器应从forkd Releases 确认版本与发布资产,再在隔离测试机执行。

手动检查

forkd doctor

forkd doctor覆盖KVM、硬件虚拟化、cgroup v2、IP Forward、Tap、Network Namespace、Firecracker版本、磁盘、Guest Kernel、Controller连接以及Live Fork所需能力。

随后可拉取官方示例快照并启动三个子机:

forkd pull deeplethe/langgraph-react
sudo -E forkd fork --tag langgraph -n 3 --per-child-netns

也可以从Docker镜像构建自己的预热快照:

sudo -E forkd from-image python:3.12-slim \
    --tag py-numpy \
    --extra python3-numpy

sudo -E forkd fork --tag py-numpy -n 5 --per-child-netns

from-image第一次运行需要拉取镜像、制作ext4、启动预热并保存快照。后续启动会复用已经生成的内容。


🧪 CLI、SDK与MCP用法

创建100个隔离子机

sudo bash scripts/netns-setup.sh 100

sudo forkd snapshot --tag pyagent \
    --kernel ./vmlinux-6.1.141 \
    --rootfs ./python-rootfs.ext4 \
    --tap forkd-tap0

sudo -E forkd fork \
    --tag pyagent \
    -n 100 \
    --per-child-netns \
    --memory-limit-mib 256

sudo forkd eval \
    --child forkd-child-42 \
    -- "numpy.zeros(100).sum()"

Python SDK

pip install forkd
from forkd import Sandbox

with Sandbox() as sb:
    result = sb.commands.run("uname -a")
    print(result.stdout)
    print(sb.eval("numpy.zeros(5).tolist()"))

eval()复用Guest内已预热的PID 1解释器;commands.run()会启动新进程。官方示例中,两者分别用于低延迟表达式和普通Shell命令。

TypeScript SDK

npm install @deeplethe/forkd
import { Controller } from '@deeplethe/forkd';

const ctrl = new Controller();
const [parent] = await ctrl.spawnSandboxes({
  snapshotTag: 'pyagent',
  n: 1,
  perChildNetns: true,
  liveFork: true,
});

const branch = await ctrl.branchSandbox(parent.id, {
  mode: 'live',
  wait: false,
});

SDK默认读取FORKD_URLFORKD_TOKEN。Token应通过Secret或权限受控的环境文件注入,避免写入仓库。

MCP Server

pip install forkd-mcp

Claude Desktop配置示例:

{
  "mcpServers": {
    "forkd": {
      "command": "forkd-mcp"
    }
  }
}

MCP Server向Agent暴露创建沙箱、执行命令和运行代码等工具。生产环境应限制可用快照、网络出口、命令权限和最大子机数量。


📊 基准怎么看

forkd创建100个microVM的官方基准图

项目在Ubuntu 24.04、Linux 6.14、20 vCPU、30 GiB内存和KVM主机上测试100个沙箱。测试任务是在每个子机中使用已经预热的NumPy运行简单表达式。

指标forkd官方测试值
100个子机总启动时间101ms
每个子机新增内存0.12 MiB
单沙箱复用预热解释器1ms
新进程重新导入NumPy96ms

这些数字描述的是“从预热快照分叉”,与容器或虚拟机冷启动属于不同工作点。主机CPU、磁盘、父快照大小、Network Namespace创建、脏页比例和子任务负载都会改变结果。

本机测量可使用:

forkd bench --tag py-numpy --n 5

v0.5加入Diff Snapshot Chain。多层快照可以减少重复保存完整基础镜像,但链越深,校验和组装成本越高。README给出的512 MiB测试中,深度3的启动p50达到1,668ms,而压平后的等价快照约746ms。长期运行应监控链深,并按需要执行:

forkd snapshot-info py-numpy
forkd snapshot-compact --from py-pandas --to py-pandas-flat

🔐 生产部署与已知限制

Controller Daemon适合持续运行的环境:

sudo install -m 0644 \
  packaging/systemd/forkd-controller.service \
  /etc/systemd/system/

sudo mkdir -p /etc/forkd
sudo bash -c 'head -c 32 /dev/urandom | base64 > /etc/forkd/token'
sudo chmod 600 /etc/forkd/token
sudo systemctl enable --now forkd-controller

REST调用示例:

TOKEN=$(sudo cat /etc/forkd/token)

curl -H "Authorization: Bearer ${TOKEN}" \
  -X POST http://127.0.0.1:8889/v1/sandboxes \
  -H 'Content-Type: application/json' \
  -d '{
    "snapshot_tag": "pyagent",
    "n": 5,
    "per_child_netns": true,
    "memory_limit_mib": 256
  }'

不要把Controller的8889端口直接暴露到公网。需要远程访问时,应放在受控内网或反向代理之后,并配置TLS、Bearer Token、来源限制和请求速率限制。

当前生产缺口包括:

  • 一个Daemon只管理一台主机,尚无内置多节点调度;
  • 子Network Namespace默认共享MASQUERADE出口,默认拒绝式Egress需要自行配置iptables;
  • 已有memory.max,CPU、IO和进程数量配额仍需额外处理;
  • 项目尚未完成第三方安全审计;
  • 快照不能跨Firecracker版本或不同CPU微架构随意迁移;
  • Live Branch依赖项目维护的Firecracker分支;
  • 0.1.0至0.1.3存在路径穿越和占位Token相关安全问题,旧版本必须升级。

⚠️ microVM隔离能提高边界强度,不能自动解决凭据泄露、恶意出网、资源耗尽和内核漏洞。运行不受信代码时,需要同时限制Secret、网络、CPU、内存、进程数、磁盘和执行时间。


❓ FAQ

forkd能替代Docker吗?

forkd面向大量短生命周期、从预热状态分叉的隔离任务。长期服务、标准OCI交付和跨平台开发仍适合Docker。两者可以组合使用:先从Docker镜像制作父快照,再由forkd分叉子机。

云服务器都能安装吗?

主机必须提供/dev/kvm。裸金属服务器通常更直接;虚拟机实例需要平台明确支持嵌套虚拟化。Kubernetes节点同样需要KVM和cgroup v2。

为什么需要Network Namespace?

它为每个子机创建独立网络空间,降低不同Agent之间的网络状态冲突。生产环境还要为每个Namespace增加出口白名单和流量审计。

适合哪些Agent任务?

代码解释器、SWE-bench式并行评测、浏览器自动化、一次任务一个数据库、CI运行不受信代码,以及在高风险步骤前建立分支都符合它的设计目标。

还可以参考哪些方案?

理解Agent与硬件的标准化连接,可阅读MHS控制物理设备 ;多模型路由和普通API工作流可参考本地AI网关搭建 。需要为Agent接入独立模型API时,可查看APIMart API入口 ,模型可用性和费用以实时页面为准。