自定义沙箱 快速入门
概览
本文将介绍如何使用sdk在沙箱服务创建自定义模版,以支持用户扩展沙箱功能。
说明:在构建自定义模版时沙箱服务会为用户的模版注入命令执行、文件操作的功能,用户无需在自己的模版内构建相关程序。
安装依赖
执行如下命令安装依赖
1pip install e2b
1npm install e2b
指定镜像构建模版
基于ccr镜像仓库中的镜像构建模版,注意镜像仓库需要开通公网以及访问权限,否则沙箱服务无法拉取用户镜像
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}")
针对私有镜像,用户需要指定镜像仓库的账号密码,否则沙箱服务无法拉取用户镜像
1# 替换为用户镜像仓库的账号和密码
2template = Template().from_image(
3 image="ccr-*****-pub.cnc.bj.baidubce.com/******/sandbox:v1",
4 username="******",
5 password="*****"
6)
基于模版构建新模版
用户在自己已有模版或者官方模版的基础上构建新模版,如下以基于官方模版browser-use为例
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'
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 | set_workdir() |
| USER | set_user() |
| ENV | set_envs() |
| CMD / ENTRYPOINT | set_start_cmd() |
当前暂不支持EXPOSE、VOLUME、COPY、ADD
创建沙箱快照模版
用户可以基于正在运行的沙箱创建模版,沙箱服务会对正在运行的沙箱执行快照功能,并将其保存为模版,用户后续可以使用该模版创建新的沙箱,此处以api形式提供该功能
1POST /v1/sandbox/templates/snapshot HTTP/1.1
2Host: sandbox-execute.gz.baidubce.com
3Authorization/X-API-Key: 用户自己的api_key
4
5{
6 "templateId": "test_snapshot_template", # 要创建的模版id
7 "sandboxId": "xjaksdjwqdkdca" # 正在运行的沙箱
8}
请求头域
除公共头域外,无其它特殊头域。
请求参数
| 参数名称 | 类型 | 是否必需 | 参数位置 | 描述 |
|---|---|---|---|---|
| templateId | String | 是 | Body参数 | 要创建的模版名 |
| sandboxId | String | 是 | Body参数 | 正在运行的沙箱 |
响应头域
除公共头域,无其它特殊头域。
响应参数 无
工具脚本
1import os
2import requests
3from typing import Any, Dict
4
5
6class TemplateManager:
7 @classmethod
8 def create_snapshot_template(
9 cls,
10 template_id: str,
11 sandbox_id: str,
12 timeout: int = 180,
13 ) -> Dict[str, Any]:
14 e2b_domain = os.environ.get("E2B_DOMAIN")
15 e2b_api_key = os.environ.get("E2B_API_KEY")
16
17 if not e2b_api_key:
18 raise ValueError("E2B_API_KEY未设置")
19 if not e2b_domain:
20 raise ValueError("E2B_DOMAIN未设置")
21
22 if not template_id:
23 raise ValueError("template_id不能为空")
24 if not sandbox_id:
25 raise ValueError("sandbox_id不能为空")
26
27 api_domain = f"api.{e2b_domain}"
28 url = f"https://{api_domain}/v1/sandbox/templates/snapshot"
29
30 headers = {
31 "X-API-Key": e2b_api_key,
32 "Content-Type": "application/json",
33 "Accept": "application/json"
34 }
35
36 payload = {
37 "templateId": template_id,
38 "sandboxId": sandbox_id,
39 }
40
41 try:
42 response = requests.post(url, headers=headers, json=payload, timeout=timeout)
43 except requests.exceptions.RequestException as e:
44 raise Exception(f"调用创建快照模版接口失败: {e}")
45
46 if response.status_code != 201:
47 raise Exception(
48 f"创建快照模版失败: HTTP {response.status_code}, "
49 f"响应: {response.text}"
50 )
51
52 if not response.text:
53 return {}
54
55 try:
56 return response.json()
57 except ValueError:
58 return {}
59
60 @classmethod
61 def delete_template(
62 cls,
63 template_id: str,
64 timeout: int = 180,
65 ) -> None:
66 """Delete a snapshot template
67
68 Args:
69 template_id: The ID of the template to delete
70 timeout: Request timeout in seconds (default: 180)
71
72 Raises:
73 ValueError: If required environment variables or parameters are missing
74 Exception: If the API request fails
75 """
76 e2b_domain = os.environ.get("E2B_DOMAIN")
77 e2b_api_key = os.environ.get("E2B_API_KEY")
78
79 if not e2b_api_key:
80 raise ValueError("E2B_API_KEY未设置")
81 if not e2b_domain:
82 raise ValueError("E2B_DOMAIN未设置")
83
84 if not template_id:
85 raise ValueError("template_id不能为空")
86
87 api_domain = f"api.{e2b_domain}"
88 url = f"https://{api_domain}/v1/sandbox/templates/{template_id}"
89
90 headers = {
91 "X-API-Key": e2b_api_key,
92 "Content-Type": "application/json",
93 "Accept": "application/json"
94 }
95
96 try:
97 response = requests.delete(url, headers=headers, timeout=timeout)
98 except requests.exceptions.RequestException as e:
99 raise Exception(f"调用删除模版接口失败: {e}")
100
101 if response.status_code != 204:
102 raise Exception(
103 f"删除模版失败: HTTP {response.status_code}, "
104 f"响应: {response.text}"
105 )
测试脚本
1import os
2from datetime import datetime
3
4from e2b_code_interpreter import Sandbox
5from templateManager import TemplateManager
6
7# Set up environment variables
8os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
9os.environ["E2B_API_KEY"] = "bce-v3/************"
10
11
12def create_template_from_sandbox(templateId: str):
13 """
14 Test Case 1: Create a sandbox, execute commands, then create a template from it
15
16 This test verifies the workflow:
17 1. Create a code sandbox
18 2. Run commands to set up sandbox state
19 3. Create a snapshot template from the sandbox
20 """
21
22 print("\n=== Test Case 1: Create Template from Sandbox ===")
23
24 # Step 1: Create a new sandbox
25 print("Step 1: Creating sandbox...")
26 start = datetime.now()
27 sandbox = Sandbox.create(
28 template="code-interpreter-v1",
29 timeout=int(os.environ.get("SANDBOX_TIMEOUT", "600")),
30 headers={"X-BCE-AGENT-SANDBOX-GRAY": "TRUE"},
31 )
32 end = datetime.now()
33 info = sandbox.get_info()
34 sandbox_id = info.sandbox_id
35 print(f"✓ Sandbox created: {sandbox_id}, time_diff{end - start}")
36
37 # Step 2: Run commands in sandbox to set up state
38 print("Step 2: Setting up sandbox state...")
39 result = sandbox.commands.run("echo hello-from-sandbox > /home/user/hello.txt; ls -la /home/user")
40 print(f"✓ Command executed:\n{result.stdout}")
41
42 # Step 3: Create snapshot template from sandbox
43 print(f"Step 3: Creating snapshot template '{templateId}' from sandbox...")
44 resp = TemplateManager.create_snapshot_template(
45 template_id=templateId,
46 sandbox_id=sandbox_id,
47 )
48 print(f"Response: {resp}")
49
50 # Step 4: Clean up
51 print("Step 4: Cleaning up...")
52 sandbox.kill()
53 print("✓ Sandbox killed")
54
55
56if __name__ == "__main__":
57 create_template_from_sandbox("custom_snapshot_template")
注意:与其他模版不同,快照模版目前是同步创建,创建完成后用户可以在控制台查看,使用方式与其他自定义模版无区别。
自定义模版ReadyCommand
为了确保用户自定义模版沙箱创建时,沙箱内的程序处于ready状态,即沙箱创建成功即可访问沙箱内的自定义程序,此处提供readyCommand的支持,用户可以在构建自定义模版时自定义readyCommad,沙箱创建时系统会等待readyCommand执行成功后才返回沙箱。
1from e2b import Template, wait_for_timeout, wait_for_process, wait_for_file, wait_for_timeout
2
3import os
4
5os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
6os.environ["E2B_API_KEY"] = "bce-v3/*********************"
7
8template = Template().from_image(
9 image="ccr-*************.cnc.gz.baidubce.com/**********/ubuntu2204_python312:v1",
10).set_ready_cmd("sleep 3") # sleep 3秒后启动,等价于wiat_for_timeout(3000)
11#
12buildIf = Template.build_in_background(template,
13 alias="template_with_python312",
14 cpu_count=2,
15 memory_mb=4096)
Sdk ReadyCommand和系统命令映射关系
| Sdk | 系统命令 |
|---|---|
| wait_for_timeou(3000) | sleep 3 |
| wait_for_prot(8080) | ss -tuln | grep :8080 |
| wait_for_file("/tmp/ready") | [ -f /tmp/ready ] |
| wait_for_process("python") | pgrep python > /dev/null |
查询模版列表、构建状态
用户可以在cfc控制台查看自定义模版列表及构建状态

使用自定义模版创建沙箱
如下是使用自定义模版创建沙箱的示例代码,执行文件操作、命令执行,针对用户模版中自定义的程序,用户可以使用sandbox.get_host(用户程序端口),获取用户程序的访问端点,sandbox.get_info()._envd_access_token获取操作沙箱的access_token,用户需要将获取的token拼接到请求头X-Access-Token中,否则会出现403错误,文件操作、命令执行无需获取端点和token,sdk自动注入。
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。
| Cpu | Memory |
|---|---|
| 2 | 2048、4096、8192 |
| 4 | 4096、8192、16384 |
| 8 | 8192、16384 |
| 16 | 16384 |
