K8EK8E
首页
  • 什么是 K8E
  • 快速开始
  • 沙箱运行时配置
  • Sandbox CLI
  • 沙箱范例
  • E2B SDK 沙箱
  • DeepSeek Harness 接入
  • 架构
  • 组件
  • 高级安装
  • K8E 对比其他方案
  • 参与贡献
更新日志
  • English
  • 简体中文
GitHub
首页
  • 什么是 K8E
  • 快速开始
  • 沙箱运行时配置
  • Sandbox CLI
  • 沙箱范例
  • E2B SDK 沙箱
  • DeepSeek Harness 接入
  • 架构
  • 组件
  • 高级安装
  • K8E 对比其他方案
  • 参与贡献
更新日志
  • English
  • 简体中文
GitHub
  • 指南

    • 什么是 K8E?
    • 快速开始
    • 沙箱运行时配置
    • Sandbox CLI
    • 沙箱范例 —— 由你的 AI Agent 驱动
    • 使用官方 E2B SDK 操作沙箱
    • DeepSeek Harness + k8e-sandbox 接入指南(分步)
    • 架构
    • 组件
    • 高级安装
    • K8E 对比其他沙箱平台
    • 参与贡献
  • 操作指南

    • 操作指南 (Guides)
    • 部署标准集群
    • 使用kubekey一键部署k8e
    • 内置Nerdctl工具
    • 离线环境下快速部署k8e
    • 默认支持10年有效证书
    • k8e集群备份与恢复
    • k8s安装配置Flannel的方案
    • 使用kube-vip实现集群VIP访问
    • 怎么清理K8E集群
    • 备份和恢复
    • 自定义pause镜像

Sandbox CLI

k8e-sandbox-cli 是一个独立二进制(约 44MB),让 AI Agent 直接访问 K8E 沙箱基础设施 —— 无需安装服务器端。

AI Agent(claude code / codex / pi)
    │  shell 命令
    ▼
k8e-sandbox-cli run "print('hello')" --lang python
    │  gRPC (TLS)
    ▼
sandbox-grpc-gateway:50051
    │
    ▼
隔离 Pod(gVisor / Kata / Firecracker)

安装 Skill

三步:给服务器配上公网名字 → 创建 API key → 在客户端执行 connect。

1. 告诉服务器客户端会拨的公网名字(仅远端/云主机需要)

沙箱网关证书(:50051,mTLS)是根据主机网卡地址生成的 —— AWS 上这些都是私有 VPC IP,客户端拨公网名字时 TLS 握手会失败。按你的部署方式选一种设置(KIP-22):

# /etc/k8e/config.yaml (服务端守护进程配置 —— 键名与 CLI 参数一致)
sandbox-advertise-hostname: sandbox.example.com   # 或弹性 IP,如 203.0.113.10
# 等价的一次性启动参数
k8e-server --sandbox-advertise-hostname sandbox.example.com

# 旧版环境变量兜底 —— 注入到 k8e-server 进程环境(如 systemd),
# 不要在登录 shell 里设置;与上面的参数合并生效
# K8E_SANDBOX_ADVERTISED_HOSTNAME=sandbox.example.com

