全栈应用服务器

  • 全栈应用服务器 > 使用指南 > 沙箱服务概述 > 挂载对象存储 Bucket

    挂载对象存储 Bucket

    最近更新时间: 2026-04-16 19:05:25

    概述

    沙箱支持通过 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 挂载。

    挂载步骤:

    1. 将 AccessKey 和 SecretKey 写入凭证文件,并设置权限为 600
    2. 使用 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();
    
    以上内容是否对您有帮助?