动态挂载 JuiceFS

更新时间:
复制 MD 格式

创建 Sandbox 时,可通过 metadata 将 JuiceFS 文件系统或其子目录挂载到 Sandbox 内的本地目录,无需预先创建 Volume。

功能介绍

创建 Sandbox 时,可以通过 metadata 将 JuiceFS 文件系统或其子目录挂载到 Sandbox 内,无需预先创建 Volume。挂载后,应用通过本地挂载目录访问数据。

如需向运行中的 Sandbox 增加挂载,请参见追加挂载 JuiceFS。

适用范围

  • 已在 JuiceFS 企业版控制台创建文件系统,并获取文件系统名称、访问 Token 和服务地址。操作方法参见 JuiceFS 企业版快速上手。

  • 已准备与 JuiceFS 服务网络连通的 VPC(Virtual Private Cloud,专有网络)、交换机和安全组。

  • 已准备智能体沙箱 API Key 和第二代运行时(MicroVM)自定义模板。

JuiceFS 通过 Token 访问文件系统,挂载 JuiceFS 本身不要求配置 RAM(Resource Access Management,访问控制)角色。

第二代运行时镜像要求

必须使用第二代运行时(MicroVM)自定义模板。推荐在构建模板时设置 buildConfig.installStorageClients: true,由 Template Build 自动安装 JuiceFS 企业版客户端、RADOS 运行库和 FUSE 2。客户端安装方法参见挂载 JuiceFS Volume 中的“创建模板时预装存储客户端”章节。

安装 SDK

创建并激活 Python 虚拟环境,然后安装 E2B SDK:

python3 -m venv .venv
source .venv/bin/activate
pip install e2b==2.31.0

挂载配置

创建 Sandbox 时,在 metadata 中提供以下配置:

metadata 键

值的格式

说明

fc.sandbox.storage.juicefs

JSON 字符串

JuiceFS 挂载配置,字段见下表。

fc.sandbox.network.vpc

JSON 字符串

完整 VPC 配置,包含 vpcId、securityGroupId 和非空的 vSwitchIds。

创建时直接挂载,需同时通过 fc.sandbox.network.vpc 提供完整 VPC 配置,值为 JSON 字符串。模板或同一请求中 Volume 的 VPC 配置不能替代该 metadata。

fc.sandbox.storage.juicefs 的 JSON 结构如下。提交时需将其序列化为字符串,不能直接传入 Python 字典或 JavaScript 对象:

{
  "mountPoints": [
    {
      "volumeName": "<JUICEFS-FILE-SYSTEM-NAME>",
      "remoteDir": "/",
      "mountDir": "/mnt/juicefs",
      "token": "<JUICEFS-TOKEN>",
      "args": []
    }
  ],
  "envs": {
    "BASE_URL": "https://<JUICEFS-SERVICE-ADDRESS>"
  }
}

字段

类型

是否必填

说明

mountPoints

对象数组

是

JuiceFS 挂载点列表,最多包含 5 个挂载点。

mountPoints[].volumeName

字符串

是

JuiceFS 文件系统名称,不是智能体沙箱 Volume 名称或 ID。

mountPoints[].remoteDir

字符串

否

JuiceFS 文件系统中要挂载的远端目录,例如 /datasets/project-a。如果目录不存在,挂载时会自动创建。建议显式设置。

mountPoints[].mountDir

字符串

是

Sandbox 内的本地挂载目录,必须是绝对路径,例如 /mnt/juicefs。

mountPoints[].token

字符串

是

JuiceFS 文件系统的访问 Token。

mountPoints[].args

字符串数组

否

传递给 JuiceFS 客户端的额外挂载参数,可以为空数组。平台根据 token 和 remoteDir 管理 --token 和 --subdir,不能通过该字段覆盖这两个参数。

envs

对象

是

仅传递给 JuiceFS 挂载进程的环境变量,不会设置到 Sandbox 用户进程中。

envs.BASE_URL

字符串

是

JuiceFS 企业版客户端访问的服务地址。字段名区分大小写。

动态挂载通过 envs.BASE_URL 指定 JuiceFS 服务地址,无需在创建请求中填写 Volume 的 baseURL 字段;与已有 JuiceFS Volume 组合挂载时,两者取值仍须一致。

args 是传递给 JuiceFS 客户端的额外挂载参数。本文示例使用环境变量 JUICEFS_ARGS_JSON 传入该数组;不需要额外参数时设置为 [],不能设置为空字符串或 JSON null,也不能覆盖平台管理的 --token 和 --subdir 参数。

不要在日志中打印完整 metadata、JuiceFS Token 或其他凭证。

挂载远端子目录

