自定义沙箱 快速入门
更新时间:2026-01-26
概览
本文将介绍如何使用sdk在沙箱服务创建自定义模版,以支持用户扩展沙箱功能。
说明:在构建自定义模版时沙箱服务会为用户的模版注入命令执行、文件操作的功能,用户无需在自己的模版内构建相关程序。
安装依赖
执行如下命令安装依赖
1pip install e2b
1npm install e2b
指定镜像构建模版
基于ccr镜像仓库中的镜像构建模版,注意镜像仓库需要开通公网以及访问权限,否则沙箱服务无法拉取用户镜像
Python
1from e2b import Template, wait_for_timeout
2import os
3
4os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
5# 修改为用户自己申请的api_key
6os.environ["E2B_API_KEY"] = "bce-v3/****************************"
7
8# 用户可替换自己的镜像仓库中的镜像
9template = Template().from_image(
10 image="ccr-******-pub.cnc.gz.baidubce.com/*******/ubuntu2204_python312:v1",
11)
12
13buildIf = Template.build_in_background(template,
14 alias="test_custom_template", # 用户自定义模版id
15 cpu_count=2,
16 memory_mb=2048)
17
18print(f"build_templateId: {buildIf.template_id}")
19print(f"build_buildId: {buildIf.build_id}")
20print(f"build_alias: {buildIf.alias}")
针对私有镜像,用户需要指定镜像仓库的账号密码,否则沙箱服务无法拉取用户镜像
Python
1# 替换为用户镜像仓库的账号和密码
2template = Template().from_image(
3 image="ccr-*****-pub.cnc.bj.baidubce.com/******/sandbox:v1",
4 username="******",
5 password="*****"
6)
基于模版构建新模版
用户在自己已有模版或者官方模版的基础上构建新模版,如下以基于官方模版browser-use为例
Python
1template = Template().from_template(
2 "browser-use-v1" # 官方模版id/用户已有模版id
3)
4
5buildIf = Template.build_in_background(template,
6 alias="browser_with_file_cmd", # 用户自定义模版id
7 cpu_count=2,
8 memory_mb=2048)
9
10print(f"build_templateId: {buildIf.template_id}")
11print(f"build_buildId: {buildIf.build_id}")
12print(f"build_alias: {buildIf.alias}")
自定义模版会为用户注入文件操作和代码执行的功能,如上基于browser-use构建的自定义模版,除了操作浏览器外、也能直接向沙箱发起文件操作和命令执行。
基于命令构建模版
用户可以在指定模版基础镜像的基础上,添加dockerfile命令,如下基于browser-use官方模版的基础上添加用户'testuser',并设置沙箱启动时用户为'testuser'
Python
1template = Template().from_template(
2 "browser-use-v1"
3).run_cmd("useradd -m -s /bin/bash testuser").set_user("testuser")
4
5buildIf = Template.build_in_background(template,
6 alias="browser_with_file_cmd",
7 cpu_count=2,
8 memory_mb=2048)
9
10print(f"build_templateId: {buildIf.template_id}")
11print(f"build_buildId: {buildIf.build_id}")
12print(f"build_alias: {buildIf.alias}")
Dockerfile指令和sdk命令映射关系
| Dockerfile | Sdk |
|---|---|
| Run | run_cmd() |
| WORKDIR | et_workdir() |
| USER | set_user() |
| ENV | set_envs() |
| CMD / ENTRYPOINT | set_start_cmd() |
当前暂不支持EXPOSE、VOLUME、COPY、ADD
查询模版列表、构建状态
后续用户可以在控制台查看自己的自定义模版和模版的构建状态,当前提供api的形式供用户临时查询模版和构建信息
工具类
template_info_manager.py
1"""
2Template Information Manager
3
4该工具类提供模版管理的高层接口,包括:
5- 获取所有模版列表
6- 根据模版名获取构建记录列表
7- 获取指定构建记录
8"""
9
10import os
11import requests
12from typing import Any, Dict, List, Optional
13from dataclasses import dataclass
14from enum import Enum
15
16
17class BuildStatus(str, Enum):
18 """构建状态枚举"""
19 BUILDING = "building"
20 READY = "ready"
21 ERROR = "error"
22
23
24@dataclass
25class TemplateInfo:
26 """模版信息"""
27 template_id: str
28 template_name: str
29 created_at: str
30 public: Optional[bool] = None
31 cpu_count: Optional[int] = None
32 memory_mb: Optional[int] = None
33
34
35@dataclass
36class BuildInfo:
37 """构建信息"""
38 build_id: str
39 template_id: str
40 status: str
41 cpu_count: Optional[int] = None
42 memory_mb: Optional[int] = None
43 errMsg: Optional[str] = None
44 created_at: Optional[str] = None
45 finished_at: Optional[str] = None
46 logs_count: Optional[int] = None
47
48
49class TemplateInfoManager:
50 """模版信息管理器"""
51
52 def __init__(
53 self,
54 api_key: Optional[str] = None,
55 domain: Optional[str] = None,
56 debug: bool = False,
57 timeout: int = 180
58 ):
59 """
60 初始化管理器
61
62 Args:
63 api_key: API密钥,如果不提供则从环境变量E2B_API_KEY读取
64 domain: 域名,如果不提供则从环境变量E2B_DOMAIN读取
65 debug: 是否启用调试模式
66 timeout: 请求超时时间(秒),默认180
67 """
68 self.api_key = api_key or os.environ.get("E2B_API_KEY")
69 # 处理域名,确保不会是空字符串
70 self.domain = domain or os.environ.get("E2B_DOMAIN")
71 self.debug = debug
72 self.timeout = timeout
73
74 if not self.api_key:
75 raise ValueError("API_KEY未设置")
76 if not self.domain:
77 raise ValueError("Domain未设置")
78 # 构建API base URL
79 self.api_url = f"https://api.{self.domain}"
80
81 # 构建请求头
82 self.headers = {
83 "X-API-Key": self.api_key,
84 "Content-Type": "application/json",
85 "Accept": "application/json",
86 }
87
88
89 def list_templates(self) -> List[TemplateInfo]:
90 """
91 获取所有模版列表
92
93 Args:
94 team_id: 可选的团队ID
95
96 Returns:
97 模版信息列表
98
99 Raises:
100 Exception: 当API调用失败时
101 """
102 url = f"{self.api_url}/templates"
103 params = {}
104
105 try:
106 response = requests.get(
107 url,
108 headers=self.headers,
109 params=params,
110 timeout=self.timeout
111 )
112
113 if response.status_code != 200:
114 raise Exception(
115 f"HTTP {response.status_code}: {response.text}"
116 )
117
118 data = response.json()
119
120 # 转换为TemplateInfo列表
121 templates = []
122 for item in data:
123 # 使用.get()避免缺少字段的问题
124 templates.append(TemplateInfo(
125 template_id=item.get("templateID", ""),
126 template_name=item.get("templateName", item.get("aliases", [""])[0] if item.get("aliases") else ""),
127 created_at=item.get("createdAt", ""),
128 public=item.get("public"),
129 cpu_count=item.get("cpuCount"),
130 memory_mb=item.get("memoryMB"),
131 ))
132
133 return templates
134
135 except requests.exceptions.RequestException as e:
136 raise Exception(f"调用模版列表API失败: {e}")
137 except Exception as e:
138 raise Exception(f"获取模版列表失败: {e}")
139
140 def get_builds_by_template(self, template_id: str) -> List[BuildInfo]:
141 """
142 根据模版ID获取构建列表(使用新的builds接口)
143
144 Args:
145 template_id: 模版ID
146
147 Returns:
148 构建信息列表
149
150 Raises:
151 Exception: 当API调用失败时
152 """
153 url = f"{self.api_url}/templates/{template_id}/builds"
154
155 try:
156 response = requests.get(
157 url,
158 headers=self.headers,
159 timeout=self.timeout
160 )
161
162 if response.status_code != 200:
163 raise Exception(
164 f"HTTP {response.status_code}: {response.text}"
165 )
166
167 data = response.json()
168
169 # 提取构建信息
170 builds = []
171 for build in data:
172 builds.append(BuildInfo(
173 build_id=build.get("buildID", ""),
174 template_id=template_id,
175 status=build.get("status", "unknown"),
176 cpu_count=build.get("cpuCount"),
177 memory_mb=build.get("memoryMB"),
178 created_at=build.get("createdAt", None),
179 finished_at=build.get("finishedAt", None),
180 errMsg=build.get("errorMessage", None),
181 logs_count=0, # 新接口不返回logs数量
182 ))
183
184 return builds
185
186 except requests.exceptions.RequestException as e:
187 raise Exception(f"调用构建列表API失败: {e}")
188 except Exception as e:
189 raise Exception(f"获取构建列表失败: {e}")
190
191 def get_build_status(
192 self,
193 template_id: str,
194 build_id: str,
195 logs_offset: int = 0,
196 level: Optional[str] = None
197 ) -> BuildInfo:
198 """
199 获取特定构建的状态和日志
200
201 Args:
202 template_id: 模版ID
203 build_id: 构建ID
204 logs_offset: 日志偏移量,默认0
205 level: 日志级别过滤 (可选: "debug", "info", "warn", "error")
206
207 Returns:
208 包含构建状态和日志的字典
209
210 Raises:
211 Exception: 当API调用失败时
212 """
213 url = f"{self.api_url}/templates/{template_id}/builds/{build_id}/status"
214 params = {"logsOffset": logs_offset}
215 if level:
216 params["level"] = level
217
218 try:
219 response = requests.get(
220 url,
221 headers=self.headers,
222 params=params,
223 timeout=self.timeout
224 )
225
226 if response.status_code != 200:
227 raise Exception(
228 f"HTTP {response.status_code}: {response.text}"
229 )
230
231 data = response.json()
232
233 # 提取构建信息
234 result = BuildInfo(
235 build_id=build_id,
236 template_id=template_id,
237 status=data.get("status", "unknown"),
238 cpu_count=data.get("cpuCount"),
239 memory_mb=data.get("memoryMB"),
240 created_at=data.get("createdAt", ""),
241 finished_at=data.get("finishedAt", ""),
242 errMsg=data.get("errorMessage", ""),
243 )
244
245 return result
246
247 except requests.exceptions.RequestException as e:
248 raise Exception(f"调用构建状态API失败: {e}")
249 except Exception as e:
250 raise Exception(f"获取构建状态失败: {e}")
测试脚本
test_template_info.py
1"""
2测试 template_info_manager 工具
3"""
4
5import os
6
7# 导入工具
8from template_info_manager import TemplateInfoManager
9
10# 设置测试环境变量(请替换为真实的API密钥)
11# 替换为对应区域的域名
12os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
13# 替换为用户自己的api_key
14os.environ["E2B_API_KEY"] = "bce-v3/****************************"
15
16
17def test_list_templates():
18 """测试获取模版列表"""
19 print("\n" + "=" * 70)
20 print("测试: 获取模版列表")
21 print("=" * 70)
22
23 try:
24 manager = TemplateInfoManager()
25 print(f"API URL: {manager.api_url}")
26
27 # 获取模版列表
28 templates = manager.list_templates()
29 print(f"\n找到 {len(templates)} 个模版")
30
31 if templates:
32 print(f"\n前{len(templates)}个模版:")
33 latest_custom_template = None
34 for template in templates[:]:
35 if not template.public:
36 latest_custom_template = template
37 print(f" - ID: {template.template_id}")
38 print(f" 名称: {template.template_name}")
39 print(f" 创建时间: {template.created_at}")
40 print(f" 模版类型: {"官方模版" if template.public else "自定义模版"}")
41 print(f" cpu: {template.cpu_count}")
42 print(f" mem_mb: {template.memory_mb}")
43 print()
44
45 return latest_custom_template
46 else:
47 print("无模版")
48 return None
49 except Exception as e:
50 print(f"错误: {e}")
51 import traceback
52 traceback.print_exc()
53 return None
54
55
56def test_get_builds_by_template(template_id):
57 """测试获取构建列表(使用新接口)"""
58 print("\n" + "=" * 70)
59 print("测试: 获取构建列表(新接口 GET /{templateID}/builds)")
60 print("=" * 70)
61
62 try:
63 manager = TemplateInfoManager()
64
65 # 使用新接口获取构建列表
66 builds = manager.get_builds_by_template(template_id)
67
68 print(f"\n模版ID: {template_id}")
69 print(f"构建数量: {len(builds)}")
70 #
71 if builds:
72 print("\n构建列表:")
73 for build in builds[:]: # 只显示前5个
74 print(f" - 构建ID: {build.build_id}")
75 print(f" 状态: {build.status}")
76 print(f" cpu_count: {build.cpu_count}")
77 print(f" mem_mb: {build.memory_mb}")
78 print(f" 创建时间: {build.created_at}")
79 print(f" 完成时间: {build.finished_at or '进行中'}")
80 print(f" error_msg: {build.errMsg or 'none'}")
81 print()
82 return builds[0]
83 else:
84 print(f"template{template_id} 无构建记录")
85 return None
86 except Exception as e:
87 print(f"错误: {e}")
88 import traceback
89 traceback.print_exc()
90 return None
91
92
93def test_get_build_status(template_id, build_id):
94 """测试获取构建状态"""
95 print("\n" + "=" * 70)
96 print("测试: 获取构建状态")
97 print("=" * 70)
98
99 try:
100 manager = TemplateInfoManager()
101
102 # 获取构建状态
103 status = manager.get_build_status(template_id, build_id)
104
105 print(f"\n构建ID: {status.build_id}")
106 print(f"模版ID: {status.template_id}")
107 print(f"状态: {status.status}")
108
109 # 使用格式化输出
110 # print("\n格式化输出:")
111 # manager.print_build_status(template_id, build_id)
112
113 except Exception as e:
114 print(f"错误: {e}")
115 import traceback
116 traceback.print_exc()
117
118
119if __name__ == "__main__":
120 print("\n" + "=" * 70)
121 print(" E2B Template Info Manager - 测试")
122 print("=" * 70)
123
124 # 测试1: 获取模版列表
125 template = test_list_templates()
126
127 if template:
128 # 测试2: 获取构建列表(新接口)
129 build = test_get_builds_by_template(template.template_id)
130
131 # 使用新接口返回的build进行后续测试
132 if build:
133 # 测试3: 获取构建状态
134 test_get_build_status(template.template_id, build.build_id)
135
136 print("\n" + "=" * 70)
137 print(" 测试完成!")
138 print("=" * 70)
使用自定义模版创建沙箱
如下是使用自定义模版创建沙箱的示例代码,执行文件操作、命令执行,针对用户模版中自定义的程序,用户可以使用sandbox.get_host(用户程序端口),获取用户程序的访问端点,sandbox.get_info()._envd_access_token获取操作沙箱的access_token,用户需要将获取的token拼接到请求头X-Access-Token中,否则会出现403错误,文件操作、命令执行无需获取端点和token,sdk自动注入。
Python
1import os
2import time
3from datetime import datetime
4
5from e2b_code_interpreter import Sandbox
6from e2b import FilesystemEventType
7
8# export E2B_DOMAIN="sandbox-execute.gz.baidubce.com"
9# export E2B_API_KEY="<你的 API Key>"
10os.environ["E2B_DOMAIN"]="sandbox-execute.gz.baidubce.com"
11os.environ["E2B_API_KEY"]="bce-v3/*************************"
12
13
14def main():
15 sandbox = Sandbox.create(
16 template="test_custom_template_online",
17 timeout=300,
18 )
19 vnc = sandbox.get_host(6080) # 浏览器相关沙箱,获取浏览器的vnc端点
20 https_vnc_url = f"https://{vnc}/vnc.html" # 拼接浏览器vnc链接
21 print(f"vncURL: {https_vnc_url}")
22 X_Access_Token = sandbox.get_info()._envd_access_token # 获取访问token,用户访问用户自定义程序
23 result = sandbox.commands.run("whoami", user="docker") # user指定执行命令的用户
24 print(result.stdout)
25
26 # 命令执行,使用模版中自带的python解释器执行命令
27 result = sandbox.commands.run("python3 -c \"print('Python3 is working!')\"", user="docker")
28 print(result.stdout)
29
30
31 # 文件操作
32 print("Creating directory 'test_dir' ...")
33 ret = sandbox.files.make_dir("test_dir", user="docker")
34 print("make_dir result:", ret)
35
36 # 写单文件
37 print("Writing file test_dir/qs3.txt ...")
38 sandbox.files.write(path="test_dir/qs3.txt", data="file content", user="docker")
39
40 # 读取文件
41 print("Reading test_dir/qs3.txt ...")
42 file_content = sandbox.files.read("test_dir/qs3.txt", user="docker")
43 print("Content of qs3.txt:", file_content)
44
45 # 获取文件信息
46 print("File info for test_dir/qs3.txt:")
47 info = sandbox.files.get_info("test_dir/qs3.txt", user="docker")
48 print(info)
49
50 # 列目录
51 print("\nListing user directory '/':")
52 user_info = sandbox.files.get_info("/home", user="docker")
53 print("user info:", user_info)
54
55 user_files = sandbox.files.list("/home/docker", user="docker")
56 print("user files:", user_files)
57
58 # 判断是否存在
59 print("\nChecking existence of test_dir/qs3.txt ...")
60 exists = sandbox.files.exists("test_dir/qs3.txt", user="docker")
61 print("exists?", exists)
62
63
64
65 # -------- 命令执行操作 --------
66
67 # 列出当前目录内容(详细)
68 print("Running 'ls -la' ...")
69 result = sandbox.commands.run("ls -la", user="docker")
70 print("stdout:\n", result.stdout)
71
72
73 print("Running 'echo hello; sleep 1; echo world' with streaming ...")
74 result = sandbox.commands.run(
75 "echo hello; sleep 1; echo world",
76 user="docker",
77 on_stdout=lambda data: print("STDOUT:", data),
78 on_stderr=lambda data: print("STDERR:", data),
79 )
80
81 # 结束沙箱
82 print("\nKilling sandbox...")
83 sandbox.kill()
84 print("Sandbox killed.")
85
86
87if __name__ == "__main__":
88 main()
说明
- 每个用户默认最多创建5个自定义模版,用户可以在同一个模版上执行多次构建,一个模版同时只允许存在一个正在构建的任务,用户最多同时存在两个正在构建的任务(不同模版),用户创建沙箱时默认使用最近一次成功的构建。
- 自定义模版的构建过程是异步过程,暂时还不支持查看构建日志,ready表示构建成功、building表示构建中、error表示构建失败。
- 在资源正常的情况下,700MiB镜像的构建时间大约为2min,2G镜像的构建时间大约为5min。
- 模版资源限制,cpu最少为2G,最大为16G,内存最小为2048MiB,最大为16384MiB(16G),cpu和内存比需按1:1/1:2/1:4的形式,例如cpu设置为2G,内存只能为2048、4096、8192。若需要使用16G cpu或16G memory,暂时只支持bj地域
| Cpu | Memory |
|---|---|
| 2 | 2048、4096、8192 |
| 4 | 4096、8192、16384 |
| 8 | 8192、16384 |
| 16 | 16384 |
