部署 Substrate Sandbox

本文主要描述在已经部署好 Agent Substrate 的 Kubernetes 集群上执行的完整示例。

先创建一个简单的 HTTP Sandbox Actor,验证完整链路:

Atespace → WorkerPool → ActorTemplate → Actor → Resume → 访问 → Suspend

这里有一个容易忽略的地方:Atespace、ActorTemplate、Actor 是通过 Substrate API 管理的逻辑资源,不是 Kubernetes CRD;WorkerPool 和 SandboxConfig 才是 Kubernetes 资源。 因此不能全部使用 kubectl apply 创建。

0. 检查 Substrate 是否部署正常

先检查核心组件:

kubectl get pods -n ate-system
kubectl get crd | grep -E 'workerpools|sandboxconfigs'

检查 Substrate CLI:

kubectl ate get atespaces
kubectl ate get workers

如果本地还没有 kubectl ate:

go install github.com/agent-substrate/substrate/cmd/kubectl-ate@latest

注意:CLI 版本尽量与集群部署的 Substrate 版本保持一致。

1. 创建 Atespace【租户】

先创建 Kubernetes Namespace:

kubectl create namespace demo-space

现在创建 Substrate 逻辑隔离空间:

kubectl ate create atespace demo-space

查看:

kubectl ate get atespace demo-space

#示例
ATESPACE       NAME            TEMPLATE                  STATE                 WORKER POD                    WORKER IPS   VERSION   AGE
demo-space   ate-demo-actor   ate-demo/demo-template   ACTOR_STATE_RUNNING   ate-demo/demo-68c995676b-f7tmn   1.1.1.1     3         39h

注意这里有两个同名对象:

对象 所属系统 作用
Namespace demo-space Kubernetes WorkerPool 等 K8s 资源的命名空间
Atespace demo-space Substrate Actor 的逻辑隔离空间

它们不是同一个对象,只是为了方便示例使用了相同名称。注意执行ate的参数指定atespace 是用参数-a而不是-n。

2. 创建 WorkerPool【资源池】

这是创建 Actor 之前最重要的准备工作。

WorkerPool 是 Kubernetes CRD,负责提供可以承载 Actor 的 Worker Pod。可以理解为资源池。

创建 workerpool.yaml:

apiVersion: ate.dev/v1
kind: WorkerPool
metadata:
  name: demo-pool
  namespace: demo-space
  labels:
    workload: demo-agent
spec:
  replicas: 2

  # 必须使用与当前 Substrate 部署版本匹配的 Worker 镜像
  workerImage: <你的 ateworker-gvisor 镜像>

  sandboxClasses:
    - name: gvisor

  template:
    resources:
      limits:
        cpu: "2"
        memory: 2Gi
      requests:
        cpu: 500m
        memory: 2Gi

这里的 workerImage 不能随意填写。应该使用你当前 Substrate 安装时使用的 ateworker-gvisor 镜像,确保版本一致。

应用:

kubectl apply -f workerpool.yaml

检查:

kubectl get workerpool -n demo-space

kubectl get pods -n demo-space -w

预期有两个 Worker Pod 逐渐变成 Running。

WorkerPool 有几个重要概念:

配置 含义
replicas 预热 Worker 的数量
workerImage Worker 内部管理程序的镜像
sandboxClasses 支持的 Sandbox Runtime
template.resources Worker Pod 的资源配置
metadata.labels 供 ActorTemplate 的 workerSelector 选择

这里要特别注意:WorkerPool 的资源限制决定 Worker 可承载的容量;ActorTemplate 的资源限制决定单个 Actor 申请的资源。两者不是同一个概念。

3. 创建 ActorTemplate【Sandbox模板】

ActorTemplate 用来定义 Actor 运行什么程序、使用什么资源、使用什么 Sandbox Runtime,以及如何保存快照。

这一步需要准备一个容器镜像。

这里推荐直接使用一个自己构建的 HTTP 服务镜像,假设它具有以下行为:

  • 容器启动后监听 80 端口。

  • GET /readyz 返回 HTTP 200。

  • GET / 返回 Hello from Agent Substrate。

  • 工作目录为 /workspace。

假设你的镜像为:

registry.example.com/agent/demo-server:v1

创建 actor-template.yaml:

metadata:
  atespace: demo-space
  name: demo-template

# 选择前面创建的 WorkerPool
workerSelector:
  matchLabels:
    workload: demo-agent

