SandboxSched:基于 Kubernetes 的 AI Agent 沙箱调度引擎项目

flux-sandbox代码仓

分支1Tags0
文件最后提交记录最后更新时间
6 天前
7 天前
6 天前
6 天前
11 天前
6 天前
1 个月前
6 天前
9 天前
8 天前
12 天前
9 天前
9 天前
1 个月前
16 天前
16 天前
1 个月前
2 个月前
11 天前
13 天前

FluxSandbox

English | 中文

高性能 Kubernetes 沙箱调度引擎,作为 OpenSandbox 的 runtime 后端,面向 AI Agent 工作负载提供低时延、高吞吐的沙箱生命周期管理能力。

FluxSandbox 不直接面向用户暴露 API,而是通过 OpenSandbox Server 的 flux runtime 接入:用户使用 OpenSandbox SDK 创建沙箱,由 Server 通过 gRPC 转发给 FluxSandbox controller 完成调度与生命周期管理。

组件

组件 职责 部署形态
flux-sandbox-controller 分片管理、调度器路由、gRPC API 网关 Deployment(单副本)
flux-sandbox-scheduler Agent Pod 派发、沙箱调度、CR 编排 StatefulSet(多副本分片)
flux-sandbox-agent 数据面:通过运行时 API 管理沙箱实例 由 scheduler 控制
sandbox-watcher 节点级孤儿沙箱清理 DaemonSet

项目结构

cmd/                          # 各二进制入口
internal/
  flux-sandbox-controller/    # 控制面:分片、路由、gRPC 服务
  flux-sandbox-scheduler/     # 调度引擎、内存注册表、CR 编排
  agent/                      # 数据面:运行时管理(containerd、E2B)
  sandbox-watcher/            # 孤儿沙箱清理
api/
  proto/v1/                   # gRPC 服务定义(生成代码)
  v1alpha1/                   # CRD 类型定义
charts/flux-sandbox/          # Helm chart(推荐部署方式)
config/                       # 原始 Kubernetes 部署清单
build/                        # Dockerfile
docs/design/                  # 系统设计文档

快速开始

FluxSandbox 以 OpenSandbox 为入口使用,整体链路为:OpenSandbox SDK → OpenSandbox Server(flux runtime)→ FluxSandbox Controller。

前置条件

  • Kubernetes 集群(1.28+),可通过 kubectl 访问
  • Worker 节点已安装 containerd
  • Helm 3.14+(推荐部署方式)
  • Go 1.25+(仅从源码构建时)
  • Python 3.10+(OpenSandbox SDK 要求)
  • Docker(用于构建镜像,仅从源码构建时需要)

1. 构建镜像(使用已发布镜像可跳过)

FluxSandbox 的四个组件均以容器镜像部署。从源码构建时,make build 编译全部二进制到 bin/ 目录,然后构建并推送 Docker 镜像:

# 编译二进制并构建镜像
make docker-build

# 推送到集群可访问的 registry
make docker-push REGISTRY=registry.example.com TAG=v0.1.0

也可以手动构建单个镜像:

make build
docker build -f build/Dockerfile.flux-sandbox-controller -t flux-sandbox/controller:latest .
docker build -f build/Dockerfile.flux-sandbox-scheduler -t flux-sandbox/scheduler:latest .
docker build -f build/Dockerfile.flux-sandbox-agent -t flux-sandbox/agent:latest .
docker build -f build/Dockerfile.sandbox-watcher -t flux-sandbox/watcher:latest .

构建完成后将镜像推送到集群可访问的 registry。

2. 部署 FluxSandbox

方式一:Helm(推荐)

各组件默认 repository 为 flux-sandbox/{controller,scheduler,agent,watcher},与 openFuyao CI 发布路径对齐。使用官方镜像时,只需设置 global.imageRegistry 前缀:

helm install flux-sandbox ./charts/flux-sandbox \
  --namespace flux-system \
  --create-namespace \
  --set global.imageRegistry=cr.openfuyao.cn/openfuyao

CRD 随 chart 自动安装;镜像版本、E2B 配置、副本数、调度约束等均可通过 values 定制,详见 chart 说明。

方式二:原始清单

# 创建命名空间
kubectl create namespace flux-system

# 安装 CRD
make crd-apply

# 部署各组件
kubectl apply -f config/controller/
kubectl apply -f config/scheduler/
kubectl apply -f config/sandbox-watcher/

验证就绪

kubectl wait --for=condition=Ready pod -n flux-system -l app=flux-sandbox-controller --timeout=60s
kubectl wait --for=condition=Ready pod -n flux-system -l app=flux-sandbox-scheduler --timeout=60s

3. 创建 SandboxGroup

SandboxGroup 定义一组沙箱的资源规格和容量。Controller 会将其拆分为 SubSandboxGroup(分片),分配给各调度器实例,由调度器拉起 Agent Pod。沙箱组状态变为 Ready 后即可创建沙箱。

注意:在标准 k8s 环境中,需显式设置 RUNTIME_TYPE=containerd 和 execdImage。Controller 默认 runtime 类型为 e2b,不会挂载 containerd socket,也不会注入 execd init container,agent 将无法创建容器。

