Skip to content

从一次 run_code 看完整数据链路

当你调用 sdk.sandbox.run_code(code="print('hello')") 时,请求并没有经过 CubeMaster 的调度器,而是直接走了数据面:SDK → CubeProxy → 沙箱 49999 端口 → envd 执行器。

这篇文章把这条数据面链路拆开,告诉你每一步该去读哪个源码文件。


1. 总览:run_code 请求经过了哪些组件


2. 第一步:SDK 构造请求

你要读的文件

文件看什么
sdk/go/sandbox.goRunCode() — 构造 HTTP POST
sdk/go/envd.goenvd 客户端封装
sdk/go/sandbox.goGetHost(port) — 生成虚拟主机名

关键代码路径

go
// sdk/go/sandbox.go
func (s *Sandbox) RunCode(code, language string, envVars map[string]string) {
    host := s.GetHost(JupyterPort) // → "49999-sb-123.cube.app"
    url := fmt.Sprintf("https://%s/execute", host)
    body := map[string]string{
        "code":     code,
        "language": language,
        "env_vars": envVars,
    }
    resp := http.Post(url, body)
    s.parseStream(resp) // 解析流式事件
}

关键设计

  • GetHost(port) 生成 <port>-<sandboxID>.<domain> 格式的虚拟主机名
  • 这个格式就是 CubeProxy 的路由键
  • SDK 不关心节点 IP,只关心 sandboxID 和 domain

3. 第二步:CubeProxy 路由

你要读的文件

文件看什么
CubeProxy/lua/rewrite_phase.luaHost 解析、sandboxID 提取
CubeProxy/lua/sandbox_backend.lua路由元数据查询、upstream 选择
CubeProxy/lua/balancer_phase.lua负载均衡

关键流程

关键设计

  • CubeProxy 不做业务逻辑,只做路由
  • 路由元数据存在 Redis 中,由 CubeMaster 在创建成功后写入
  • 一个 sandboxID 可能有多个端口映射(49999 for envd、49983 for process API、自定义端口等)

4. 第三步:CubeVS 网络转发

你要读的文件

文件看什么
CubeNet/src/mvmtap.bpf.cTAP 设备入口、DNAT 逻辑
CubeNet/src/natenic.bpf.cNAT session 管理
CubeNet/src/session.hsession map 数据结构

关键流程

  1. 流量到达宿主机网卡
  2. CubeVS eBPF 程序根据目的端口查找 session map
  3. 执行 DNAT:将宿主端口映射回沙箱 TAP 设备的端口
  4. 包通过 TAP 设备进入 guest 网络栈

5. 第四步:envd 执行器

你要读的文件

文件看什么
agent/src/sandbox.rsguest 内沙箱管理
agent/src/rpc.rsvsock RPC 服务

关键动作

  1. envd 监听沙箱内 49999 端口
  2. 收到 POST /execute 后:
    • 解析 code + language + env_vars
    • 启动对应语言的解释器
    • 执行代码
  3. 通过流式 HTTP 响应返回 stdout / result / error 事件

6. 与 commands.run 的对比

维度run_codecommands.run
端口4999949999
路径POST /executePOST /process.Process/Start
语义代码解释器进程执行器
返回结构化执行事件流connect 风格 process 事件流
用途执行 Python/JS 等代码执行 shell 命令

7. 完整链路速查表

阶段组件关键文件关键函数/配置
构造请求SDKsdk/go/sandbox.goRunCode(), GetHost()
解析 HostCubeProxylua/rewrite_phase.luaHost 解析逻辑
查路由表CubeProxylua/sandbox_backend.luaRedis 查询
网络转发CubeVSCubeNet/src/mvmtap.bpf.cDNAT + TAP
执行代码envdagent 内部/execute handler
流式返回SDKsdk/go/sandbox.goparseStream()

延伸阅读