containers:
  - name: agent
    image: registry.example.com/agent/demo-server:v1

    ports:
      - containerPort: 80

    wakeupProbe:
      httpGet:
        path: /readyz
        port: 80

    volumeMounts:
      - name: workspace
        mountPath: /workspace

resources:
  limits:
    cpuMillicores: 1000
    memoryBytes: 1073741824

snapshotConfig:
  storageLocation: gs://YOUR_BUCKET/agent-substrate/demo-space/

sandboxConfig:
  sandboxClass: SANDBOX_CLASS_GVISOR
  configName: gvisor-default

volumes:
  - name: workspace
    durableDir: {}

需要替换:

  • registry.example.com/agent/demo-server:v1:替换成你自己的镜像。

  • gs://YOUR_BUCKET/...:替换成当前 Substrate 对象存储插件支持的快照存储路径。这里沿用官方 GCS 示例;如果你部署的是其他存储后端,要使用对应支持的 URI。

  • gvisor-default:确保集群里存在对应的 SandboxConfig。

关于几个关键字段:

字段 作用
metadata.atespace ActorTemplate 所属的 Atespace
metadata.name 模板名称
workerSelector 选择具有对应标签的 WorkerPool
containers Actor 内部运行的容器
resources Actor 的资源申请
wakeupProbe 恢复后判断服务是否就绪
snapshotConfig 配置快照策略和存储位置
sandboxConfig 选择 Sandbox Runtime
durableDir Actor 独立的持久化数据目录

这里使用 durableDir,是为了让 /workspace 中的数据能够在 Actor Suspend/Resume 后保留。

关于快照: 当前示例重点是持久化工作目录。如果你还要求进程内存状态也恢复,需要根据当前 Substrate 版本配置相应的完整内存快照策略。

官方 Counter Demo 提供了完整的 gVisor、DurableDir 和内存快照配置,可以作为进一步参考 substrate/demos/counter。

创建模板:

kubectl ate create actor-template -f actor-template.yaml

查看:

kubectl ate get actor-templates -a demo-space

查看具体模板:

kubectl ate get actor-template demo-template \
  -a demo-space \
  -o yaml

# status 输出
status:
  goldenSnapshotStatus:
    goldenTag:
      atespace: ate-golden
      name: 0afe4a06-1432-424e-9e9c-ca60bb991a17
    takeGoldenSnapshotAt: "2026-10-31T11:34:52.168080494Z"

注意

ActorTemplate 创建后,Substrate 默认会创建 Golden Snapshot。Golden Snapshot 是模板的初始快照,不是你创建的每个 Actor 的独立快照。

需要等待模板初始化完成,再创建 Actor。检查模板状态以及 Golden Tag 是否已经生成。

4. 创建 Actor【sandbox逻辑实例】

现在终于可以创建 Actor 了。actor 是sandbox的逻辑实例,类似一个轻量型虚拟机,初始化是未开机状态。

kubectl ate create actor my-agent-001 \
  -a demo-space \
  --template demo-template

这里:

参数 含义
my-agent-001 Actor 名称
-a demo-space Actor 所属 Atespace
--template demo-template 使用哪个 ActorTemplate

查看 Actor:

kubectl ate get actors -a demo-space

查看具体 Actor:

kubectl ate get actor my-agent-001 \
  -a demo-space \
  -o yaml

这里要注意:

创建 Actor 并不等于立即启动 Actor。

CreateActor 主要是在 Substrate 控制面注册一个逻辑 Actor,真正分配 Worker 和恢复 Sandbox 需要执行 Resume,或者通过 Router 的请求触发自动恢复。

5. 启动 Sandbox【Resume Actor】

执行:

kubectl ate resume actor my-agent-001 \
  -a demo-space

这时候 Substrate 会完成大致如下流程:

kubectl ate resume actor

查看 Actor 状态:

kubectl ate get actor my-agent-001 \
  -a demo-space \
  -o yaml

查看 Worker:

kubectl ate get workers