只能是裸 DNS 名或裸 IP。 带 scheme(https://…)、带端口(host:50051)、 带路径或空格都会被拒绝:k8e-server 会直接启动失败并报 invalid --sandbox-advertise-hostname: …。能解析成 IP 的值进证书的 IP SAN,其余进 DNS SAN。/etc/k8e/config.yaml 里的 tls-san不是这个开关 —— 它只作用于 kube-apiserver 的服务证书。

重启 k8e-server 即可 —— SAN 集合变化时网关证书会自动重新生成,下一次 connect 就能用新名字,无需手动删除 /var/lib/k8e/server/tls/sandbox-server.{crt,key}。

2. 在服务器端创建 API key(默认 TTL 30 天)

k8e sandbox-apikey create my-agent
# → {"name":"my-agent","key":"849a5302e66f98d1d5064ef8501703574af4053b7bf9cf5337f9533326ce2bc9",
#    "e2b_key":"e2b_849a5302e66f98d1d5064ef8501703574af4053b7bf9cf5337f9533326ce2bc9",
#    "ttl_days":30,"created_at":"...","expires_at":"..."}
# 当服务器的公网名字已知时,还会打印:
# mcp client config:
# {"url":"https://sandbox.example.com/mcp","headers":{"Authorization":"Bearer e2b_849a5302e66f98d1…"}}

# 可选:更长或永不过期的 bootstrap key
# k8e sandbox-apikey create my-agent --ttl 90d      # 也支持 720h 或纯数字天数
# k8e sandbox-apikey create my-agent --ttl never   # 也支持 none / 0

key(裸 hex)传给 connect --apikey。e2b_key 给官方 e2b SDK 用 —— 它们要求 e2b_ 前缀,服务端会剥掉。末尾的 mcp client config 块可以直接粘进 MCP 客户端 (Claude Code、Codex);只有在服务器公网名字已知时才会打印,没有公网名字的主机 自然不会输出它。

3. 在客户端下载 CLI 并连接

connect 会做四件事:mTLS 认证、验证网关、把 k8e-sandbox-cli 放进 PATH、记住 这个网关,以及把 /k8e-sandbox skill 装进你的 harness —— 之后的命令不再需要 --endpoint。

# 1. 下载对应平台二进制(约 44MB)
#    选择你的平台:linux-amd64 | linux-arm64 | darwin-amd64 | darwin-arm64 | windows-amd64.exe
curl -sLO https://github.com/xiaods/k8e/releases/latest/download/k8e-sandbox-cli-linux-amd64
chmod +x k8e-sandbox-cli-linux-amd64

# 2. 为下载的文件创建普通命令名软链接(不要重命名)
#    可选:把两者都移动到 PATH 目录,例如 ~/.local/bin/
ln -s k8e-sandbox-cli-linux-amd64 k8e-sandbox-cli

# 3. 连接:mTLS 认证 + 验证网关 + 安装 /k8e-sandbox skill
#    (Claude / Codex / Pi / dsh;--agent 指定目标,默认自动探测)
#    注意:--endpoint 和 --apikey 是全局参数,放在子命令之前
./k8e-sandbox-cli --endpoint sandbox.example.com:50051 --apikey 849a5302e66f98d1d5064ef8501703574af4053b7bf9cf5337f9533326ce2bc9 connect

# 参数也可以放在子命令后面(两种写法都有效)
# ./k8e-sandbox-cli connect --endpoint sandbox.example.com:50051 --apikey 849a… --ca-file ./sandbox-ca.crt

# 多集群:使用命名 profile(见下方「配置与认证」)
# ./k8e-sandbox-cli --profile prod connect --apikey 849a5302e66f98d1d5064ef8501703574af4053b7bf9cf5337f9533326ce2bc9

和服务器在同一台机器上? 直接运行 k8e-sandbox-cli connect —— CLI 会自动 发现本地网关及其证书,无需 API key。

4. 把网关 CA 拿到客户端

网关用的是私有 CA,你的机器不信任它,所以首次远程 connect 需要这个 CA。 connect 和 login 通过系统信任、已缓存的 CA 或 --ca-file 校验网关。

在服务器本机上 CLI 可以直接导出:

k8e-sandbox-cli tls export-ca --output ~/sandbox-ca.crt
# 或输出到标准输出:  k8e-sandbox-cli tls export-ca -

服务器上没装 CLI 的话,同一个文件就在磁盘上:

sudo cat /var/lib/k8e/server/tls/sandbox-ca.crt > ~/sandbox-ca.crt

把它复制到客户端机器,首次 connect 时带上:

scp user@server:~/sandbox-ca.crt ./
./k8e-sandbox-cli --endpoint <服务器 IP>:50051 --apikey <key> \
  connect --ca-file ./sandbox-ca.crt

CA 是公开证书,不是秘密 —— 它只用来证明「这个网关就是这个网关」。真正的秘密是 API key;客户端私钥永远不离开客户端。

tls export-ca 在客户端有 kubeconfig 时也会去找 sandbox-matrix/sandbox-ca ConfigMap ——但集群目前并不发布这个 ConfigMap,所以上面这条「在服务器上导出」的路径才是 真正能用的。如果你就在服务器本机,k8e-sandbox-cli connect(不带参数)会跳过这一切: 它自动发现本地网关及其证书。

5. 验证整条链路通了

一条命令就能证明 API key、mTLS 客户端证书、gRPC 网关、warm pool 和运行时全部对得上:

k8e-sandbox-cli run 'echo hello from k8e'
# → {"duration_ms":…,"exit_code":0,"session_id":"sess-…","status":"completed",
#    "stdout":"hello from k8e\n","stderr":"","…":…}

stdout 里有 hello from k8e 就说明你已经在一个隔离的 gVisor Pod 里执行代码了。 如果失败,下面的故障排查表会把症状对应到原因。

status 不会创建会话

k8e-sandbox-cli status 只是探测网关——在 run 或 create 真正建出会话之前, 它会报 "session_id":""。这不是错误,先跑点东西就行。

平台二进制:

平台下载名称
Linux amd64k8e-sandbox-cli-linux-amd64
Linux arm64k8e-sandbox-cli-linux-arm64
macOS amd64k8e-sandbox-cli-darwin-amd64
macOS arm64k8e-sandbox-cli-darwin-arm64
Windows amd64k8e-sandbox-cli-windows-amd64.exe(通过 mklink k8e-sandbox-cli.exe k8e-sandbox-cli-windows-amd64.exe 建软链接)

同一个二进制,两个名字: 下载的带平台后缀文件就是 k8e-sandbox-cli 命令 —— 软链接只是普通名字的别名。下文所有示例均使用 k8e-sandbox-cli。

然后在你的 Agent 工具链中:

/k8e-sandbox <目标>            # Claude Code
$k8e-sandbox <目标>            # Codex(或从 /skills 里选)
/skill:k8e-sandbox <目标>      # Pi

dsh(DeepSeek Harness)通过它的 skill 工具加载同一份 skill,也可以直接在对话里 点名使用 —— 插件挂载路径见 dsh + k8e-sandbox。

或自然提问:"在沙箱里运行这段 Python 代码" —— skill 会自动驱动 k8e-sandbox-cli run。

Skill 没出现? 运行 k8e-sandbox-cli connect --skill-only 刷新 harness 安装 (不拨号网关),然后开一个新的 agent 会话。k8e-sandbox-cli doctor 会检查 二进制 / PATH / profile / 证书 / skill 安装 / dsh 插件(--json 输出机器可读 报告,--fix 自动修掉能本地修复的问题)。

可用命令

命令说明
k8e-sandbox-cli --profile <name> …使用 ~/.k8e/sandbox/profiles.yaml 中的命名 profile(不是服务器的 /etc/k8e/config.yaml)
k8e-sandbox-cli connect连接本地/远程网关、验证它、确保 PATH、记住网关,并安装 /k8e-sandbox skill
k8e-sandbox-cli connect --agent <auto|claude|codex|pi|dsh|all>指定 skill 安装目标(默认 auto:探测本机已装的 harness)
k8e-sandbox-cli connect --skill-only仅重装 Agent skill(不拨号网关)
k8e-sandbox-cli connect --skip-skill只认证,不安装 Agent skill
k8e-sandbox-cli login仅认证(mTLS 证书;不安装 skill);可选 --device-name
k8e-sandbox-cli doctor诊断 CLI / 网关 / 证书 / skill 安装 / dsh 插件,并逐项给出修复命令(--json、--fix)
k8e-sandbox-cli tls export-ca把沙箱网关 CA 写到 ~/.k8e/sandbox-ca.crt(--output <path> / - 输出到 stdout),供只用 IP 的网关、MCP 和 e2b 客户端信任
k8e-sandbox-cli status检查沙箱服务可用性和当前会话
k8e-sandbox-cli run <code>运行代码或 shell 命令(自动创建/管理会话;--lang、--timeout、--raw、--session-id、--tenant、--background、--manifest、--git-repo、--allowed-hosts)
k8e-sandbox-cli create创建新会话(自定义运行时、出口、env、secret、manifest、git-repo)
k8e-sandbox-cli get <sid>检查会话(阶段、运行时、env 键)
k8e-sandbox-cli sessions列出会话
k8e-sandbox-cli destroy <sid>销毁会话并释放资源
k8e-sandbox-cli write <sid> <path>写入文件到 /workspace(内容经 stdin)
k8e-sandbox-cli read <sid> <path>从 /workspace 读取文件
k8e-sandbox-cli push <sid> <local> [remote]将本地文件流式传入沙箱——分块 4MiB 窗口、恒定内存、二进制安全、任意大小(--chunk-mb 可调)
k8e-sandbox-cli pull <sid> <remote> [local]将沙箱文件流式取回本地(同样的分块传输)
k8e-sandbox-cli list <sid>列出 /workspace 中的文件(按 --since 时间戳过滤,用于变更文件 diff)
k8e-sandbox-cli log <sid>重放执行记录(--offset、--limit、--follow)
k8e-sandbox-cli events <sid>读取守护进程 NDJSON 事件流(--limit)
k8e-sandbox-cli ps <sid>列出沙箱 Pod 中的进程(pid、comm、state)
k8e-sandbox-cli poll <run-id>轮询后台运行(--follow)
k8e-sandbox-cli subagent <parent-sid>在父会话下生成子沙箱(共享父 Pod + workspace,不新建 Pod)
k8e-sandbox-cli confirm <sid> <action>将不可逆操作置于人工审批门禁(--timeout、--no-wait)
k8e-sandbox-cli approve <approval-id>批准待处理的 confirm 请求(--reject、--reason)
k8e-sandbox-cli snapshot save <sid> <name>保存 workspace 快照(内容寻址、去重)
k8e-sandbox-cli snapshot list列出已保存的快照
k8e-sandbox-cli snapshot restore <name>从快照新建会话(--base <snap> 增量恢复)
k8e-sandbox-cli snapshot delete <name>删除快照
k8e-sandbox-cli expose <port>通过 k8e API Gateway 暴露沙箱内服务,返回公网 URL(--host、--session-id)
k8e-sandbox-cli unexpose <port>停止暴露某端口(幂等;--session-id)
k8e-sandbox-cli exposed列出当前会话的活跃暴露
k8e-sandbox-cli allow-hosts自由配置会话出网白名单,实时生效(--hosts 替换、--add、--remove、--clear)
k8e-sandbox-cli mcp-serve为具备 MCP 能力的 Agent 提供沙箱 MCP 端点(--listen、--gateway、TLS + API-key 标志、--bootstrap-api-key)
k8e-sandbox-cli benchmark热池延迟指标(--pool-size、--iterations)
k8e-sandbox-cli catalog输出机器可读的命令面(SDK 生成)
k8e sandbox-apikey create <name>创建 API key(默认 TTL 30 天;--ttl 90d / 720h / 45 / never)—— 输出含 key、e2b_key 和可直接粘贴的 mcp client config 块
k8e sandbox-apikey list列出 API key 名称与过期时间(不回显 secret)
k8e sandbox-apikey delete <name>删除 API key(服务器端)

完整用法参见 pkg/sandboxcli/skills/k8e-sandbox/SKILL.md,以及 KIP-17(profile 与 API-key TTL)和 KIP-22(上面的 advertise hostname)。

示例 —— 从单行命令到 Vue 网站

上手演练请见 沙箱范例 —— 由你的 AI Agent 驱动:你在 Agent 工具链(pi / Claude Code / Codex)中通过 /k8e-sandbox skill 驱动一切。本页是原始命令参考;范例页展示的是同样的命令由 skill 代表你执行。

先快速感受一下 skill 会替你运行什么:

快速示例

# Shell 命令(默认 lang=bash)
k8e-sandbox-cli run "ls -la /workspace"

# TypeScript —— 类型注解通过 tsx 运行
k8e-sandbox-cli run "const nums: number[] = [1, 2, 3]; console.log(nums.reduce((a, b) => a + b, 0))" --lang ts

# 后台执行(立即返回 run_id,然后轮询)
k8e-sandbox-cli run "sleep 30; echo done" --background
k8e-sandbox-cli poll <run-id>

# 基于租户的跨进程会话复用
k8e-sandbox-cli run "echo hello" --tenant my-project

# 流式查看长时间运行的输出
k8e-sandbox-cli run "python3 train.py" --session-id $SID --raw

# 子 Agent:共享父 Pod + workspace 的子会话
k8e-sandbox-cli subagent <parent-sid>

# 快照:内容寻址的保存/恢复
SID=$(k8e-sandbox-cli create | jq -r .session_id)
k8e-sandbox-cli run "echo work > /workspace/state.txt" --session-id $SID
k8e-sandbox-cli snapshot save $SID my-state
k8e-sandbox-cli snapshot list
# ... 之后从快照新建会话:
k8e-sandbox-cli snapshot restore my-state
# 基于现有快照增量恢复(KIP-16 M2):
k8e-sandbox-cli snapshot restore my-state --base older-state

暴露服务(KIP-24)

当你的代码在沙箱里启动了长驻服务(web 应用、API 服务)时,通过 k8e API Gateway 把它暴露出去,得到一个可以直接访问的 URL:

k8e-sandbox-cli run "python3 -m http.server 8080 --bind 127.0.0.1" --background
k8e-sandbox-cli expose 8080
# -> {"url":"http://<gateway>/k8e/expose/<sid>/8080/","port":8080,"session_id":"..."}
curl http://<gateway>/k8e/expose/<sid>/8080/
k8e-sandbox-cli exposed            # 列出活跃暴露
k8e-sandbox-cli unexpose 8080      # 停止暴露

URL 链路:Cilium Gateway API → 内嵌 e2b HTTP server → 反向代理到 pod, 无需端口转发、无 pod 入站暴露。

故障排查

先跑 k8e-sandbox-cli doctor —— 它会检查二进制、PATH、profile、证书和 skill 安装, 并为每个失败项打印修复方式(--json 输出机器可读报告,--fix 自动应用能本地修复的问题)。

症状原因修复
connect 报 TLS / 证书错误网关的私有 CA 不被你的机器信任在服务器上导出 CA(k8e-sandbox-cli tls export-ca 或 sudo cat /var/lib/k8e/server/tls/sandbox-ca.crt),首次 connect 时带 --ca-file ./sandbox-ca.crt
connect 找不到网关客户端拨的地址或端口不对gRPC 网关是 :50051;E2B HTTP 面是 :3676(或 Gateway 的 :80)。k8e-sandbox-cli doctor 会打印它将要使用的端点
connect 成功,但后续调用报 sandboxd …: connection timed out会话的 Pod 被换掉了(回收、重启、节点驱逐),缓存的 Pod IP 已失效k8e-sandbox-cli destroy <sid> 后重跑 —— 新会话会认领新的 Pod。不带 --session-id 的 run 总是用当前会话
tls export-ca 报 sandbox CA not found你不在服务器本机,且客户端没有 kubeconfig到服务器本机执行,或在服务器上 sudo cat /var/lib/k8e/server/tls/sandbox-ca.crt 后把文件拷过来
run 返回 warm pool full: …节点放不下另一个沙箱 Pod(小节点上先见顶的是 CPU request)等某个 Pod 被回收,或给节点加 CPU。kubectl -n sandbox-matrix get pods 能看到活着的 Pod
poll <run-id> 在任务还在跑时 stdout 是空的poll 返回的是状态快照,输出要等任务完成才出现继续轮询直到 status 为 completed(或用 poll --follow)
run --background 明明跑了但输出为空用的 sandboxd 版本在 JSON 字符串里吐了裸 ANSI 转义,导致响应无法解析——控制面吞掉了解析错误,于是报「没有输出」把沙箱镜像升级到 v1.37.0-20261022-rc2 或更高
文件监听报的是被监视的目录,而不是变化的文件用的 sandboxd 版本把 inotify 记录解析错了,事件名变成空串同上——inotify 解析修复在 v1.37.0-20261022-rc2
template '<name>' not founde2b API 的 template 字段选的是 Kubernetes RuntimeClass,不是 E2B 模板用 gvisor、kata、firecracker、crun 或 lunatic
Agent 里看不到 skillharness 缓存了 skill 列表k8e-sandbox-cli connect --skill-only,然后新开一个 agent 会话

配置与认证

配置文件(不要混用)

路径归属用途
/etc/k8e/config.yamlk8e server/agent守护进程 CLI flags —— 包括 sandbox-advertise-hostname(第 1 步)。CLI 从不读它。
~/.k8e/sandbox/profiles.yamlk8e-sandbox-cli命名网关 / 每 profile 的 cert_dir、device_name
~/.k8e/sandbox/config.jsonk8e-sandbox-cli最近一次 connect / login 记录
~/.k8e/sandbox-ca.crtk8e-sandbox-clik8e-sandbox-cli tls export-ca 导出的 CA,供只用 IP 的网关使用
~/.k8e/sandbox/{ca.crt,client.crt,client.key}k8e-sandbox-climTLS 材料(客户端证书 90 天;剩余不足 30 天自动续期)

/etc/k8e/config.yaml 的键名与 CLI flags 完全一致(flag-name: value), 所以任何能传给 k8e-server 的参数都能写进文件 —— 这正是 sandbox-advertise-hostname 能在重启后依然生效的原因。

mTLS 引导

远程 connect / login 仅用 API key 一次 签发客户端证书;私钥始终留在本机。之后的 RPC 只走 mTLS,线上不再传 API key。

首次认证会依次尝试系统信任、已缓存的 CA、或管理员通过 --ca-file 提供的 CA —— 请通过可信渠道取得该 CA。--insecure-bootstrap 只在没有可选 CA 时跳过服务端 校验;它会让 API key 暴露在中间人风险下,因此不应作为常规步骤。并发 CLI 进程会 串行化凭据初始化与续期。

客户端证书有效期 90 天,剩余不足 30 天 时自动续期。如果服务器重装或 CA 轮换,用新凭据和新 CA 重新连接 —— --reset-certs 会先验证再替换缓存文件:

k8e-sandbox-cli --endpoint sandbox.example.com:50051 --apikey <key> connect \
  --reset-certs --ca-file /path/to/trusted-new-ca.crt

多集群 profile

# ~/.k8e/sandbox/profiles.yaml  —— 不是 /etc/k8e/config.yaml
version: 1
current_profile: default
profiles:
  default:
    endpoint: 10.0.0.1:50051
  prod:
    endpoint: sandbox.prod.example:50051
    cert_dir: ~/.k8e/sandbox-prod
    device_name: laptop-prod
k8e-sandbox-cli --profile prod connect --apikey <64 位 hex key>
k8e-sandbox-cli --profile prod run 'echo hi'
# 或:export K8E_SANDBOX_PROFILE=prod

connect 会把它认证成功的网关写成 default profile,因此后续 CLI 调用完全不 需要再带 --endpoint。

解析优先级:flag → env → profile → 最近一次连接记录(config.json)→ 默认值。
cert_dir 没有对应 flag:K8E_SANDBOX_CERT_DIR → profile cert_dir → ~/.k8e/sandbox。
环境变量:K8E_SANDBOX_ENDPOINT、K8E_SANDBOX_APIKEY、K8E_SANDBOX_CERT_DIR、K8E_SANDBOX_PROFILE、K8E_SANDBOX_CONFIG(显式指定 profiles 文件路径)、K8E_SANDBOX_DEVICE_NAME、K8E_SANDBOX_SESSION_ID、K8E_SANDBOX_TENANT。

覆盖方式

# 只认证(mTLS 证书;不安装 skill)—— 之后命令不再需要 --apikey
k8e-sandbox-cli --endpoint sandbox.example.com:50051 --apikey <key> login

k8e-sandbox-cli run "echo hello"

# 或通过环境变量:
K8E_SANDBOX_ENDPOINT=sandbox.example.com:50051 K8E_SANDBOX_APIKEY=<key> k8e-sandbox-cli login

# 按命令覆盖端点:
K8E_SANDBOX_ENDPOINT=10.0.0.2:50051 k8e-sandbox-cli run "echo hello"
最近更新: 2026/10/24 04:45
Prev
沙箱运行时配置
Next
沙箱范例 —— 由你的 AI Agent 驱动