追加挂载 JuiceFS

更新时间:
复制 MD 格式

Sandbox 处于运行中状态时,可通过追加挂载接口增加 JuiceFS 挂载,无需重新创建 Sandbox。

功能介绍

Sandbox 处于运行中(running)状态时,可以增加 JuiceFS 挂载,无需重新创建 Sandbox。追加时可以直接提供 JuiceFS 挂载配置,也可以按名称引用已有的智能体沙箱 Volume(JuiceFS 类型)。

创建 Sandbox 时直接提供挂载配置的方法,参见动态挂载 JuiceFS。

适用范围

  • Sandbox 处于运行中状态。已暂停的 Sandbox 需要先恢复运行。

  • 请求使用的智能体沙箱 API Key 与目标 Sandbox 属于同一 Team。

  • Sandbox 使用第二代运行时(MicroVM)自定义模板,并已安装 JuiceFS 企业版客户端、RADOS 运行库和 FUSE 2。镜像要求参见挂载 JuiceFS Volume。

  • Sandbox 已配置可访问 JuiceFS 服务的完整 VPC(Virtual Private Cloud,专有网络)信息,包括 vpcId、securityGroupId 和非空的 vSwitchIds。

  • 直接提供配置时,已准备 JuiceFS 文件系统名称、服务地址及有权访问目标目录的 Token。引用已有 Volume 时,已在同一 Team 中创建 JuiceFS Volume,并获取可用 Volume 的名称。

追加接口沿用 Sandbox 当前的 VPC 配置,不会用新增 Volume 的 mountConfig.vpcConfig 替换它。缺少所需 VPC 配置时,需要重新创建 Sandbox。创建时的配置方法参见动态挂载 JuiceFS和挂载 JuiceFS Volume。

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

接口与参数

POST /sandboxes/{sandboxID}/fc-volume-mounts

请求头需要提供 X-API-Key 和 Content-Type: application/json。接口成功时返回 204 No Content,响应体为空。

请求体支持直接提供配置和引用已有 Volume,两种方式可以在同一次请求中组合使用:

字段

类型

是否必填

说明

inlineVolumeMounts.juiceFS

对象

与 namedVolumeMounts 至少提供一种。

直接提供 JuiceFS 挂载配置,字段见下表。

namedVolumeMounts

对象数组

与 inlineVolumeMounts.juiceFS 至少提供一种。

按名称引用已有 Volume。

namedVolumeMounts[].name

字符串

引用 Volume 时必填。

同一 Team 中的 Volume 名称,不使用 Volume ID。

namedVolumeMounts[].path

字符串

引用 Volume 时必填。

Sandbox 内的本地挂载目录。

请求至少需要包含一个有效挂载点。追加请求中的挂载配置是 JSON 对象,不使用创建 Sandbox 时的 metadata 或 JSON 字符串格式。字段名区分大小写:创建时的 metadata 键为 fc.sandbox.storage.juicefs,追加请求中的字段为 juiceFS。

JuiceFS 挂载参数

以下字段位于 inlineVolumeMounts.juiceFS 中;选择直接提供配置时,按表中要求填写:

字段

类型

是否必填

说明

inlineVolumeMounts.juiceFS.envs

对象

条件必填

仅传递给 JuiceFS 挂载进程的环境变量。Sandbox 尚未配置 JuiceFS 服务地址时,需要通过 envs.BASE_URL 提供。

inlineVolumeMounts.juiceFS.envs.BASE_URL

字符串

条件必填

JuiceFS 企业版客户端访问的服务地址。已有和新增挂载必须使用相同的地址。

inlineVolumeMounts.juiceFS.mountPoints

对象数组

是

本次请求的 JuiceFS 挂载点列表,包含 1~5 个挂载点;已有与新增 JuiceFS 挂载点累计不能超过 5 个。

inlineVolumeMounts.juiceFS.mountPoints[].volumeName

字符串

是

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

inlineVolumeMounts.juiceFS.mountPoints[].remoteDir

字符串

否

JuiceFS 文件系统中的远端目录,建议显式设置。

inlineVolumeMounts.juiceFS.mountPoints[].mountDir

字符串

是

Sandbox 内的本地挂载目录,须符合使用限制中的目录要求。

inlineVolumeMounts.juiceFS.mountPoints[].token

字符串

是

JuiceFS 文件系统的访问 Token。

inlineVolumeMounts.juiceFS.mountPoints[].args

字符串数组

否

传递给 JuiceFS 客户端的额外挂载参数。不能重复提供平台管理的 --token 和 --subdir 参数。

不要在日志中打印 Token 或完整请求体。

本地挂载目录

mountDir 和 namedVolumeMounts[].path 都表示 Sandbox 内的本地挂载目录。建议使用 /home、/mnt、/tmp 或 /data 的子目录,目录限制参见使用限制。

安装 SDK