remoteDir 是 JuiceFS 文件系统中的远端目录,mountDir 是 Sandbox 内的本地挂载目录。例如,设置 remoteDir 为 /datasets/project-a、mountDir 为 /mnt/juicefs 后,应用通过 /mnt/juicefs 访问该远端子目录。

远端目录须使用以 / 开头的绝对路径。如果目录不存在,挂载时会自动创建;Token 需具备创建和访问该目录的权限。

本地挂载目录

mountDir 表示 Sandbox 内的本地挂载目录,远端目录通过存储配置单独指定。建议使用 /home、/mnt、/tmp 或 /data 的子目录,避免覆盖模板内已有内容。目录限制参见使用限制。

环境变量说明

环境变量

用途

取值来源或填写方式

E2B_API_KEY

调用智能体沙箱接口的 API Key。

在智能体沙箱控制台创建,使用目标 Team 的 API Key。

E2B_API_URL

智能体沙箱 E2B API 地址。

https://api.<REGION>.sandbox.aliyuncs.com,将 <REGION> 替换为目标地域。

E2B_DOMAIN

SDK 访问 Sandbox 的域名。

<REGION>.sandbox.aliyuncs.com,与 API 地址使用相同地域,不含协议或 api. 前缀。

E2B_TEMPLATE

创建 Sandbox 使用的模板 ID 或别名。

在智能体沙箱控制台选择满足本文客户端要求的模板。

SANDBOX_VPC_ID

Sandbox 所在的 VPC。

在专有网络控制台获取,需与目标存储网络连通。

SANDBOX_SECURITY_GROUP_ID

Sandbox 使用的安全组。

在 ECS 控制台获取,需属于所选 VPC,并允许访问目标存储。

SANDBOX_VSWITCH_ID

Sandbox 使用的交换机。

在专有网络控制台获取,需属于所选 VPC。

JUICEFS_BASE_URL

JuiceFS 企业版服务地址。

从 JuiceFS 企业版服务配置中获取,需在所选 VPC 内可达。

JUICEFS_VOLUME_NAME

JuiceFS 文件系统名称。

在 JuiceFS 企业版控制台获取,不是智能体沙箱 Volume 名称。

JUICEFS_TOKEN

访问 JuiceFS 文件系统的 Token。

在 JuiceFS 企业版控制台获取,需具备访问目标目录的权限。

JUICEFS_REMOTE_DIR

JuiceFS 文件系统中的远端目录。

按任务指定,例如 /datasets/project-a;/ 表示根目录。

JUICEFS_MOUNT_DIR

Sandbox 内的本地挂载目录。

按应用访问路径设置,例如 /mnt/juicefs。

JUICEFS_ARGS_JSON

JuiceFS 客户端的额外挂载参数。

按需设置为 JSON 字符串数组;不需要额外参数时使用 []。

挂载并验证

先设置环境变量,替换示例中的占位符;API 地址、模板和存储需使用匹配的地域及网络配置:

export E2B_API_KEY="<YOUR-E2B-API-KEY>"
export E2B_API_URL="https://api.<REGION>.sandbox.aliyuncs.com"
export E2B_DOMAIN="<REGION>.sandbox.aliyuncs.com"
export E2B_TEMPLATE="<MICROVM-TEMPLATE-ID>"

export SANDBOX_VPC_ID="vpc-xxxxxxxx"
export SANDBOX_SECURITY_GROUP_ID="sg-xxxxxxxx"
export SANDBOX_VSWITCH_ID="vsw-xxxxxxxx"

export JUICEFS_BASE_URL="https://<JUICEFS-SERVICE-ADDRESS>"
export JUICEFS_VOLUME_NAME="<JUICEFS-FILE-SYSTEM-NAME>"
export JUICEFS_TOKEN="<JUICEFS-TOKEN>"
export JUICEFS_REMOTE_DIR="/"
export JUICEFS_MOUNT_DIR="/mnt/juicefs"

export JUICEFS_ARGS_JSON="[]"

示例会在挂载目录中创建带随机标识的独立测试文件,写入并读取校验后删除该文件,再释放本次创建的 Sandbox。请使用具备读写权限的挂载配置。

将以下代码保存为 14_sandbox_juicefs.py:

import json
import os
from uuid import uuid4

from e2b import Sandbox


def require_env(name: str) -> str:
    value = os.environ.get(name, "").strip()
    if not value:
        raise RuntimeError(f"缺少环境变量: {name}")
    return value


