Skip to content

Commit ad91c85

Browse files
elithraraninibread
andauthored
containers: R2 FUSE example (#26569)
* containers: R2 FUSE example * update * changelog, update * changelog update * Update src/content/docs/containers/examples/r2-fuse-mount.mdx Co-authored-by: Anni Wang <[email protected]> * Apply suggestions from code review Co-authored-by: Anni Wang <[email protected]> * Update src/content/docs/containers/examples/r2-fuse-mount.mdx Co-authored-by: Anni Wang <[email protected]> * Update src/content/changelog/containers/2025-11-21-fuse-support-in-containers.mdx Co-authored-by: Anni Wang <[email protected]> * Update src/content/changelog/containers/2025-11-21-fuse-support-in-containers.mdx Co-authored-by: Anni Wang <[email protected]> * editS * s3, gcs * fix trailing para --------- Co-authored-by: Anni Wang <[email protected]>
1 parent ce0d3ab commit ad91c85

File tree

2 files changed

+215
-0
lines changed

2 files changed

+215
-0
lines changed
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Mount R2 buckets in Containers
3+
description: Containers now support mounting FUSE volumes
4+
products:
5+
- containers
6+
date: 2025-11-21
7+
---
8+
9+
[Containers](/containers/) now support mounting R2 buckets as FUSE (Filesystem in Userspace) volumes, allowing applications to interact with [R2](/r2/) using standard filesystem operations.
10+
11+
Common use cases include:
12+
13+
- Bootstrapping containers with datasets, models, or dependencies for [sandboxes](/sandbox/) and [agent](/agents/) environments
14+
- Persisting user configuration or application state without managing downloads
15+
- Accessing large static files without bloating container images or downloading at startup
16+
17+
FUSE adapters like [tigrisfs](https://github.com/tigrisdata/tigrisfs), [s3fs](https://github.com/s3fs-fuse/s3fs-fuse), and [gcsfuse](https://github.com/GoogleCloudPlatform/gcsfuse) can be installed in your container image and configured to mount buckets at startup.
18+
19+
```dockerfile
20+
FROM alpine:3.20
21+
22+
# Install FUSE and dependencies
23+
RUN apk update && \
24+
apk add --no-cache ca-certificates fuse curl bash
25+
26+
# Install tigrisfs
27+
RUN ARCH=$(uname -m) && \
28+
if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; fi && \
29+
if [ "$ARCH" = "aarch64" ]; then ARCH="arm64"; fi && \
30+
VERSION=$(curl -s https://api.github.com/repos/tigrisdata/tigrisfs/releases/latest | grep -o '"tag_name": "[^"]*' | cut -d'"' -f4) && \
31+
curl -L "https://github.com/tigrisdata/tigrisfs/releases/download/${VERSION}/tigrisfs_${VERSION#v}_linux_${ARCH}.tar.gz" -o /tmp/tigrisfs.tar.gz && \
32+
tar -xzf /tmp/tigrisfs.tar.gz -C /usr/local/bin/ && \
33+
rm /tmp/tigrisfs.tar.gz && \
34+
chmod +x /usr/local/bin/tigrisfs
35+
36+
# Create startup script that mounts bucket
37+
RUN printf '#!/bin/sh\n\
38+
set -e\n\
39+
mkdir -p /mnt/r2\n\
40+
R2_ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"\n\
41+
/usr/local/bin/tigrisfs --endpoint "${R2_ENDPOINT}" -f "${BUCKET_NAME}" /mnt/r2 &\n\
42+
sleep 3\n\
43+
ls -lah /mnt/r2\n\
44+
' > /startup.sh && chmod +x /startup.sh
45+
46+
CMD ["/startup.sh"]
47+
```
48+
49+
See the [Mount R2 buckets with FUSE](/containers/examples/r2-fuse-mount/) example for a complete guide on mounting R2 buckets and/or other S3-compatible storage buckets within your containers.
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
---
2+
summary: Mount R2 buckets as filesystems using FUSE in Containers
3+
pcx_content_type: example
4+
title: Mount R2 buckets with FUSE
5+
sidebar:
6+
order: 8
7+
description: Mount R2 buckets as filesystems using FUSE in Containers
8+
---
9+
10+
import { Details, TypeScriptExample } from "~/components";
11+
12+
FUSE (Filesystem in Userspace) allows you to mount [R2 buckets](/r2/) as filesystems within Containers. Applications can then interact with R2 using standard filesystem operations rather than object storage APIs.
13+
14+
Common use cases include:
15+
16+
- **Bootstrapping containers with assets** - Mount datasets, models, or dependencies for sandboxes and agent environments
17+
- **Persisting user state** - Store and access user configuration or application state without managing downloads
18+
- **Large static files** - Avoid bloating container images or downloading files at startup
19+
- **Editing files** - Make code or config available within the container and save edits across instances.
20+
21+
:::note[Performance considerations]
22+
23+
Object storage is not a POSIX-compatible filesystem, nor is it local storage. While FUSE mounts provide a familiar interface, you should not expect native SSD-like performance.
24+
25+
Common use cases where this tradeoff is acceptable include reading shared assets, bootstrapping [agents](/agents/) or [sandboxes](/sandbox/) with initial data, persisting user state, and applications that require filesystem APIs but don't need high-performance I/O.
26+
27+
:::
28+
29+
## Mounting buckets
30+
31+
To mount an R2 bucket, install a FUSE adapter in your Dockerfile and configure it to run at container startup.
32+
33+
This example uses [tigrisfs](https://github.com/tigrisdata/tigrisfs), which supports S3-compatible storage including R2:
34+
35+
<Details header="Dockerfile">
36+
```dockerfile
37+
FROM alpine:3.20
38+
39+
# Install FUSE and dependencies
40+
RUN apk update && \
41+
apk add --no-cache ca-certificates fuse curl bash
42+
43+
# Install tigrisfs
44+
RUN ARCH=$(uname -m) && \
45+
if [ "$ARCH" = "x86_64" ]; then ARCH="amd64"; fi && \
46+
if [ "$ARCH" = "aarch64" ]; then ARCH="arm64"; fi && \
47+
VERSION=$(curl -s https://api.github.com/repos/tigrisdata/tigrisfs/releases/latest | grep -o '"tag_name": "[^"]*' | cut -d'"' -f4) && \
48+
curl -L "https://github.com/tigrisdata/tigrisfs/releases/download/${VERSION}/tigrisfs_${VERSION#v}_linux_${ARCH}.tar.gz" -o /tmp/tigrisfs.tar.gz && \
49+
tar -xzf /tmp/tigrisfs.tar.gz -C /usr/local/bin/ && \
50+
rm /tmp/tigrisfs.tar.gz && \
51+
chmod +x /usr/local/bin/tigrisfs
52+
53+
# Create startup script that mounts bucket and runs a command
54+
RUN printf '#!/bin/sh\n\
55+
set -e\n\
56+
\n\
57+
mkdir -p /mnt/r2\n\
58+
\n\
59+
R2_ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"\n\
60+
echo "Mounting bucket ${BUCKET_NAME}..."\n\
61+
/usr/local/bin/tigrisfs --endpoint "${R2_ENDPOINT}" -f "${BUCKET_NAME}" /mnt/r2 &\n\
62+
sleep 3\n\
63+
\n\
64+
echo "Contents of mounted bucket:"\n\
65+
ls -lah /mnt/r2\n\
66+
' > /startup.sh && chmod +x /startup.sh
67+
68+
CMD ["/startup.sh"]
69+
```
70+
</Details>
71+
72+
The startup script creates a mount point, starts tigrisfs in the background to mount the bucket, and then lists the mounted directory contents.
73+
74+
### Passing credentials to the container
75+
76+
Your Container needs [R2 credentials](/r2/api/tokens/) and configuration passed as environment variables. Store credentials as [Worker secrets](/workers/configuration/secrets/), then pass them through the `envVars` property:
77+
78+
<TypeScriptExample filename="src/index.ts">
79+
```ts
80+
import { Container, getContainer } from "@cloudflare/containers";
81+
82+
interface Env {
83+
FUSEDemo: DurableObjectNamespace<FUSEDemo>;
84+
AWS_ACCESS_KEY_ID: string;
85+
AWS_SECRET_ACCESS_KEY: string;
86+
R2_BUCKET_NAME: string;
87+
R2_ACCOUNT_ID: string;
88+
}
89+
90+
export class FUSEDemo extends Container<Env> {
91+
defaultPort = 8080;
92+
sleepAfter = "10m";
93+
envVars = {
94+
AWS_ACCESS_KEY_ID: this.env.AWS_ACCESS_KEY_ID,
95+
AWS_SECRET_ACCESS_KEY: this.env.AWS_SECRET_ACCESS_KEY,
96+
BUCKET_NAME: this.env.R2_BUCKET_NAME,
97+
R2_ACCOUNT_ID: this.env.R2_ACCOUNT_ID,
98+
};
99+
}
100+
```
101+
</TypeScriptExample>
102+
103+
The `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` should be stored as secrets, while `R2_BUCKET_NAME` and `R2_ACCOUNT_ID` can be configured as variables in your `wrangler.jsonc`:
104+
105+
```json
106+
{
107+
"vars": {
108+
"R2_BUCKET_NAME": "my-bucket",
109+
"R2_ACCOUNT_ID": "your-account-id"
110+
}
111+
}
112+
```
113+
114+
### Other S3-compatible storage providers
115+
116+
Other S3-compatible storage providers, including AWS S3 and Google Cloud Storage, can be mounted using the same approach as R2. You will need to provide the appropriate endpoint URL and access credentials for the storage provider.
117+
118+
## Mounting bucket prefixes
119+
120+
To mount a specific prefix (subdirectory) within a bucket, most FUSE adapters require mounting the entire bucket and then accessing the prefix path within the mount.
121+
122+
With tigrisfs, mount the bucket and access the prefix via the filesystem path:
123+
124+
```dockerfile
125+
RUN printf '#!/bin/sh\n\
126+
set -e\n\
127+
\n\
128+
mkdir -p /mnt/r2\n\
129+
\n\
130+
R2_ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"\n\
131+
/usr/local/bin/tigrisfs --endpoint "${R2_ENDPOINT}" -f "${BUCKET_NAME}" /mnt/r2 &\n\
132+
sleep 3\n\
133+
\n\
134+
echo "Accessing prefix: ${BUCKET_PREFIX}"\n\
135+
ls -lah "/mnt/r2/${BUCKET_PREFIX}"\n\
136+
' > /startup.sh && chmod +x /startup.sh
137+
```
138+
139+
Your application can then read from `/mnt/r2/${BUCKET_PREFIX}` to access only the files under that prefix. Pass `BUCKET_PREFIX` as an environment variable alongside your other R2 configuration.
140+
141+
## Mounting buckets as read-only
142+
143+
To prevent applications from writing to the mounted bucket, add the `-o ro` flag to mount the filesystem as read-only:
144+
145+
```dockerfile
146+
RUN printf '#!/bin/sh\n\
147+
set -e\n\
148+
\n\
149+
mkdir -p /mnt/r2\n\
150+
\n\
151+
R2_ENDPOINT="https://${R2_ACCOUNT_ID}.r2.cloudflarestorage.com"\n\
152+
/usr/local/bin/tigrisfs --endpoint "${R2_ENDPOINT}" -o ro -f "${BUCKET_NAME}" /mnt/r2 &\n\
153+
sleep 3\n\
154+
\n\
155+
ls -lah /mnt/r2\n\
156+
' > /startup.sh && chmod +x /startup.sh
157+
```
158+
159+
This is useful for shared assets or configuration files where you want to ensure applications only read data.
160+
161+
## Related resources
162+
163+
- [Container environment variables](/containers/examples/env-vars-and-secrets/) - Learn how to pass secrets and variables to Containers
164+
- [tigrisfs](https://github.com/tigrisdata/tigrisfs) - FUSE adapter for S3-compatible storage including R2
165+
- [s3fs](https://github.com/s3fs-fuse/s3fs-fuse) - Alternative FUSE adapter for S3-compatible storage
166+
- [gcsfuse](https://github.com/GoogleCloudPlatform/gcsfuse) - FUSE adapter for Google Cloud Storage buckets

0 commit comments

Comments
 (0)