示例使用 httpx 调用追加挂载接口,成功后通过 E2B SDK 连接已有 Sandbox,验证文件读写。

pip install "e2b==2.31.0" httpx

环境变量说明

环境变量

用途

取值来源或填写方式

E2B_API_KEY

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

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

E2B_API_URL

智能体沙箱 E2B API 地址。

https://api.<REGION>.sandbox.aliyuncs.com,地域与目标 Sandbox 一致。

E2B_DOMAIN

SDK 访问 Sandbox 的域名。

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

SANDBOX_ID

接收追加挂载请求的 Sandbox ID。

从创建 Sandbox 的响应或 Sandbox 列表中获取。

JUICEFS_BASE_URL

JuiceFS 企业版服务地址。

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

JUICEFS_VOLUME_NAME

JuiceFS 文件系统名称。

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

JUICEFS_TOKEN

访问 JuiceFS 文件系统的 Token。

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

JUICEFS_REMOTE_DIR

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

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

存储类型专用的环境变量用于直接提供挂载配置。引用已有 Volume 时,无需设置这些变量。

追加挂载示例

在本地终端设置连接信息,将占位符替换为实际值:

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 SANDBOX_ID="<SANDBOX-ID>"

以下代码在本地运行,通过 SDK 访问 Sandbox 内的文件。示例会创建带随机标识的独立测试文件,写入并读取校验后删除该文件,保留当前 Sandbox。请使用允许读写的挂载配置;仅允许读取时,按验证挂载调整验证代码。

Sandbox.connect() 会更新 Sandbox 的超时时间。示例通过 timeout=300 将连接后的超时时间设为 300 秒,可按任务需要调整。

两种方式任选其一,也可以在同一次请求中组合使用:

  • 直接提供挂载配置:在请求体的 inlineVolumeMounts.juiceFS 中给出 JuiceFS 挂载参数。

  • 引用已有 Volume:在请求体的 namedVolumeMounts 中按名称引用同一 Team 中的 Volume。

直接提供挂载配置

以下示例将 JuiceFS 文件系统中的远端目录追加到 /mnt/juicefs,并验证读写。请确保 Token 和目录权限允许读写;已有 JuiceFS 挂载时,BASE_URL 必须与当前地址一致。

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="/datasets/project-a"

将以下代码保存为 append_juicefs.py,确认 mount_dir 未被已有挂载占用:

import os
from uuid import uuid4

import httpx
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 verify_read_write(sandbox: Sandbox, mount_dir: str) -> None:
    marker_path = f"{mount_dir}/mount-check-{uuid4().hex}.txt"
    expected = f"append mount check {uuid4().hex}\n"
    sandbox.files.write(marker_path, expected)
    try:
        content = sandbox.files.read(marker_path)
        if content != expected:
            raise RuntimeError(f"文件内容校验失败: {marker_path}")
    finally:
        sandbox.files.remove(marker_path)
    print(f"读写校验通过,测试文件已删除: {mount_dir}")


api_key = require_env("E2B_API_KEY")
api_url = require_env("E2B_API_URL").rstrip("/")
domain = require_env("E2B_DOMAIN")
sandbox_id = require_env("SANDBOX_ID")
mount_dir = "/mnt/juicefs"

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

response = httpx.post(
    f"{api_url}/sandboxes/{sandbox_id}/fc-volume-mounts",
    headers={"X-API-Key": api_key},
    json=payload,
    timeout=120.0,
)
if response.status_code != 204:
    raise RuntimeError(f"追加挂载失败: HTTP {response.status_code}, {response.text}")

sandbox = Sandbox.connect(
    sandbox_id,
    timeout=300,
    api_key=api_key,
    api_url=api_url,
    domain=domain,
)

verify_read_write(sandbox, mount_dir)
python append_juicefs.py

remoteDir 是 JuiceFS 中的远端目录,mountDir 是 Sandbox 内的本地目录。平台会将 remoteDir 转换为客户端的 --subdir 参数;远端目录的使用方法参见动态挂载 JuiceFS。

引用已有 Volume

已有智能体沙箱 Volume 时,首次运行前将上述脚本中的 payload 定义替换为以下内容,其他代码保持不变。请将 name 替换为同一 Team 中的 Volume 名称,读写校验要求该 Volume 允许读写。

payload = {
    "namedVolumeMounts": [{
        "name": "juicefs-workspace",
        "path": mount_dir,
    }],
}

name 使用智能体沙箱 Volume 名称,不使用 JuiceFS 文件系统名称。组合挂载时,envs.BASE_URL 必须与所引用 Volume 的 baseURL 以及已有 JuiceFS 挂载的服务地址一致。

以上两个示例分别演示一种挂载方式,单次运行时选择其一。同一个挂载目录不能重复追加;挂载已成功但校验失败时,只需重新执行连接和验证代码,不要再次提交追加请求。