kubectl apply -f - <<EOF
apiVersion: sandbox.flux.io/v1alpha1
kind: SandboxGroup
metadata:
  name: sg-1u1g
  namespace: flux-system
spec:
  capacity:
    agentPodMin: 1
    agentPodMax: 3
    sandboxBufferMin: 1
    maxSandboxesPerPod: 5
  sandboxResources:
    requests: { cpu: "1", memory: "2Gi" }
    limits:   { cpu: "1", memory: "2Gi" }
  agentEnv:
    RUNTIME_TYPE: "containerd"
  execdImage: "opensandbox/execd:v1.0.20"
EOF

等待 SandboxGroup 就绪:

kubectl wait --for=condition=Ready sandboxgroup sg-1u1g -n flux-system --timeout=120s

sandboxResources 的 requests/limits 决定每个沙箱占用的资源规格,且为唯一权威来源——调用方(OpenSandbox SDK)传入的资源参数会被忽略。调度机制详见设计文档。

4. 部署 OpenSandbox Server

克隆 openFuyao/opensandbox 仓库,构建并部署 Server:

git clone https://gitcode.com/openFuyao/opensandbox.git
cd opensandbox/server

# 构建 OpenSandbox Server 镜像
docker build -f Dockerfile.flux -t opensandbox-server:flux .

构建完成后将镜像推送到集群可访问的 registry。

创建配置文件 config.toml:

[server]
host = "0.0.0.0"
port = 8080
api_key = "your-api-key"

[runtime]
type = "flux"
execd_image = "opensandbox/execd:v1.0.20"

[flux_sandbox]
endpoint = "flux-sandbox-controller.flux-system.svc:9091"
timeout_seconds = 15
use_tls = false

[ingress]
mode = "direct"

部署到集群:

kubectl create configmap opensandbox-server-config -n flux-system --from-file=config.toml
kubectl apply -f - <<EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: opensandbox-server
  namespace: flux-system
spec:
  replicas: 1
  selector:
    matchLabels:
      app: opensandbox-server
  template:
    metadata:
      labels:
        app: opensandbox-server
    spec:
      containers:
      - name: server
        image: opensandbox-server:flux
        imagePullPolicy: IfNotPresent
        args: ["--config", "/etc/opensandbox/config.toml"]
        ports:
        - name: http
          containerPort: 8080
        readinessProbe:
          httpGet:
            path: /health
            port: http
          initialDelaySeconds: 5
          periodSeconds: 10
        volumeMounts:
        - name: config
          mountPath: /etc/opensandbox
      volumes:
      - name: config
        configMap:
          name: opensandbox-server-config
---
apiVersion: v1
kind: Service
metadata:
  name: opensandbox-server
  namespace: flux-system
spec:
  selector:
    app: opensandbox-server
  ports:
  - name: http
    port: 8080
    targetPort: http
EOF

kubectl wait --for=condition=Ready pod -n flux-system -l app=opensandbox-server --timeout=60s

5. 准备沙箱镜像

Agent 创建沙箱时需要从集群节点拉取沙箱镜像和 execd 镜像。确保以下镜像在所有 Worker 节点上可拉取:

# 沙箱运行时镜像(SDK 示例使用 python:3.11)
docker pull python:3.11

# execd 镜像(SandboxGroup 中 execdImage 指定)
docker pull opensandbox/execd:v1.0.20

确保镜像推送到集群可访问的 registry,或在所有 Worker 节点上预拉取。

6. 通过 SDK 创建沙箱

安装 OpenSandbox Python SDK:

pip install opensandbox

创建沙箱,通过 extensions.sandboxGroup 字段指定路由到哪个 SandboxGroup:

import asyncio
from datetime import timedelta
from opensandbox import Sandbox
from opensandbox.config import ConnectionConfig

async def main():
    config = ConnectionConfig(
        domain="<server-address>:8080",   # OpenSandbox Server 地址
        api_key="your-api-key",
    )

    # extensions.sandboxGroup 路由到名为 sg-1u1g 的 SandboxGroup
    async with await Sandbox.create(
        "python:3.11",
        connection_config=config,
        entrypoint=["python", "-m", "http.server"],
        env={"PYTHONUNBUFFERED": "1"},
        timeout=timedelta(minutes=30),
        extensions={"sandboxGroup": "sg-1u1g"},
    ) as sandbox:
        # 运行命令
        result = await sandbox.commands.run("echo 'Hello FluxSandbox!'")
        print(result.logs.stdout[0].text)

        # 获取端口 endpoint
        endpoint = await sandbox.get_endpoint(8080)
        print(f"endpoint: {endpoint.endpoint}")

asyncio.run(main())

SDK 完整 API 见 OpenSandbox Python SDK。

设计文档

完整系统设计见 docs/design/0001-FluxSandbox沙箱集群调度引擎系统设计.md。

Roadmap

贡献

欢迎在 gitcode 提交 Issue 或 Pull Request。