When you create a Sandbox, use volume_mounts to mount an existing JuiceFS Volume by name.
How it works
After the volume is mounted, the Sandbox accesses JuiceFS through file paths, and the data is not deleted when the Sandbox is released.
To provide the complete JuiceFS configuration when you create a Sandbox, see Mount JuiceFS dynamically.
To append a mount to a running Sandbox, see Append a volume mount.
Prerequisites
-
You have created a JuiceFS Volume for the destination team and obtained the volume name.
-
You have prepared an Agent Sandbox API key bound to the same team. A volume and an API key cannot be used across teams. For more information, see Create an API Key.
-
You have prepared a Virtual Private Cloud (VPC), a vSwitch, and a security group, all of which can reach the JuiceFS service.
-
You have prepared the Agent Sandbox API URL, the domain, and a custom template of the second-generation runtime (MicroVM).
The VPC configuration used to create the Sandbox must contain vpcId, securityGroupId, and a non-empty vSwitchIds, and must be able to access the target storage. The VPC configuration in the template cannot replace this mount configuration.
A JuiceFS Volume requires a custom template of the second-generation runtime. The source image must have the JuiceFS Enterprise Edition client, the RADOS (Reliable Autonomic Distributed Object Store) runtime library, and FUSE 2 (Filesystem in Userspace) pre-installed. RADOS is the underlying object store of Ceph.
Procedure
Step 1: Prepare the second-generation runtime image
If you already have a template that meets the requirements, skip this step and go to Step 2: Install the SDK.
A JuiceFS Volume mount requires the second-generation runtime (MicroVM). Before you build the custom template, the source image must have the JuiceFS Enterprise Edition client, the RADOS runtime library, and FUSE 2 pre-installed. The second-generation runtime uses the source image directly and does not inject the JuiceFS client when the template is built.
JuiceFS Volume mounts support only JuiceFS Enterprise Edition. JuiceFS provides the Enterprise Edition mount image in the juicedata/mount repository on Docker Hub, and the image tags start with ee-. In the image, /usr/bin/juicefs is the client launcher, and the version-pinned client executable is located at /usr/local/juicefs/mount/jfsmount.
The following example uses juicedata/mount:ee-5.3.7-58af72b. In this tag, 5.3.7 is the client version and 58af72b is the corresponding build commit. Verify the version information in the JuiceFS Command Reference. For information about how to use the image and containers, see Use JuiceFS in Docker.
Make sure that the image can be pulled, and then check the Enterprise Edition client in the image:
docker pull --platform linux/amd64 \
juicedata/mount:ee-5.3.7-58af72b
docker run --rm --platform linux/amd64 \
--entrypoint /usr/bin/juicefs \
juicedata/mount:ee-5.3.7-58af72b \
version
The client version in the output must be 5.3.7, and the build commit must be 58af72b. Do not use floating tags such as latest or ee-nightly, because the client version may change after you rebuild the template. If the build environment cannot access Docker Hub, sync the image to an accessible private image repository first, and then replace the image address of juicedata/mount in the following Dockerfile.
The following Dockerfile uses Ubuntu 22.04 by default. To build on an existing Sandbox base image, pass the image address by using the BASE_IMAGE build argument:
ARG BASE_IMAGE=ubuntu:22.04
FROM juicedata/mount:ee-5.3.7-58af72b AS juicefs-ee
FROM ${BASE_IMAGE}
ARG DEBIAN_FRONTEND=noninteractive
RUN set -eux; \
apt-get update; \
apt-get install -y --no-install-recommends \
ca-certificates \
fuse \
librados2; \
rm -rf /var/lib/apt/lists/*
COPY --from=juicefs-ee /usr/local/juicefs/mount/jfsmount /usr/bin/juicefs
RUN set -eux; \
chmod 0755 /usr/bin/juicefs; \
command -v juicefs; \
command -v fusermount; \
mkdir -p /mnt/juicefs
WORKDIR /root
# Do not set a custom USER, ENTRYPOINT, or CMD. The Sandbox control plane takes over.
Do not write the JuiceFS token or the mount configuration into the Dockerfile or any image layer.
Before you build and push the linux/amd64 image, replace the placeholders with actual values:
docker buildx build \
--platform linux/amd64 \
--build-arg BASE_IMAGE="<YOUR-SANDBOX-BASE-IMAGE>" \
--push \
-t "<REGISTRY>/<NAMESPACE>/microsandbox-juicefs-ee:<VERSION>" \
.
After the build is complete, check the client, the RADOS runtime library, and FUSE 2 in the image:
docker run --rm --platform linux/amd64 \
--entrypoint /bin/sh \
<REGISTRY>/<NAMESPACE>/microsandbox-juicefs-ee:<VERSION> \
-euxc '
command -v juicefs
command -v fusermount
ldconfig -p | grep "librados\.so\.2"
juicefs version
'
This check verifies only the image content. It does not mean that the VPC, the token, or the actual mount path works. Use this image to rebuild the MicroVM template, and then run the following examples.
Step 2: Install the SDK
This topic uses the E2B Python SDK for demonstration. volume_mounts requires E2B Python SDK 2.31.0 or later.
python3 -m venv .venv
source .venv/bin/activate
pip install e2b==2.31.0
Step 3: Mount and verify
Environment variables
|
Environment variable |
Purpose |
Source or value |
|
|
The API key used to access Agent Sandbox. |
Obtain the key in the Agent Sandbox console. The key must be bound to the team that owns the volume. |
|
|
The endpoint of the E2B API. |
Set the value to |
|
|
The service domain that the SDK uses. |
Set the value to |
|
|
The template used to create the Sandbox. |
Specify the ID or alias of a template that meets the prerequisites. Obtain the value in the Agent Sandbox console. |
|
|
The name of the JuiceFS Volume to mount. |
Use the name that you set when you created the JuiceFS Volume, or query the name in the volume list. Do not use the volume ID. |
In volume_mounts, specify the name of the JuiceFS Volume, which is the value of JUICEFS_SANDBOX_VOLUME_NAME. Do not use the JuiceFS file system name or the volume ID.
Mount example
Set the following parameters in your terminal and replace the placeholders with actual values. For the value of each variable, see Environment variables in this topic.
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 JUICEFS_SANDBOX_VOLUME_NAME="juicefs-workspace"
The local mount directory resides in the Sandbox and corresponds to the key of volume_mounts. Use a subdirectory of /home, /mnt, /tmp, or /data. This topic uses /mnt/juicefs.
The following example reuses the mountConfig.vpcConfig of the volume to mount the JuiceFS Volume to /mnt/juicefs. Make sure that the volume stores a complete VPC configuration.
The example creates a separate test file with a random identifier in the mount directory, writes data to the file, and reads the file for verification. The example then deletes the file and releases the Sandbox created in this run. Use a mount configuration that provides read and write permissions.
Save the following code as 04_mount_juicefs_volume.py:
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"Missing environment variable: {name}")
return value
mount_dir = "/mnt/juicefs"
marker_path = f"{mount_dir}/hello-juicefs-{uuid4().hex}.txt"
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"),
volume_mounts={
mount_dir: require_env("JUICEFS_SANDBOX_VOLUME_NAME"),
},
)
info = sandbox.get_info()
print(f"volume_mounts={info.volume_mounts}")
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"File content mismatch: {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 Volume read/write verification passed")
Run the example:
python 04_mount_juicefs_volume.py
If the output shows JuiceFS Volume read/write verification passed, the read and write operations, the test file cleanup, and the Sandbox release are complete.
Behavior notes
-
volume_mountsuses the{mount directory: volume name}format. Do not use a volume ID or the JuiceFS file system name. -
Based on the volume name, Agent Sandbox reads the
volumeName,baseURL,remoteDir,token, andargsstored when the volume was created. Agent Sandbox then converts these values into the JuiceFS mount configuration. -
This topic reuses the
mountConfig.vpcConfigof the volume. To override it, provide a complete VPC configuration in the metadata of the Sandbox creation request by usingfc.sandbox.network.vpc. If both are configured, the metadata takes precedence. -
When a Sandbox is resumed after it is paused, the volume mount is restored.
-
Releasing a Sandbox does not delete the data in JuiceFS. The test file is deleted by the example. The retention and cleanup of other data must be handled separately.
Limits
-
In the same Sandbox, JuiceFS supports a maximum of five mount points. The count includes mounts created with the Sandbox, mounts appended later, and mounts that specify the storage configuration directly.
-
The mount directory must be a normalized absolute Unix path. It cannot be
/, and it cannot contain leading or trailing spaces, repeated path separators, or the.or..path segments. -
The mount directory cannot be a system directory such as
/bin,/opt,/var, or/dev, or a subdirectory of such a directory. The mount directory also cannot contain a hidden directory, such as.cache, whose name starts with.. -
Mount directories cannot be duplicated in the same Sandbox.
-
All JuiceFS mounts in the same Sandbox must use the same
baseURL. This requirement applies to both the mounts that reference volumes by name and the mounts that specify the storage configuration directly.
FAQ
The system reports that the volume cannot be found
If the error message is volume not found, check the volume name in the request, the team that owns the API key, and the region of the API endpoint. When you mount a volume by name, use an existing volume in the same team. Do not specify a volume ID.
The VPC is configured, but why does the system report that the configuration is incomplete
If the error message contains mount requires complete VPC config, the VPC configuration used in this creation is missing required fields.
If you do not specify the VPC in the metadata, check the mountConfig.vpcConfig of the volume. If you specify it, check fc.sandbox.network.vpc. The configuration actually used must contain vpcId, securityGroupId, and a non-empty vSwitchIds. The metadata configuration takes precedence, and the fields of the volume are not used to fill in an incomplete metadata configuration.
The volume is created, but Sandbox creation times out or the mount fails
Creating a volume only stores the configuration and does not perform the actual mount. Check the corresponding configuration based on the error message. If the message does not clearly indicate the cause, troubleshoot in the following order:
-
Verify the JuiceFS Enterprise Edition client, the RADOS runtime library, and FUSE 2 as described in Step 1: Prepare the second-generation runtime image in this topic.
-
Check the VPC routes, security groups, and service addresses actually used, and confirm that the Sandbox can access the JuiceFS service.
-
Check the token, the file system name, and the remote directory, and confirm that the token allows access to the destination directory.
To troubleshoot further, retain the complete error message and the request ID.