跳到主要内容

E2B Infra — 这是什么 · 全景图 · 阅读地图

30 秒导读: E2B 是给 AI 代码解释器 / agent 用的云沙箱——让不可信的、模型现写现跑的代码,在一个强隔离的环境里安全执行。本仓库(e2b-dev/infra)是它的后端基础设施:用 Firecracker microVM 做隔离,能秒级创建、暂停、恢复沙箱,并把流量路由进具体那台 VM。本页只做导航与直觉:讲清"这是什么、大盘怎么转、该读哪一章",不进底层细节。


1. 这是什么(零基础也能懂)

一句话定义: E2B 给每个 AI agent 会话发一台云上的隔离小电脑,agent 让模型写的代码就在里面跑,跑坏了也伤不到别人。本仓库是造并管理这些小电脑的基础设施

它解决谁的什么问题。 假设你在做一个 AI agent:模型会现场生成一段 Python,你得真的把它跑起来看结果。可是这段代码来自大模型、不可信——它可能删你的文件、偷你的密钥、或吃光机器资源。你需要一个用完即弃、强隔离、还要开得快的执行环境。E2B 就是把"造这种环境"这件事做成基础设施。

核心难点是:又要强隔离,又要快。 传统容器开得快但隔离弱(共享内核);传统虚拟机隔离强但开得慢(动辄几十秒)。E2B 选了 Firecracker microVM——AWS 给 Lambda 造的轻量虚拟机,有真正的内核级隔离,却能在几百毫秒到几秒内启动。

一句话直觉 / 类比。 把每个 agent 会话想成一台随手可开关机、状态还能冻结再解冻的独立小电脑:

  • 开机 = 创建沙箱(从模板启动一台 microVM)。
  • 冻结(暂停) = 把这台电脑的整个内存和磁盘状态拍成快照存起来,VM 停掉、不再占资源。
  • 解冻(恢复) = 从快照秒级复活,内存里的变量、跑到一半的进程,原样接着来。
  • 关机(销毁) = 用完即弃,连痕迹一起清掉。

E2B 最难、也最巧的部分,全在"冻结 / 解冻要快"上——这正是 03、04 两章要讲的精华。

它能做什么(能力清单):

  • 从预构建的模板秒级拉起一台隔离沙箱。
  • 暂停 / 恢复沙箱:冻结完整内存态,之后原样复活。
  • 给每台沙箱独立网络栈,并对出站流量做管控(允许 / 拒绝、按域名改写)。
  • 把外部 HTTP/gRPC 流量路由到正确的那台沙箱、正确的端口。
  • 在 VM 内跑一个守护进程(envd),对外提供执行命令、读写文件的 API。

它不是什么。 本仓库不是 SDK、也不是 CLI——面向用户的 SDK/CLI 在另一个仓库 e2b-dev/e2b(见 README.md:6)。本仓库是跑在云上的后端,用 Terraform + Nomad 部署,官方支持 GCP、AWS(Beta)(README.md:18-22)。


2. 顶层全景(它大概怎么转)

E2B 的架构分两条线,这是理解整个系统的钥匙:

  • 控制面(control plane): 谁能开沙箱、开哪个模板、放到哪台机器——决策在这里。走 REST/gRPC,和 Postgres/Redis/ClickHouse 打交道。
  • 数据面(data plane): 真正把 microVM 跑起来、承载流量——干活在这里。逐台节点(node)上跑 orchestrator,直接操作 Firecracker。

怎么读这张图

从左到右:客户端 → 边缘 → 控制面 → (gRPC 下发) → 数据面 → VM 内。上半区是控制面(决策 + 存储),下半区是数据面(执行)。

