Kibotos
场景

批量创建与回收

本页批量创建 Workspace,程序重启也不会多建;再用 label 找到它们并删除。完整程序是 examples/go/fleet。

前提条件

  • Go 1.27 或更新版本,以及 Kibotos 仓库的一份检出。
  • ctrl 地址,以及用 kibo enrollment create --operator 为这个程序生成的注册密钥(enrollment key),见身份与注册。

步骤

1. 从自己的键派生幂等键

同一个批次与序号总是对应同一条命令。程序中途重启时会再次发送相同的命令,ctrl 重放它们,不会多创建 Workspace:

commandID := kibotos.DeriveCommandID("fleet", "create", batch, strconv.Itoa(index))

2. 创建时设置 label 与到期时间

label 用来在之后找到这个批次。平台再也不回来时,到期时间会清理这些 Workspace:

request := &ctrlv1.CreateWorkspaceRequest{
	Metadata: &ctrlv1.CommandMetadata{CommandId: commandID},
	Spec: &ctrlv1.WorkspaceCreateSpec{
		Template:  &ctrlv1.TemplateSelector{TemplateId: templateID},
		Resources: &ctrlv1.ResourceRequest{CpuMillis: 500, MemoryBytes: 256 << 20},
	},
	Labels: map[string]string{"example.com/batch": batch},
	Expiration: &ctrlv1.WorkspaceExpirationPolicy{
		Timeout: durationpb.New(30 * time.Minute),
		Action:  ctrlv1.WorkspaceExpirationAction_WORKSPACE_EXPIRATION_ACTION_DELETE,
	},
}

限制同时进行的创建数量。这个程序最多同时创建四个。

3. 处理容量不足

没有 node 放得下时,等待 Workspace 会返回原因 RESOURCE_EXHAUSTED。把任务排队后重试:

_, err = client.WaitWorkspace(ctx, created.Msg.GetWorkspace(), commandID)
if kibotos.Reason(err) == ctrlv1.FailureReason_FAILURE_REASON_RESOURCE_EXHAUSTED {
	return fmt.Errorf("no capacity: %w", err)
}

4. 用 label 找到批次

逐页列出带这个 label 的 Workspace,平台不需要自己保存 ID 列表:

page, err := client.Workspaces().ListWorkspaces(ctx, connect.NewRequest(&ctrlv1.ListWorkspacesRequest{
	LabelSelector: map[string]string{"example.com/batch": batch},
	PageToken:     token,
}))

5. 删除并确认

用列表返回的到期版本删除每个 Workspace,等每次删除完成,再列一次,确认已经没有剩余:

request := &ctrlv1.DeleteWorkspaceRequest{
	Metadata:                   &ctrlv1.CommandMetadata{CommandId: commandID},
	WorkspaceId:                workspaceID,
	ExpectedExpirationRevision: workspace.GetExpiration().GetRevision(),
}

6. 运行程序

一个批次名称只能用一次:再次运行会重放已完成的命令,而它们的 Workspace 已经删除。不传 -batch 时,程序用当前时间命名批次:

go run ./examples/go/fleet -endpoint https://ctrl.example.com:18092 \
  -identity "$HOME/.local/state/kibotos-fleet" -enrollment-key-file fleet.key \
  -batch nightly-2026-11-09 -count 3
batch nightly-2026-11-09 has 3 Workspaces
  ws-06gvz1hxyxyv3crnhyq9pj6848 WORKSPACE_STATE_AVAILABLE
  ws-06gvz1hxz5v3z1466hj4s08ec4 WORKSPACE_STATE_AVAILABLE
  ws-06gvz1hxz9yvd3b4w4n86em0km WORKSPACE_STATE_AVAILABLE
reclaimed 3 Workspaces

用 E2B SDK

用 metadata 标记 sandbox,按它列出,再逐个删除:

import { Sandbox } from 'e2b';

const batch = 'nightly-2026-11-09';
await Promise.all([0, 1, 2].map((worker) =>
  Sandbox.create('kibotos-minimal', {
    timeoutMs: 30 * 60_000,
    metadata: { batch, worker: String(worker) },
  })));

const paginator = Sandbox.list({ query: { metadata: { batch } } });
while (paginator.hasNext) {
  for (const { sandboxId } of await paginator.nextItems()) {
    await Sandbox.kill(sandboxId);
  }
}

注意

  • 列表不是某一时刻的快照。读取分页期间创建或删除的资源可能出现,也可能不出现,见分页。
  • 用同一个幂等键发送不同的请求会返回 already_exists,所以同一个键对应的请求要保持相同。
  • 删除 Workspace 时,随它创建的 Volume 也会删除,见删除哪些数据。

下一步

本页内容