Go SDK 架构解析
Go SDK 是 CubeSandbox 的官方客户端库,提供沙箱创建、代码执行、文件操作等能力。这篇文章拆解它的对象模型、请求通道和 Connect 协议实现。
1. SDK 对象模型
2. 双 HTTP Client 设计
SDK 有两个独立的 HTTP client,分别走不同的通道:
controlHTTP
走标准 HTTP 代理,用于控制面请求:
POST /sandboxes— 创建沙箱DELETE /sandboxes/:id— 销毁沙箱POST /sandboxes/:id/pause— 暂停GET /sandboxes/:id— 查询信息
dataHTTP
绕过代理,直连 CubeProxy,用于数据面请求:
POST /process.Process/Start— 执行代码GET /files— 读取文件POST /files— 写入文件
go
// transport.go
func newDataHTTPClient(cfg Config) *http.Client {
transport := http.DefaultTransport.(*http.Transport).Clone()
transport.Proxy = nil // 绕过代理
if cfg.ProxyNodeIP != "" {
target := net.JoinHostPort(cfg.ProxyNodeIP, strconv.Itoa(cfg.ProxyPortHTTP))
transport.DialContext = func(ctx context.Context, network, _ string) (net.Conn, error) {
return dialer.DialContext(ctx, network, target)
}
}
return &http.Client{Transport: transport}
}3. Sandbox 生命周期
GetHost 的域名格式
go
func (s *Sandbox) GetHost(port int) string {
return fmt.Sprintf("%d-%s.%s", port, s.SandboxID, s.Domain)
// 例如: 49999-abc123.cube.app
}这个域名会被 DNS 解析到运行该沙箱的节点 IP,CubeProxy 根据 Host header 路由到正确的沙箱。
4. Commands.Run:命令执行
go
// commands.go
func (c *Commands) Run(ctx context.Context, cmd string, opts CommandOptions) (*CommandResult, error) {
process, err := c.starter.startProcess(ctx, processStartRequest{
Process: processConfig{
Cmd: "/bin/bash",
Args: []string{"-l", "-c", cmd},
Envs: envs,
Cwd: opts.Cwd,
},
Stdin: &stdin,
}, opts)
return &CommandResult{
Stdout: process.Stdout,
Stderr: process.Stderr,
ExitCode: process.ExitCode,
}, nil
}所有命令都通过 /bin/bash -l -c 包装,确保:
- 使用 login shell 加载环境变量
- 支持管道、重定向等 shell 特性
5. Connect 协议:流式命令执行
envd.go 中的 startProcess 使用 Connect 协议与 envd 通信:
Envelope 格式
[1 byte flags][4 bytes length][payload JSON]flags & 0x01:压缩标志flags & 0x02:end stream 标志
事件类型
| 事件 | 字段 | 说明 |
|---|---|---|
start | pid | 进程启动 |
data | stdout, stderr, pty | 输出数据 |
end | exitCode, status | 进程结束 |
keepalive | - | 心跳保活 |
6. 文件操作
文件操作通过 envd 的 HTTP API 实现:
go
// envd.go
func (s *Sandbox) readFile(ctx context.Context, path string) (string, error) {
query := url.Values{"path": []string{path}}
req, _ := s.newEnvdRequest(ctx, http.MethodGet, "/files", query, nil)
resp, _ := s.client.dataHTTP.Do(req)
raw, _ := io.ReadAll(resp.Body)
return string(raw), nil
}请求目标:http://{port}-{sandboxID}.{domain}/files?path=/path/to/file
7. 配置加载
go
// config.go
type Config struct {
ApiURL string // CubeAPI 地址
ApiKey string // API Key
SandboxDomain string // 沙箱域名
Timeout time.Duration
ProxyNodeIP string // 直连节点 IP
ProxyPortHTTP int // CubeProxy HTTP 端口
ProxyScheme string // http / https
}配置优先级:环境变量 → 显式传入 → 默认值
| 环境变量 | 说明 |
|---|---|
CUBESANDBOX_API_URL | CubeAPI 地址 |
CUBESANDBOX_API_KEY | API Key |
CUBESANDBOX_DOMAIN | 沙箱域名 |
CUBESANDBOX_TIMEOUT | 超时时间 |
延伸阅读
- Python SDK 架构解析 — Python 版本对比
- 从 examples 看 SDK 实战用法 — 官方示例拆解
- 从一次 run_code 看完整数据链路 — 数据面全链路