┌──────────────── 控制面(决策) ────────────────┐
│ │
客户端 ┌─────────┐ ┌──────────────┐ ⟷ Postgres(主数据)
(SDK/HTTP) ───▶ │ client- │ ───▶ │ API (REST) │ ⟷ Redis(状态/缓存)
│ proxy │ │ Gin 框架 │ ⟷ ClickHouse(分析)
│ 边缘路由 │ └──────┬───────┘
└────┬────┘ │ ① 选节点 + gRPC 下发
│ ▼
── 运行期流量 ───────┼────────── ┌──────────────────┐
直连到具体沙箱 │ │ orchestrator │ ← 每个数据面节点一个
│ │ (逐节点数据面) │
│ └────────┬─────────┘
│ │ ② 启动/恢复
│ ▼
│ ┌──────────────────┐
└──────────▶ │ Firecracker VM │
③ 路由进 │ ┌──────────┐ │
具体 VM │ │ envd │ │ ← VM 内守护进程
│ │ (49983) │ │ 跑命令 / 读写文件
│ └──────────┘ │
└──────────────────┘

部件一句话职责

部件干什么在哪个 package
client-proxy边缘路由层:把外部请求按沙箱 ID 找到承载它的节点并转发;通过 Redis 目录(catalog)做服务发现packages/client-proxy
APIREST 控制面(Gin):鉴权、解析请求、选模板、挑节点并 gRPC 下发创建请求packages/api
orchestrator逐节点数据面:接 gRPC,真正操作 Firecracker 启动/暂停/恢复/销毁 microVMpackages/orchestrator
envd跑在每台 VM 内部的守护进程(Connect RPC):对外暴露"执行进程、读写文件系统"的 APIpackages/envd
shared跨服务公共件:gRPC/proto 定义、遥测、日志、DB、存储客户端(GCS/S3)、特性开关packages/shared
dbPostgreSQL 层:goose 迁移 + sqlc 生成的类型安全查询packages/db
Postgres / Redis / ClickHouse分别管:主数据 / 状态与缓存 / 分析事件(外部依赖)

注:orchestrator 的源码在 packages/orchestrator/pkg/…(不是仓库自带 CLAUDE.md 里写的 internal/…;那份文档略有漂移,以真实目录为准)。

主线走一遍:一次"创建沙箱"的旅程(高层)

跟着一个 POST /sandboxes 请求走一遍,只看经过谁、干了啥,代码细节留给 01 章:

  1. 进边缘。 请求先到 client-proxy,转给 API
  2. 控制面决策。 APIPostSandboxes 鉴权、解析 body、把模板别名解析成具体 build(packages/api/internal/handlers/sandbox_create.go:59 PostSandboxes),然后交给 startSandbox
  3. 挑一台节点。 Orchestrator.CreateSandbox 组装 gRPC 请求 SandboxCreateRequest,用放置算法 placement.PlaceSandbox 从集群里选一台合适的数据面节点(packages/api/internal/orchestrator/create_instance.go:135 CreateSandbox:321 PlaceSandbox)。
  4. gRPC 下发到数据面。 选中的 orchestrator 节点收到 Server.Create,取模板快照数据(packages/orchestrator/pkg/server/sandboxes.go:75 Create)。
  5. microVM 跑起来。 orchestratorFactory.CreateSandbox(全新启动)或 ResumeSandbox(从快照恢复),启动 Firecracker 进程,VM 内 envd 就绪(packages/orchestrator/pkg/sandbox/sandbox.go:390 CreateSandbox:694 ResumeSandbox)。
  6. 能收发流量了。 返回沙箱信息;之后运行期流量再经 client-proxy 直接路由进这台 VM 的 envd,agent 就能在里面跑命令、读写文件了。

一句话总结这条线:API 做"选谁、放哪"的决策,orchestrator 做"把 VM 跑起来"的执行,client-proxy 负责让请求找到那台 VM。


3. 阅读地图(各章讲什么、建议顺序)

建议顺序读;想直取精华可跳到 03、04。