直接配置与引用 Volume 组合使用时,将两种配置放入同一个请求体,并为每个挂载点指定不同的本地挂载目录。引用 Volume 的完整操作和多卷示例参见追加挂载 Volume。

验证挂载

示例仅在接口返回 204 后连接 Sandbox 并验证文件读写。输出“读写校验通过,测试文件已删除”表示写入、内容比对和删除均已完成。

Token 或挂载配置仅允许读取时,只验证读取。首次运行前,将示例末尾的 verify_read_write(sandbox, mount_dir) 替换为以下代码,并把 <EXISTING-FILE> 替换为挂载目录中已存在的文件相对路径。

file_path = f"{mount_dir}/<EXISTING-FILE>"
content = sandbox.files.read(file_path, format="bytes")
print(f"读取成功: {file_path},{len(content)} 字节")

引用 Volume 的挂载还可以在连接成功后通过 SDK 查询:

print(sandbox.get_info().volume_mounts)

SDK 的 volume_mounts 对应 GET /sandboxes/{sandboxID} 响应中的 volumeMounts。直接提供配置的挂载不会出现在该字段中,需要通过文件访问验证。目录存在不代表数据访问正常。

行为说明

释放 Sandbox 不会删除 JuiceFS 中的数据。测试文件和任务数据需要通过存储服务或挂载目录单独清理。

使用限制

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

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

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

  • 追加挂载仅支持 JuiceFS 企业版。

  • 接口只增加挂载,不支持卸载或替换。需要移除已有挂载时,应释放并重新创建 Sandbox。省略已有挂载不会删除它,重复提交相同挂载会返回 400。

  • 同一 Sandbox 中,已有与新增 JuiceFS 挂载点累计最多 5 个,并共用同一个 JuiceFS 服务地址。

  • 不要并发修改同一 Sandbox 的挂载。

常见问题

请求被 API Key 策略拒绝

错误消息为 request is not allowed by API key policy 时,检查 API Key 策略是否允许本次挂载方式和存储类型,参见API Key 管理。这类拒绝发生在接口授权阶段,调整存储 RAM 角色不能解决。

按名称挂载时提示找不到 Volume

核对请求中的 Volume 名称、API Key 所属 Team 和 API 地址的地域,确认使用同一 Team 中的 Volume 名称,而非 Volume ID。详细说明参见追加挂载 Volume。

按名称挂载时提示 Volume 不可用

通过 GetVolume 查询 Volume 的状态和状态原因,确认处于可用状态后再挂载;存在失败原因时,先处理该原因。详细说明参见追加挂载 Volume。

追加挂载提示 Sandbox 未运行

错误消息为 sandbox must be running 时,确认目标 Sandbox 已进入 running 状态。已暂停的 Sandbox 需先恢复运行;已释放的 Sandbox 需重新创建。

追加挂载提示 Sandbox 的 VPC 配置不完整

错误消息包含 FC Function complete VPC configuration is required 时,缺少配置的是当前 Sandbox。追加请求或新增 Volume 的 mountConfig.vpcConfig 不会补齐它。

需要在重新创建 Sandbox 时配置完整的 vpcId、securityGroupId 和非空 vSwitchIds。创建时可直接通过 metadata 提供,或在引用 Volume 时使用该 Volume 保存的 VPC 配置。

追加挂载提示 JuiceFS 服务地址冲突

核对本次 inlineVolumeMounts.juiceFS.envs.BASE_URL、所引用 Volume 的 baseURL,以及 Sandbox 已有 JuiceFS 挂载使用的服务地址。所有 JuiceFS 挂载必须使用同一服务地址。

例如,错误消息包含 JuiceFS Volume baseUrl conflicts with inline JuiceFS envs.BASE_URL,表示本次直接配置与引用 Volume 的服务地址不一致。填写一致的地址或选择相应 Volume;需要接入另一个 JuiceFS 服务时,应使用另一个 Sandbox。

追加挂载提示目录重复

错误消息包含 duplicate mount path 或 duplicate mount dir 时,检查本次请求内是否有重复的本地挂载目录,以及目录是否已被 Sandbox 中的其他挂载占用。不同存储类型也不能共用同一个本地挂载目录。

已有挂载无需再次提交;新增挂载应使用未占用的目录。追加接口不能覆盖或替换已有挂载。

本次只追加一个挂载点,为什么仍提示数量超限

挂载数量按 Sandbox 中已有和本次新增的挂载累计计算,直接配置和引用 Volume 的挂载都需计入。不能只检查本次请求的数量。

按本文使用限制核对相应存储类型的挂载数量。达到上限时,可将新增存储挂载到另一个 Sandbox;更换本地挂载目录不会减少已有挂载数量。

若问题仍未解决,或接口提示服务暂时不可用,请保留完整错误信息和请求 ID,联系产品支持。