概述
沙箱支持通过 FUSE 技术将兼容 S3 协议的对象存储 Bucket 挂载到沙箱内部,像操作本地文件一样读写远端对象存储中的数据。七牛 Kodo 对象存储兼容 AWS S3 协议,可以直接使用 s3fs 工具进行挂载。
适用场景
- 需要在沙箱中访问大量预存数据(如数据集、模型文件)
- 多个沙箱共享同一份远端数据
- 沙箱产出的文件需要长期持久化到对象存储
注意事项
- 对象存储挂载基于网络传输,读写性能低于本地文件系统,不适合高频 I/O 场景
- 文件操作非原子性,存在本地操作成功但远端写入失败的风险
- 适合低频读写、对性能不敏感的数据访问场景
- 运行环境需要可用的 FUSE 设备(
/dev/fuse) - 使用
-o allow_other前,需要在环境中启用user_allow_other(见下文模板配置) - 建议在销毁沙箱前先执行卸载(
fusermount -u),减少未完成写入残留风险 - 示例中的环境变量在真实生产代码中应先校验格式并做 shell 参数转义
前置准备:创建包含 s3fs 的模板
在沙箱模板的 Dockerfile 中安装 s3fs 并完成 FUSE 相关配置。沙箱默认以 user 身份运行,因此需要在构建阶段提前处理好权限:
FROM e2b/base:latest
# 安装 s3fs
RUN DEBIAN_FRONTEND=noninteractive apt-get update && apt-get install -y s3fs && rm -rf /var/lib/apt/lists/*
# 启用 user_allow_other,允许非 root 用户使用 -o allow_other 挂载选项
RUN sed -i 's/#user_allow_other/user_allow_other/' /etc/fuse.conf
# 开放 FUSE 设备权限,使非 root 用户可以执行挂载
RUN chmod 666 /dev/fuse
# 预创建挂载目录并赋权给默认用户
RUN mkdir -p /mnt/bucket && chown user:user /mnt/bucket
构建包含 s3fs 的自定义模板后,使用该模板创建沙箱即可使用挂载功能。关于如何创建和构建自定义模板,请参考沙箱模板文档。
注意:如果不使用自定义模板,也可以在运行时通过 sudo 完成上述配置,但每次创建沙箱都需要重复执行,建议将配置固化到模板中。
挂载七牛 Kodo Bucket
七牛 Kodo 兼容 AWS S3 协议,使用对应区域的 S3 endpoint 即可通过 s3fs 挂载。
挂载步骤:
- 将 AccessKey 和 SecretKey 写入凭证文件,并设置权限为 600
- 使用
s3fs命令挂载 Bucket 到指定目录
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const KODO_ACCESS_KEY = process.env.KODO_ACCESS_KEY;
const KODO_SECRET_KEY = process.env.KODO_SECRET_KEY;
const KODO_BUCKET_NAME = process.env.KODO_BUCKET_NAME;
const KODO_S3_ENDPOINT = process.env.KODO_S3_ENDPOINT; // 例如:https://s3.cn-east-1.qiniucs.com
const MOUNT_DIR = "/mnt/bucket";
if (
!KODO_ACCESS_KEY ||
!KODO_SECRET_KEY ||
!KODO_BUCKET_NAME ||
!KODO_S3_ENDPOINT
) {
throw new Error(
"Missing required env vars: KODO_ACCESS_KEY, KODO_SECRET_KEY, KODO_BUCKET_NAME, KODO_S3_ENDPOINT",
);
}
// 生产环境建议:插入 shell 命令前,应先校验并转义用户可控参数。
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
// 写入凭证文件(沙箱默认用户为 user)
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${KODO_ACCESS_KEY}:${KODO_SECRET_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
// 挂载 Bucket(挂载目录已在模板 Dockerfile 中预创建)
await sandbox.commands.run(
`s3fs ${shellEscape(KODO_BUCKET_NAME)} ${MOUNT_DIR} -o url=${shellEscape(KODO_S3_ENDPOINT)} -o allow_other -o use_path_request_style -o passwd_file=/home/user/.passwd-s3fs`,
);
// 等待挂载就绪(s3fs 初始化需要几秒)
await sandbox.commands.run(
`for i in $(seq 1 10); do mountpoint -q ${MOUNT_DIR} && touch ${MOUNT_DIR}/.ready 2>/dev/null && rm -f ${MOUNT_DIR}/.ready && break; sleep 1; done`,
);
// 验证挂载结果
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
// 像本地文件一样读写
await sandbox.commands.run(`echo "hello kodo" > ${MOUNT_DIR}/test.txt`);
const result = await sandbox.commands.run(`cat ${MOUNT_DIR}/test.txt`);
console.log(result.stdout); // 输出:hello kodo\n
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();
参数说明
| 参数 | 说明 |
|---|---|
KODO_ACCESS_KEY |
七牛 AccessKey |
KODO_SECRET_KEY |
七牛 SecretKey |
KODO_BUCKET_NAME |
Bucket 名称 |
KODO_S3_ENDPOINT |
S3 兼容 endpoint,如 https://s3.cn-east-1.qiniucs.com |
MOUNT_DIR |
沙箱内的挂载目录路径(需在模板中预创建) |
s3fs 挂载选项
| 选项 | 说明 |
|---|---|
-o url |
S3 兼容服务的 endpoint 地址 |
-o allow_other |
允许其他用户访问挂载目录(需启用 user_allow_other) |
-o use_path_request_style |
使用 path-style URL(七牛 Kodo 需要此选项) |
-o passwd_file |
指定凭证文件路径(默认为 ~/.passwd-s3fs) |
更多 s3fs 配置和用法请参考七牛 Kodo S3FS 使用指南。
S3 兼容服务域名
KODO_S3_ENDPOINT 需要填写 Bucket 所在区域对应的 S3 兼容域名,以下为各区域域名:
| 存储区域 | Region ID | Endpoint |
|---|---|---|
| 华东-浙江 | cn-east-1 | https://s3.cn-east-1.qiniucs.com |
| 华东-浙江2 | cn-east-2 | https://s3.cn-east-2.qiniucs.com |
| 华北-河北 | cn-north-1 | https://s3.cn-north-1.qiniucs.com |
| 华南-广东 | cn-south-1 | https://s3.cn-south-1.qiniucs.com |
| 北美-洛杉矶 | us-north-1 | https://s3.us-north-1.qiniucs.com |
| 亚太-新加坡 | ap-southeast-1 | https://s3.ap-southeast-1.qiniucs.com |
| 亚太-河内 | ap-southeast-2 | https://s3.ap-southeast-2.qiniucs.com |
| 亚太-胡志明 | ap-southeast-3 | https://s3.ap-southeast-3.qiniucs.com |
完整域名列表请参考七牛 Kodo S3 兼容服务域名。
挂载 AWS S3 Bucket
s3fs 同样支持挂载 AWS S3,挂载方式类似,只需替换凭证和 endpoint 信息。
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const AWS_ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID;
const AWS_SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY;
const AWS_BUCKET_NAME = process.env.AWS_BUCKET_NAME;
const AWS_REGION = process.env.AWS_REGION || "us-east-1";
const MOUNT_DIR = "/mnt/bucket";
if (!AWS_ACCESS_KEY_ID || !AWS_SECRET_ACCESS_KEY || !AWS_BUCKET_NAME) {
throw new Error(
"Missing required env vars: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_BUCKET_NAME",
);
}
// 生产环境建议:插入 shell 命令前,应先校验并转义用户可控参数。
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
// 写入凭证文件(沙箱默认用户为 user)
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
// 挂载 Bucket
await sandbox.commands.run(
`s3fs ${shellEscape(AWS_BUCKET_NAME)} ${MOUNT_DIR} -o allow_other -o endpoint=${shellEscape(AWS_REGION)} -o url=${shellEscape(`https://s3.${AWS_REGION}.amazonaws.com`)} -o passwd_file=/home/user/.passwd-s3fs`,
);
// 验证挂载结果
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();
挂载其他 S3 兼容存储
任何兼容 AWS S3 协议的对象存储服务都可以通过 s3fs 挂载。除替换 url、AccessKey、SecretKey 外,建议明确访问风格:
- 当服务要求 path-style 访问时,增加
-o use_path_request_style - 当服务支持 virtual-hosted-style 时,可不加
-o use_path_request_style
通用示例:
import "dotenv/config";
import { Sandbox } from "@e2b/code-interpreter";
async function main() {
const S3_ACCESS_KEY = process.env.S3_ACCESS_KEY;
const S3_SECRET_KEY = process.env.S3_SECRET_KEY;
const S3_BUCKET_NAME = process.env.S3_BUCKET_NAME;
const S3_ENDPOINT_URL = process.env.S3_ENDPOINT_URL; // 例如:https://minio.example.com
const MOUNT_DIR = "/mnt/bucket";
if (!S3_ACCESS_KEY || !S3_SECRET_KEY || !S3_BUCKET_NAME || !S3_ENDPOINT_URL) {
throw new Error(
"Missing required env vars: S3_ACCESS_KEY, S3_SECRET_KEY, S3_BUCKET_NAME, S3_ENDPOINT_URL",
);
}
// 生产环境建议:插入 shell 命令前,应先校验并转义用户可控参数。
const shellEscape = (value) => `'${value.replace(/'/g, `'\\''`)}'`;
const sandbox = await Sandbox.create("your-s3fs-template");
try {
await sandbox.files.write(
"/home/user/.passwd-s3fs",
`${S3_ACCESS_KEY}:${S3_SECRET_KEY}`,
);
await sandbox.commands.run("chmod 600 /home/user/.passwd-s3fs");
await sandbox.commands.run(
`s3fs ${shellEscape(S3_BUCKET_NAME)} ${MOUNT_DIR} -o url=${shellEscape(S3_ENDPOINT_URL)} -o allow_other -o use_path_request_style -o passwd_file=/home/user/.passwd-s3fs`,
);
const files = await sandbox.commands.run(`ls ${MOUNT_DIR}`);
console.log("Bucket contents:", files.stdout);
} finally {
await sandbox.commands.run(`fusermount -u ${MOUNT_DIR}`).catch(() => {});
await sandbox.kill();
}
}
main();
文档反馈
(如有产品使用问题,请 提交工单)