返回 Blog

HANDS-ON / GOCLAW BLOG

用 kind 运行 E2B Sandbox 调用任务

在本地 kind 集群中运行调用 E2B 的 Worker,完成 Sandbox 创建、命令执行和回收;E2B 数据面仍运行在托管环境。

E2BkindKubernetesSandbox
01

实验范围

kind 把 Kubernetes 节点运行在容器里,适合本地开发和 CI。本实验在 kind 中部署调用 E2B 的 Worker,配置 Secret、Job 生命周期和日志采集。Sandbox 由 E2B 托管服务创建。

本文不部署 E2B 自托管基础设施。官方自托管方案包含 Terraform、Packer、Nomad、PostgreSQL、对象存储和 Firecracker orchestrator;AWS 参考架构要求裸金属或支持嵌套虚拟化的实例。

  • kind 验证:Kubernetes Job、配置注入、SDK 调用、失败重试、日志和清理。
  • E2B 验证:Sandbox 创建、命令执行、文件和生命周期 API。
  • 不验证:本地 Firecracker、嵌套虚拟化、E2B 自托管控制面与容量调度。
02

实验链路

执行链路包括:将本地镜像加载到 kind,Kubernetes Job 从 Secret 读取 API Key,Python Worker 创建 Sandbox、运行固定命令、输出结果,并在 finally 中回收资源。

  • 入口:Kubernetes Job。
  • 凭据:仅通过 Secret 注入,不写进镜像或 Git。
  • 执行:E2B Python SDK 的 create → commands.run → kill。
  • 证据:Job 日志、Sandbox ID、stdout、exit code 和清理结果。
03

在 finally 中回收 Sandbox

Smoke Test 使用固定命令,不允许模型生成任意 Shell。Worker 输出 Sandbox ID、退出码和 stdout,便于 CI 判断结果。

无论命令成功还是异常,都在 finally 中调用 kill。生产系统还需要 TTL 回收器和控制面补偿任务,不能只依赖客户端正常退出。

worker.pyREFERENCE · REVIEW BEFORE RUNNING
import json
from e2b import Sandbox

sandbox = Sandbox.create(
    timeout=300,
    metadata={"lab": "goclaw-kind", "purpose": "smoke"},
)

try:
    result = sandbox.commands.run(
        "python -c 'import platform; print(platform.platform())'"
    )
    print(json.dumps({
        "sandbox_id": sandbox.sandbox_id,
        "exit_code": result.exit_code,
        "stdout": result.stdout.strip(),
    }, ensure_ascii=False))
finally:
    sandbox.kill()
04

固定 Worker 镜像与 SDK 版本

示例固定 SDK 主版本范围,实际仓库应锁定经过验证的精确版本并记录升级证据。Worker 使用非 root 用户运行;API Key 只在 Pod 启动时注入。

DockerfileREFERENCE · REVIEW BEFORE RUNNING
FROM python:3.12-slim

WORKDIR /app
RUN pip install --no-cache-dir "e2b>=2.3,<3"
COPY worker.py /app/worker.py

USER 65532:65532
CMD ["python", "/app/worker.py"]
05

用 Kubernetes Job 约束单次调用

backoffLimit 设为 0,避免认证错误或 Provider 故障触发无意识的重复创建。Job 完成五分钟后自动清理 Kubernetes 对象,但这不会替代 E2B Sandbox 的 kill/TTL。

生产环境应进一步配置 NetworkPolicy、Workload Identity 或外部 Secret 管理,并把请求幂等键、预算和审计字段传给 GoClaw 控制面。

deploy/e2b-smoke-job.yamlREFERENCE · REVIEW BEFORE RUNNING
apiVersion: batch/v1
kind: Job
metadata:
  name: e2b-smoke
  namespace: agent-lab
spec:
  backoffLimit: 0
  ttlSecondsAfterFinished: 300
  template:
    spec:
      restartPolicy: Never
      containers:
        - name: worker
          image: goclaw/e2b-kind-lab:0.1.0
          imagePullPolicy: IfNotPresent
          env:
            - name: E2B_API_KEY
              valueFrom:
                secretKeyRef:
                  name: e2b-credentials
                  key: E2B_API_KEY
          resources:
            requests:
              cpu: 50m
              memory: 64Mi
            limits:
              cpu: 250m
              memory: 256Mi
06

用 Makefile 固定实验入口

Makefile 提供 make lab-up、make lab-image、make lab-secret、make lab-run、make lab-logs 和 make lab-down。开发环境与 CI 使用相同入口。

kind 官方支持将本地镜像加载到命名集群;镜像不要使用 latest,并在 Job 中设置 IfNotPresent,避免 kubelet 再次尝试从远端拉取。

MakefileREFERENCE · REVIEW BEFORE RUNNING
LAB_CLUSTER ?= goclaw-e2b
LAB_IMAGE ?= goclaw/e2b-kind-lab:0.1.0

.PHONY: lab-up lab-image lab-secret lab-run lab-logs lab-down

lab-up:
	kind create cluster --name $(LAB_CLUSTER) --wait 90s
	kubectl create namespace agent-lab --dry-run=client -o yaml | kubectl apply -f -

lab-image:
	docker build -t $(LAB_IMAGE) .
	kind load docker-image $(LAB_IMAGE) --name $(LAB_CLUSTER)

lab-secret:
	@test -n "$(E2B_API_KEY)" || (echo "E2B_API_KEY is required"; exit 1)
	kubectl -n agent-lab create secret generic e2b-credentials \
		--from-literal=E2B_API_KEY="$(E2B_API_KEY)" \
		--dry-run=client -o yaml | kubectl apply -f -

lab-run:
	kubectl -n agent-lab delete job e2b-smoke --ignore-not-found
	kubectl apply -f deploy/e2b-smoke-job.yaml
	kubectl -n agent-lab wait --for=condition=complete job/e2b-smoke --timeout=180s

lab-logs:
	kubectl -n agent-lab logs job/e2b-smoke

lab-down:
	kind delete cluster --name $(LAB_CLUSTER)
07

通过条件

至少保存一次结构化日志,确认 sandbox_id 非空、exit_code 为 0、stdout 包含 Linux 内核信息,并确认 Job 完成。随后在 E2B Dashboard 或 CLI 中验证 Sandbox 已终止。

  • 认证失败时,Job 必须失败且不能无限重试。
  • 命令非零退出时,仍然必须执行 kill。
  • 删除 kind 集群不会自动删除远端 Sandbox。
  • 任何输出都不能包含 E2B_API_KEY。
S

官方来源与继续阅读

文中的技术信息来自以下官方文档和开源仓库。实施前请核对所用版本的最新说明。