云沙箱支持直接从容器镜像仓库拉取镜像来构建 Sandbox 模板。当业务需要预置特定语言运行时、系统依赖、私有 SDK 或数据科学工具链时,把这些内容打包成一个容器镜像,再从镜像构建模板,比在运行时逐条安装依赖更可控、更可复现。
本文以 GitHub Container Registry(GHCR) 上的私有镜像为例,说明如何在美国(硅谷)地域(us-west-1)从 ghcr.io/<owner>/<image>:<tag> 构建模板、创建 Sandbox 并校验运行结果。GHCR 属于需要鉴权的私有仓库,因此构建时需要携带拉取凭据。
业务场景
团队把统一的 Python/Node 运行时和常用依赖打包成镜像,多个 Agent 共用同一基础模板。
分析类任务需要预装
pandas、numpy、绘图库等重依赖,希望构建期一次装好,而不是每次运行时安装。私有 SDK 或内部工具只发布到 GHCR 私有仓库,不能公开拉取。
需要把镜像版本与模板版本对齐,做到构建可追溯、可回滚。
前置条件
已开通云沙箱,并获取目标地域的
E2B_API_KEY。目标地域为美国(硅谷),对应接入点:
api_url:https://api.us-west-1.e2b.fc.aliyuncs.comdomain:us-west-1.e2b.fc.aliyuncs.com
已在 GHCR 上准备好镜像,例如
ghcr.io/<owner>/python:3.10。已创建用于拉取镜像的 GitHub 凭据(见下节「镜像仓库凭据」)。
安装
e2bSDK:
pip install e2b镜像仓库凭据
从 GHCR 私有仓库拉取镜像需要携带用户名和密码。这里的凭据是 GitHub 的 Personal Access Token (classic),不是账号登录密码:
用户名:填 GitHub 用户名(镜像所属的 owner)。
密码:填创建的 Personal Access Token (classic) 值(形如
ghp_xxxxxxxx)。
Token 权限要求:创建 Personal Access Token (classic) 时,勾选
read:packages和write:packages两项packages权限。read:packages用于拉取镜像(构建阶段必需),勾选write:packages时 GitHub 会自动包含read:packages。缺少这些权限会导致构建阶段拉取镜像失败(鉴权 401 / 403,可见 GitHub 相关文档)。
创建路径:GitHub → Settings → Developer settings → Personal access tokens → Tokens (classic) → Generate new token (classic),在 Select scopes 中勾选 read:packages、write:packages。
构建请求通过以下两个 HTTP Header 传递凭据,SDK 侧以 Template.build() 的 headers 参数注入:
| Header | 含义 | 取值 |
X-E2B-Template-Source-Username | 镜像仓库用户名 | GitHub 用户名 |
X-E2B-Template-Source-Password | 镜像仓库密码 | Personal Access Token (classic) |
凭据属于敏感信息,建议通过环境变量或密钥管理服务注入,不要硬编码进代码或提交进代码仓库。
推荐流程
建议把「自定义镜像 → 模板 → Sandbox」拆成四步:
用
Template().from_image(<镜像地址>)声明镜像来源。调用
Template.build构建模板,通过headers参数传入仓库凭据,并指定cpu_count、memory_mb等规格,拿到template_id。用
template_id创建 Sandbox,等待数据面就绪后执行命令做冒烟校验。校验通过后销毁 Sandbox,避免资源长期占用。
其中模板构建是一次性动作:同一镜像构建出的 template_id 可以被后续多次 Sandbox.create 复用,生产上通常把构建和运行拆成两个阶段,而不是每次运行都重新构建。
示例代码
以下示例从 GHCR 私有镜像 ghcr.io/<owner>/python:3.10 构建模板,创建 Sandbox,执行一段 Python 打印校验标记,最后销毁 Sandbox。用户名、密码、E2B_API_KEY 均从环境变量读取。
import os
import time
import uuid
from e2b import Sandbox, Template, default_build_logger
API_URL = "https://api.us-west-1.e2b.fc.aliyuncs.com"
DOMAIN = "us-west-1.e2b.fc.aliyuncs.com"
SOURCE_IMAGE = "ghcr.io/<owner>/python:3.10"
SANDBOX_MARKER = "sandbox-ok"
READY_TIMEOUT_SECONDS = 90
READY_INTERVAL_SECONDS = 3
def required_env(name: str) -> str:
value = os.environ.get(name, "").strip()
if not value:
raise RuntimeError(f"缺少环境变量: {name}")
return value
def main() -> int:
# USERNAME=GitHub 用户名;PASSWORD=Personal Access Token (classic)
username = required_env("USERNAME")
password = required_env("PASSWORD")
api_key = required_env("E2B_API_KEY")
name = f"custom-python-{int(time.time())}-{uuid.uuid4().hex[:8]}"
headers = {
"X-E2B-Template-Source-Username": username,
"X-E2B-Template-Source-Password": password,
}
# 1. 从 GHCR 私有镜像构建模板
build = Template.build(
Template().from_image(SOURCE_IMAGE),
name=name,
cpu_count=2,
memory_mb=2048,
skip_cache=False,
on_build_logs=default_build_logger(),
headers=headers,
api_key=api_key,
api_url=API_URL,
domain=DOMAIN,
)
print(f"template_id={build.template_id}")
# 2. 用 template_id 创建 Sandbox
sandbox = Sandbox.create(
template=build.template_id,
timeout=900,
api_key=api_key,
api_url=API_URL,
domain=DOMAIN,
)
print(f"sandbox_id={sandbox.sandbox_id}")
try:
# 3. 等待数据面就绪并执行冒烟校验
last_error = None
deadline = time.monotonic() + READY_TIMEOUT_SECONDS
while time.monotonic() < deadline:
try:
result = sandbox.commands.run(
f"python3 - <<'PY'\nprint('{SANDBOX_MARKER}')\nPY",
timeout=60,
)
break
except Exception as err:
last_error = err
time.sleep(READY_INTERVAL_SECONDS)
else:
raise RuntimeError(f"数据面等待超时: {last_error}") from last_error
if result.exit_code != 0 or SANDBOX_MARKER not in result.stdout:
raise RuntimeError(f"校验失败: exit={result.exit_code}, stdout={result.stdout}")
print(f"stdout={result.stdout.strip()}")
finally:
# 4. 销毁 Sandbox
sandbox.kill()
return 0
if __name__ == "__main__":
raise SystemExit(main())运行方式(凭据放在环境变量中):
export USERNAME="<github-username>"
export PASSWORD="ghp_xxxxxxxxxxxxxxxxxxxx" # Personal Access Token (classic)
export E2B_API_KEY="<your-e2b-api-key>"
python3 build_from_ghcr.py正常输出会依次打印模板构建日志、template_id、sandbox_id,以及校验标记 sandbox-ok,最后销毁 Sandbox。
上线建议
凭据管理:GitHub Token 和
E2B_API_KEY通过环境变量或密钥管理服务注入,不要写进代码或提交进 Git;Token 遵循最小权限原则,仅勾选read:packages、write:packages,并定期轮转。构建与运行分离:模板构建是一次性动作,构建产出的
template_id应持久化保存并复用;不要在每次创建 Sandbox 前重复构建。镜像版本化:镜像使用明确的 tag(避免只用
latest),做到模板与镜像版本对齐、可回溯、可回滚。资源规格:
cpu_count、memory_mb按镜像内工作负载评估,重依赖或大数据处理场景适当上调。及时销毁:任务结束后调用
sandbox.kill()(放在finally中),避免异常路径下 Sandbox 长期占用。