def juicefs_args() -> list[str]:
    value = json.loads(require_env("JUICEFS_ARGS_JSON"))
    if not isinstance(value, list) or not all(isinstance(item, str) for item in value):
        raise RuntimeError("JUICEFS_ARGS_JSON 必须是字符串数组")

    managed_options = ("--token", "--subdir")
    for item in value:
        if any(item == option or item.startswith(f"{option}=") for option in managed_options):
            raise RuntimeError(f"JUICEFS_ARGS_JSON 不能覆盖平台托管参数: {item}")
    return value


mount_dir = require_env("JUICEFS_MOUNT_DIR")
marker_path = f"{mount_dir}/hello-juicefs-{uuid4().hex}.txt"

vpc_config = {
    "vpcId": require_env("SANDBOX_VPC_ID"),
    "securityGroupId": require_env("SANDBOX_SECURITY_GROUP_ID"),
    "vSwitchIds": [require_env("SANDBOX_VSWITCH_ID")],
}

juicefs_config = {
    "mountPoints": [
        {
            "volumeName": require_env("JUICEFS_VOLUME_NAME"),
            "remoteDir": require_env("JUICEFS_REMOTE_DIR"),
            "mountDir": mount_dir,
            "token": require_env("JUICEFS_TOKEN"),
            "args": juicefs_args(),
        }
    ],
    "envs": {
        "BASE_URL": require_env("JUICEFS_BASE_URL"),
    },
}

sandbox = None
marker_written = False

try:
    sandbox = Sandbox.create(
        template=require_env("E2B_TEMPLATE"),
        timeout=300,
        api_key=require_env("E2B_API_KEY"),
        api_url=require_env("E2B_API_URL"),
        domain=require_env("E2B_DOMAIN"),
        metadata={
            "fc.sandbox.network.vpc": json.dumps(vpc_config),
            "fc.sandbox.storage.juicefs": json.dumps(juicefs_config),
        },
    )

    sandbox.files.write(marker_path, "hello juicefs\n")
    marker_written = True
    content = sandbox.files.read(marker_path)
    if content != "hello juicefs\n":
        raise RuntimeError(f"文件内容不一致: {content!r}")
finally:
    try:
        if sandbox is not None and marker_written:
            sandbox.files.remove(marker_path)
    finally:
        if sandbox is not None:
            sandbox.kill()

print("JuiceFS 动态挂载读写验证成功")

在已激活的 Python 虚拟环境中运行示例:

python 14_sandbox_juicefs.py

输出 JuiceFS 动态挂载读写验证成功 表示本次读写、测试文件清理和 Sandbox 释放已完成。

行为说明

  • Sandbox 暂停后再恢复时会恢复 JuiceFS 挂载。

  • 释放 Sandbox 不会删除底层存储数据。测试文件由示例主动删除,其他数据的保留和清理需通过存储服务或挂载目录单独处理。

使用限制

  • 本地挂载目录必须是规范化的绝对 Unix 路径,不能为 /,不能包含前后空格、.、.. 或重复的路径分隔符。

  • 本地挂载目录不能使用 /bin、/opt、/var、/dev 等系统目录及其子目录,也不能包含 .cache 等隐藏目录。如需通过隐藏目录访问数据,可先挂载到符合要求的目录,再在隐藏目录路径下创建指向该挂载目录的符号链接。

  • 同一个 Sandbox 中的本地挂载目录不能重复,包括不同存储类型的挂载目录。

  • 同一个 Sandbox 最多包含 5 个 JuiceFS 挂载点,按创建时的挂载点与后续追加的挂载点累计计算,包括直接配置和引用 Volume 的挂载。

  • 多个 JuiceFS 挂载点必须使用相同的服务地址;与已有 JuiceFS Volume 组合挂载时,envs.BASE_URL 必须与 Volume 的 baseURL 一致。

常见问题

已配置 VPC,为什么仍提示配置不完整

错误消息包含 mount requires complete VPC config,表示本次创建使用的 VPC 配置缺少必填项。

在本次创建请求的 metadata 中,通过 fc.sandbox.network.vpc 传入包含 vpcId、securityGroupId 和非空 vSwitchIds 的 JSON 字符串。创建时直接挂载,需同时提供这项 metadata,模板或同一请求中 Volume 的 VPC 配置均不能替代。

Sandbox 创建超时或挂载失败

根据错误消息检查对应配置;消息未明确指出原因时,可按以下顺序排查:

  1. 按本文镜像要求验证 JuiceFS 企业版客户端、RADOS 运行库和 FUSE 2。

  2. 检查服务地址、VPC 路由和安全组,确认 Sandbox 能访问 JuiceFS 服务。

  3. 核对 Token、文件系统名称及远端目录,确认 Token 允许访问目标目录。

如需进一步排查,请保留完整错误信息和请求 ID。