顺序章节一句话讲什么
101-architecture把第 2 节的全景放大:控制面 vs 数据面的分工,一次创建沙箱端到端每一步的真实代码
202-sandbox-lifecycle一台 microVM 的一生:创建 / 暂停 / 恢复 / 销毁,以及 Firecracker 进程怎么被编排
303-fast-resume-uffd秒级恢复的核心:内存快照 + userfaultfd 惰性缺页——不预加载全部内存,用到哪页才拉哪页
404-cow-block-storage省空间的核心:分层去重的写时复制块存储,rootfs 与内存 diff 只存"改动的块"
505-network-isolation每台沙箱的独立网络栈、IP 槽位分配,与出站流量的允许/拒绝/改写
606-edge-and-envd请求如何抵达具体沙箱:client-proxy 边缘路由 + VM 内 envd 守护进程

给 AI agent 的用法: 先读本页的 essence 与全景判断相关性;要"创建流程"看 01,要"暂停/恢复语义"看 02,要"为什么恢复这么快"看 03,要"存储怎么省"看 04,要"网络隔离"看 05,要"流量怎么进来"看 06。


4. 巧妙之处速览(精华在哪一章)

这一节把 E2B 最值得带走的三个设计各用一句话点破,细节在对应章:

  • ① 内存快照 + UFFD 惰性缺页 → 秒级恢复。 恢复一台 VM 不预先把几个 GB 内存全读回来,而是先"空着起",Firecracker 通过 userfaultfd 报告缺页,orchestrator 才按需从快照里拉那一页(packages/orchestrator/pkg/sandbox/uffd/uffd.go:38 Uffd:72 Start)。→ 详见 03

  • ② 分层去重的写时复制块存储 → 省空间又快。 沙箱磁盘和内存都建在一个只读基础层之上;读时先查本地缓存、没有再落到只读设备,写只落到缓存层(即"diff"),相同块跨沙箱去重(packages/orchestrator/pkg/sandbox/block/overlay.go:14 OverlayReadAt/WriteAt)。→ 详见 04

  • ③ 按需恢复被暂停的沙箱 → 冷的不占资源、来流量才复活。 沙箱可被暂停成快照、完全不占节点;当有请求打到一个已暂停的沙箱,边缘层触发按需恢复再转发(packages/client-proxy/internal/proxy/paused_resumer.goproxy.go:97 handlePausedSandbox)。→ 详见 0206


5. 顶层代码地图(导航索引)

想直接跳进源码时,用符号名 grep 比行号更抗漂移(上游更新后行号会变、符号名通常还在)。

主题文件符号
控制面入口:接收创建沙箱请求packages/api/internal/handlers/sandbox_create.goPostSandboxes
控制面:组装 gRPC 请求 + 选节点下发packages/api/internal/orchestrator/create_instance.goCreateSandboxPlaceSandbox
数据面 gRPC 服务:创建/恢复沙箱packages/orchestrator/pkg/server/sandboxes.goServer.Create
数据面:microVM 工厂(启动/恢复/重启)packages/orchestrator/pkg/sandbox/sandbox.goFactoryCreateSandboxResumeSandbox
Firecracker 进程封装packages/orchestrator/pkg/sandbox/fc/process.goProcessNewProcess
秒级恢复:惰性缺页packages/orchestrator/pkg/sandbox/uffd/uffd.goUffdUffd.Start
写时复制块存储packages/orchestrator/pkg/sandbox/block/overlay.goOverlayReadAtWriteAt
每台沙箱的网络栈packages/orchestrator/pkg/sandbox/network/network.gopool.goslot.go
边缘路由 + 按需恢复packages/client-proxy/internal/proxy/proxy.goNewClientProxyhandlePausedSandbox
VM 内守护进程入口packages/envd/main.gomain(端口 49983)
服务通信全景(参考)packages/orchestrator/orchestrator.protoSandboxCreateRequest

想继续: 直接进 01-architecture 看这条创建之旅的真实代码走读;或跳到 03-fast-resume-uffd 直取"为什么恢复能做到秒级"的核心机制。