# 输出
NAME                                   POOL                   STATE                 ACTORS   CPU   MEMORY    POD                                                              AGE
978b42b3-8bed-4b8c-a1b0-957c5b343f76   demo-pool        WORKER_STATE_ACTIVE   0/1      0/1   0/2Gi     ate-demo-pool/demo-pool-68c995676b-2nrvm             39h
009b30f6-e170-43a0-9b5d-7cfe236e9e9f   demo-pool        WORKER_STATE_ACTIVE   1/1      1/1   1Gi/2Gi   ate-demo-pool/demo-pool-68c995676b-f7tmn             39h
fef5851c-52b1-4805-b7b0-c86af3d53143   demo-pool        WORKER_STATE_ACTIVE   0/1      0/1   0/2Gi     ate-demo-pool/demo-pool-68c995676b-kcwnz             39h

你应该能看到一个 Worker 被分配给 demo-space/my-agent-001。

6. 通过 Router 访问 Actor

Substrate 不要求你直接访问 Worker Pod IP。

通过 atenet-router 访问:

先转发 Router:

kubectl port-forward \
  -n ate-system \
  svc/atenet-router 8000:80

另外打开一个终端:

curl -i \
  -H "ate-target-actor: demo-space/my-agent-001" \
  http://localhost:8000/

预期:

HTTP/1.1 200 OK

Hello from Agent Substrate

这里最重要的是:

ate-target-actor: demo-space/my-agent-001

它告诉 Router 应该把请求路由到哪个 Actor。

Router 不需要知道 Actor 当前在哪一个 Worker Pod 上。

7. 暂停sandbox【Suspend Actor】

这是 Substrate 最值得验证的功能。

先在 Actor 工作目录中创建一个文件:

# 这里假设你的 demo-server 提供了文件操作接口
# 或者通过你自己的 Actor 命令接口写入文件

然后暂停 Actor:

kubectl ate suspend actor my-agent-001 \
  -a demo-space

查看状态:

kubectl ate get actor my-agent-001 \
  -a demo-space


# 示例
ATESPACE       NAME             TEMPLATE               STATE                   WORKER POD   WORKER IPS   VERSION   AGE
demo-space   ate-demo-actor   ate-demo/demo-template   ACTOR_STATE_SUSPENDED   <none>                    5         39h

此时 Actor 应该进入 SUSPENDED 状态,并释放原来占用的 Worker。

kubectl ate get workers
# 输出
NAME                                   POOL                   STATE                 ACTORS   CPU   MEMORY    POD                                                              AGE
978b42b3-8bed-4b8c-a1b0-957c5b343f76   demo-pool        WORKER_STATE_ACTIVE   0/1      0/1   0/2Gi     ate-demo-pool/demo-pool-68c995676b-2nrvm             39h
009b30f6-e170-43a0-9b5d-7cfe236e9e9f   demo-pool        WORKER_STATE_ACTIVE   0/1      0/1   0/2Gi   ate-demo-pool/demo-pool-68c995676b-f7tmn             39h
fef5851c-52b1-4805-b7b0-c86af3d53143   demo-pool        WORKER_STATE_ACTIVE   0/1      0/1   0/2Gi     ate-demo-pool/demo-pool-68c995676b-kcwnz             39h

再次访问:

curl -i \
  -H "ate-target-actor: demo-space/my-agent-001" \
  http://localhost:8000/

Router 会触发 Actor 恢复,然后将请求转发到新的执行位置。

你可以再查看:

kubectl ate get actor my-agent-001 \
  -a demo-space \
  -o yaml

kubectl ate get workers

这就完成了 Actor 的创建、启动、访问、暂停和恢复。

8. 完整创建流程汇总

如果前面的准备工作都完成了,后续日常创建 Actor 主要就是下面这些命令:

# 1. 创建 Kubernetes Namespace
kubectl create namespace demo-space

# 2. 创建 WorkerPool
kubectl apply -f workerpool.yaml

# 3. 创建 Atespace
kubectl ate create atespace demo-space

# 4. 创建 ActorTemplate
kubectl ate create actor-template -f actor-template.yaml

# 5. 等待 Golden Snapshot 就绪
kubectl ate get actor-templates -a demo-space

# 6. 创建 Actor
kubectl ate create actor my-agent-001 \
  -a demo-space \
  --template demo-template

# 7. 启动 Actor
kubectl ate resume actor my-agent-001 \
  -a demo-space

# 8. 查看 Actor
kubectl ate get actor my-agent-001 -a demo-space

# 9. 查看 Worker
kubectl ate get workers

# 10. 暂停 Actor
kubectl ate suspend actor my-agent-001 \
  -a demo-space

# 11. 删除 Actor
kubectl ate delete actor my-agent-001 \
  -a demo-space

参考: