diff --git a/content/de/developer/integration/big-data/images/rustfs-zerofs-data.png b/content/de/developer/integration/big-data/images/rustfs-zerofs-data.png new file mode 100644 index 00000000..ee417c27 Binary files /dev/null and b/content/de/developer/integration/big-data/images/rustfs-zerofs-data.png differ diff --git a/content/de/developer/integration/big-data/index.md b/content/de/developer/integration/big-data/index.md index 72ebcc11..54245dee 100644 --- a/content/de/developer/integration/big-data/index.md +++ b/content/de/developer/integration/big-data/index.md @@ -24,6 +24,7 @@ Use **RustFS** as the object storage layer for data analytics systems that suppo - [Spark](./spark.md) - [Flink](./flink.md) - [Trino](./trino.md) +- [ZeroFS](./zerofs.md) - [Vitess](./vitess.md) Keep application data in a dedicated bucket and prefix, and use credentials scoped to the required bucket operations. \ No newline at end of file diff --git a/content/de/developer/integration/big-data/meta.json b/content/de/developer/integration/big-data/meta.json index 2374fa35..d5662e19 100644 --- a/content/de/developer/integration/big-data/meta.json +++ b/content/de/developer/integration/big-data/meta.json @@ -18,6 +18,7 @@ "pyiceberg", "spark", "trino", + "zerofs", "vitess", "zeppelin" ] diff --git a/content/de/developer/integration/big-data/zerofs.md b/content/de/developer/integration/big-data/zerofs.md new file mode 100644 index 00000000..2dd1640b --- /dev/null +++ b/content/de/developer/integration/big-data/zerofs.md @@ -0,0 +1,174 @@ +--- +title: "ZeroFS" +description: "Serve a RustFS bucket as a POSIX filesystem over NFS with ZeroFS." +--- + +This guide connects [ZeroFS](https://github.com/Barre/ZeroFS) — the log-structured filesystem that serves S3 buckets as POSIX filesystems — to **RustFS** as its object storage backend. You will run ZeroFS with its LSM tree rooted in a RustFS bucket, mount the filesystem over NFS on a Linux host, write files through the mount, and verify they survive a ZeroFS restart as objects in the bucket. The workflow was verified with ZeroFS v2.3.5 (ghcr.io/barre/zerofs) against `rustfs/rustfs-x86-musl:v2.3.1`. + +You need Docker and a Linux host with an NFS client (`nfs-common`). This deployment is intended for local integration testing, not production. + +## Architecture + +```mermaid +flowchart LR + POSIX["POSIX apps"] -->|"NFS :2049"| ZeroFS["ZeroFS"] + ZeroFS -->|"LSM SSTs, WAL, manifests"| RustFS["RustFS :9000"] +``` + +ZeroFS translates filesystem operations into an LSM key-value tree stored in the bucket: writes land in a write-ahead log, flush into SST segments, and compaction runs in the background. Clients see an ordinary directory tree over NFS (or 9P/NBD). + +## 1. Generate the configuration + +Create the bucket and the config file, replacing all connection placeholders: + +```bash +rc mb rustfs/zerofs-demo + +docker run --rm -u root:root -v /opt/zerofs:/cfg -w /cfg \ + --entrypoint /bin/sh ghcr.io/barre/zerofs:latest -c "zerofs init" +``` + +Then edit `zerofs.toml` so the storage and AWS sections point at RustFS: + +```toml title="zerofs.toml" +[cache] +dir = "/cache" +disk_size_gb = 5.0 + +[storage] +url = "s3://zerofs-demo/zerofs-data" +encryption_password = "${ZEROFS_PASSWORD}" + +[servers.nfs] +addresses = ["0.0.0.0:2049"] + +[servers.rpc] +addresses = ["0.0.0.0:7000"] + +[aws] +access_key_id = "${AWS_ACCESS_KEY_ID}" +secret_access_key = "${AWS_SECRET_ACCESS_KEY}" +endpoint = "http://:9000" +default_region = "us-east-1" +allow_http = "true" +``` + +The `endpoint` plus `allow_http` pair is what redirects ZeroFS from AWS to RustFS. Custom endpoints use path-style addressing, so no extra option is needed. + +## 2. Run ZeroFS + +Run the server with the config file, credentials, and a writable cache directory (the image runs as UID 1001): + +```bash +mkdir -p /opt/zerofs/cache && chown -R 1001:1001 /opt/zerofs/cache + +docker run -d --name zerofs --network oo-rustfs_default -p 2049:2049 \ + -e ZEROFS_PASSWORD= \ + -e AWS_ACCESS_KEY_ID= \ + -e AWS_SECRET_ACCESS_KEY= \ + -v /opt/zerofs/zerofs.toml:/zerofs.toml:ro \ + -v /opt/zerofs/cache:/cache \ + ghcr.io/barre/zerofs:latest run -c /zerofs.toml +``` + +```text +INFO zerofs::nfs: NFS server listening on 0.0.0.0:2049 +``` + +## 3. Mount over NFS + +On the host, mount the export with the options ZeroFS recommends: + +```bash +apt-get install -y nfs-common +mkdir -p /mnt/zerofs + +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +The mount is an ordinary POSIX filesystem: + +```bash +echo "written via zerofs nfs mount on rustfs" > /mnt/zerofs/hello.txt +dd if=/dev/urandom of=/mnt/zerofs/data/inner/blob.bin bs=1M count=8 +``` + +## 4. Verify persistence and objects in RustFS + +Force pending writes to the bucket, then restart ZeroFS and remount: + +```bash +docker exec zerofs zerofs flush -c /zerofs.toml +umount /mnt/zerofs +docker restart zerofs +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +Everything written before the restart is still there: + +```bash +cat /mnt/zerofs/hello.txt +sha1sum /mnt/zerofs/data/inner/blob.bin +``` + +```text +written via zerofs nfs mount on rustfs +645faaefe499f9ebda8edceeeb1a6261999aece7 /mnt/zerofs/data/inner/blob.bin +``` + +List the bucket to see where the files actually live: + +```bash +rc ls rustfs/zerofs-demo/ -r | head -4 +``` + +```text +zerofs-data/compacted/01M40Q1RA0X3AVG76VC0SBYE58.sst +zerofs-data/manifest/0000000000000000.json +zerofs-data/wal/00000000000000000001.sst +``` + +Files are not stored 1:1 — they are keys and values inside the LSM tree, which is what lets ZeroFS serve a bucket as a filesystem. + +![ZeroFS LSM data stored in the RustFS Console](./images/rustfs-zerofs-data.png) + +## 5. Stop or reset + +To tear down the demo while keeping the bucket objects: + +```bash +umount /mnt/zerofs +docker rm -f zerofs +``` + +To delete the stored data (this erases the filesystem itself): + +```bash +rc rm rustfs/zerofs-demo/ --recursive --force +``` + +## Troubleshooting + +### `Failed to parse config file: missing field uid` at `[servers.webui]` + +ZeroFS v2.3.5 requires `uid` and `gid` in the `[servers.webui]` section when it is present. Either add `uid = 1000` and `gid = 1000` or delete the section entirely if you do not need the Web UI. + +### `Permission denied` creating the cache directory + +The container runs as UID 1001. After mounting the cache volume, run `chown -R 1001:1001 ` before starting the container. + +### Mount fails or hangs + +Confirm the NFS client package is installed (`nfs-common`) and that ZeroFS is listening on `0.0.0.0:2049` inside a network your client can reach. The `port=2049,mountport=2049` options matter because ZeroFS serves the mountd traffic on the same port. + +### Writes vanish after a container crash + +ZeroFS buffers writes and flushes periodically. For the demo, run `docker exec zerofs zerofs flush -c /zerofs.toml`; in production, clients that need strict durability should fsync (or use the 9P mount, whose fsync waits for stable storage). + +## Next steps + +- Review [S3 compatibility notes](/administration/protocols/s3) before adopting additional ZeroFS backends. +- Create dedicated production credentials with [Access Key Management](/security-compliance/iam/access-token). +- Follow the [ZeroFS configuration guide](https://www.zerofs.net/configuration) for cache sizing, 9P/NBD serving, and high-availability replication over the same bucket. diff --git a/content/de/developer/integration/index.md b/content/de/developer/integration/index.md index 477aefa7..2fb5a6b5 100644 --- a/content/de/developer/integration/index.md +++ b/content/de/developer/integration/index.md @@ -10,7 +10,7 @@ Use this section to connect **RustFS** to infrastructure and application platfor - [Reverse Proxy](./reverse-proxy/index.md) covers Nginx, Traefik, Caddy, HAProxy, and Envoy. - [Backup](./backup/index.md) covers Kopia, Longhorn, Restic, and Velero. - [AI](./ai/index.md) covers AI platforms including Ray and vLLM. -- [Datenanalyse](./big-data/index.md) covers analytics systems including Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess, and Zeppelin. +- [Datenanalyse](./big-data/index.md) covers analytics systems including Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess, Zeppelin, and ZeroFS. - [Cloud Native](./cloud-native/index.md) covers Cortex and Flux. - [Observability](./observability/index.md) covers telemetry systems including Fluentd, GreptimeDB, Loki, OpenObserve, OpenTelemetry, Tempo, Thanos, and VictoriaMetrics. - [Others](./others/index.md) covers the capo SDK, rclone, JuiceFS, Nextcloud, and tusd. diff --git a/content/en/developer/integration/big-data/images/rustfs-zerofs-data.png b/content/en/developer/integration/big-data/images/rustfs-zerofs-data.png new file mode 100644 index 00000000..ee417c27 Binary files /dev/null and b/content/en/developer/integration/big-data/images/rustfs-zerofs-data.png differ diff --git a/content/en/developer/integration/big-data/index.md b/content/en/developer/integration/big-data/index.md index d26a8d96..82d0c544 100644 --- a/content/en/developer/integration/big-data/index.md +++ b/content/en/developer/integration/big-data/index.md @@ -24,6 +24,7 @@ Use **RustFS** as the object storage layer for data analytics systems that suppo - [Spark](./spark.md) - [Flink](./flink.md) - [Trino](./trino.md) +- [ZeroFS](./zerofs.md) - [Vitess](./vitess.md) Keep application data in a dedicated bucket and prefix, and use credentials scoped to the required bucket operations. \ No newline at end of file diff --git a/content/en/developer/integration/big-data/meta.json b/content/en/developer/integration/big-data/meta.json index 2374fa35..d5662e19 100644 --- a/content/en/developer/integration/big-data/meta.json +++ b/content/en/developer/integration/big-data/meta.json @@ -18,6 +18,7 @@ "pyiceberg", "spark", "trino", + "zerofs", "vitess", "zeppelin" ] diff --git a/content/en/developer/integration/big-data/zerofs.md b/content/en/developer/integration/big-data/zerofs.md new file mode 100644 index 00000000..2dd1640b --- /dev/null +++ b/content/en/developer/integration/big-data/zerofs.md @@ -0,0 +1,174 @@ +--- +title: "ZeroFS" +description: "Serve a RustFS bucket as a POSIX filesystem over NFS with ZeroFS." +--- + +This guide connects [ZeroFS](https://github.com/Barre/ZeroFS) — the log-structured filesystem that serves S3 buckets as POSIX filesystems — to **RustFS** as its object storage backend. You will run ZeroFS with its LSM tree rooted in a RustFS bucket, mount the filesystem over NFS on a Linux host, write files through the mount, and verify they survive a ZeroFS restart as objects in the bucket. The workflow was verified with ZeroFS v2.3.5 (ghcr.io/barre/zerofs) against `rustfs/rustfs-x86-musl:v2.3.1`. + +You need Docker and a Linux host with an NFS client (`nfs-common`). This deployment is intended for local integration testing, not production. + +## Architecture + +```mermaid +flowchart LR + POSIX["POSIX apps"] -->|"NFS :2049"| ZeroFS["ZeroFS"] + ZeroFS -->|"LSM SSTs, WAL, manifests"| RustFS["RustFS :9000"] +``` + +ZeroFS translates filesystem operations into an LSM key-value tree stored in the bucket: writes land in a write-ahead log, flush into SST segments, and compaction runs in the background. Clients see an ordinary directory tree over NFS (or 9P/NBD). + +## 1. Generate the configuration + +Create the bucket and the config file, replacing all connection placeholders: + +```bash +rc mb rustfs/zerofs-demo + +docker run --rm -u root:root -v /opt/zerofs:/cfg -w /cfg \ + --entrypoint /bin/sh ghcr.io/barre/zerofs:latest -c "zerofs init" +``` + +Then edit `zerofs.toml` so the storage and AWS sections point at RustFS: + +```toml title="zerofs.toml" +[cache] +dir = "/cache" +disk_size_gb = 5.0 + +[storage] +url = "s3://zerofs-demo/zerofs-data" +encryption_password = "${ZEROFS_PASSWORD}" + +[servers.nfs] +addresses = ["0.0.0.0:2049"] + +[servers.rpc] +addresses = ["0.0.0.0:7000"] + +[aws] +access_key_id = "${AWS_ACCESS_KEY_ID}" +secret_access_key = "${AWS_SECRET_ACCESS_KEY}" +endpoint = "http://:9000" +default_region = "us-east-1" +allow_http = "true" +``` + +The `endpoint` plus `allow_http` pair is what redirects ZeroFS from AWS to RustFS. Custom endpoints use path-style addressing, so no extra option is needed. + +## 2. Run ZeroFS + +Run the server with the config file, credentials, and a writable cache directory (the image runs as UID 1001): + +```bash +mkdir -p /opt/zerofs/cache && chown -R 1001:1001 /opt/zerofs/cache + +docker run -d --name zerofs --network oo-rustfs_default -p 2049:2049 \ + -e ZEROFS_PASSWORD= \ + -e AWS_ACCESS_KEY_ID= \ + -e AWS_SECRET_ACCESS_KEY= \ + -v /opt/zerofs/zerofs.toml:/zerofs.toml:ro \ + -v /opt/zerofs/cache:/cache \ + ghcr.io/barre/zerofs:latest run -c /zerofs.toml +``` + +```text +INFO zerofs::nfs: NFS server listening on 0.0.0.0:2049 +``` + +## 3. Mount over NFS + +On the host, mount the export with the options ZeroFS recommends: + +```bash +apt-get install -y nfs-common +mkdir -p /mnt/zerofs + +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +The mount is an ordinary POSIX filesystem: + +```bash +echo "written via zerofs nfs mount on rustfs" > /mnt/zerofs/hello.txt +dd if=/dev/urandom of=/mnt/zerofs/data/inner/blob.bin bs=1M count=8 +``` + +## 4. Verify persistence and objects in RustFS + +Force pending writes to the bucket, then restart ZeroFS and remount: + +```bash +docker exec zerofs zerofs flush -c /zerofs.toml +umount /mnt/zerofs +docker restart zerofs +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +Everything written before the restart is still there: + +```bash +cat /mnt/zerofs/hello.txt +sha1sum /mnt/zerofs/data/inner/blob.bin +``` + +```text +written via zerofs nfs mount on rustfs +645faaefe499f9ebda8edceeeb1a6261999aece7 /mnt/zerofs/data/inner/blob.bin +``` + +List the bucket to see where the files actually live: + +```bash +rc ls rustfs/zerofs-demo/ -r | head -4 +``` + +```text +zerofs-data/compacted/01M40Q1RA0X3AVG76VC0SBYE58.sst +zerofs-data/manifest/0000000000000000.json +zerofs-data/wal/00000000000000000001.sst +``` + +Files are not stored 1:1 — they are keys and values inside the LSM tree, which is what lets ZeroFS serve a bucket as a filesystem. + +![ZeroFS LSM data stored in the RustFS Console](./images/rustfs-zerofs-data.png) + +## 5. Stop or reset + +To tear down the demo while keeping the bucket objects: + +```bash +umount /mnt/zerofs +docker rm -f zerofs +``` + +To delete the stored data (this erases the filesystem itself): + +```bash +rc rm rustfs/zerofs-demo/ --recursive --force +``` + +## Troubleshooting + +### `Failed to parse config file: missing field uid` at `[servers.webui]` + +ZeroFS v2.3.5 requires `uid` and `gid` in the `[servers.webui]` section when it is present. Either add `uid = 1000` and `gid = 1000` or delete the section entirely if you do not need the Web UI. + +### `Permission denied` creating the cache directory + +The container runs as UID 1001. After mounting the cache volume, run `chown -R 1001:1001 ` before starting the container. + +### Mount fails or hangs + +Confirm the NFS client package is installed (`nfs-common`) and that ZeroFS is listening on `0.0.0.0:2049` inside a network your client can reach. The `port=2049,mountport=2049` options matter because ZeroFS serves the mountd traffic on the same port. + +### Writes vanish after a container crash + +ZeroFS buffers writes and flushes periodically. For the demo, run `docker exec zerofs zerofs flush -c /zerofs.toml`; in production, clients that need strict durability should fsync (or use the 9P mount, whose fsync waits for stable storage). + +## Next steps + +- Review [S3 compatibility notes](/administration/protocols/s3) before adopting additional ZeroFS backends. +- Create dedicated production credentials with [Access Key Management](/security-compliance/iam/access-token). +- Follow the [ZeroFS configuration guide](https://www.zerofs.net/configuration) for cache sizing, 9P/NBD serving, and high-availability replication over the same bucket. diff --git a/content/en/developer/integration/index.md b/content/en/developer/integration/index.md index 6957a392..110d94f0 100644 --- a/content/en/developer/integration/index.md +++ b/content/en/developer/integration/index.md @@ -10,7 +10,7 @@ Use this section to connect **RustFS** to infrastructure and application platfor - [Reverse Proxy](./reverse-proxy/index.md) covers Nginx, Traefik, Caddy, HAProxy, and Envoy. - [Backup](./backup/index.md) covers Kopia, Longhorn, Restic, and Velero. - [AI](./ai/index.md) covers AI platforms including Ray and vLLM. -- [Data Analytics](./big-data/index.md) covers analytics systems including Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess, and Zeppelin. +- [Data Analytics](./big-data/index.md) covers analytics systems including Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess, Zeppelin, and ZeroFS. - [Cloud Native](./cloud-native/index.md) covers Cortex and Flux. - [Observability](./observability/index.md) covers telemetry systems including Fluentd, GreptimeDB, Loki, OpenObserve, OpenTelemetry, Tempo, Thanos, and VictoriaMetrics. - [Others](./others/index.md) covers the capo SDK, rclone, JuiceFS, Nextcloud, and tusd. diff --git a/content/fr/developer/integration/big-data/images/rustfs-zerofs-data.png b/content/fr/developer/integration/big-data/images/rustfs-zerofs-data.png new file mode 100644 index 00000000..ee417c27 Binary files /dev/null and b/content/fr/developer/integration/big-data/images/rustfs-zerofs-data.png differ diff --git a/content/fr/developer/integration/big-data/index.md b/content/fr/developer/integration/big-data/index.md index 2e820bff..5e488c39 100644 --- a/content/fr/developer/integration/big-data/index.md +++ b/content/fr/developer/integration/big-data/index.md @@ -24,6 +24,7 @@ Use **RustFS** as the object storage layer for data analytics systems that suppo - [Spark](./spark.md) - [Flink](./flink.md) - [Trino](./trino.md) +- [ZeroFS](./zerofs.md) - [Vitess](./vitess.md) Keep application data in a dedicated bucket and prefix, and use credentials scoped to the required bucket operations. \ No newline at end of file diff --git a/content/fr/developer/integration/big-data/meta.json b/content/fr/developer/integration/big-data/meta.json index 2374fa35..d5662e19 100644 --- a/content/fr/developer/integration/big-data/meta.json +++ b/content/fr/developer/integration/big-data/meta.json @@ -18,6 +18,7 @@ "pyiceberg", "spark", "trino", + "zerofs", "vitess", "zeppelin" ] diff --git a/content/fr/developer/integration/big-data/zerofs.md b/content/fr/developer/integration/big-data/zerofs.md new file mode 100644 index 00000000..2dd1640b --- /dev/null +++ b/content/fr/developer/integration/big-data/zerofs.md @@ -0,0 +1,174 @@ +--- +title: "ZeroFS" +description: "Serve a RustFS bucket as a POSIX filesystem over NFS with ZeroFS." +--- + +This guide connects [ZeroFS](https://github.com/Barre/ZeroFS) — the log-structured filesystem that serves S3 buckets as POSIX filesystems — to **RustFS** as its object storage backend. You will run ZeroFS with its LSM tree rooted in a RustFS bucket, mount the filesystem over NFS on a Linux host, write files through the mount, and verify they survive a ZeroFS restart as objects in the bucket. The workflow was verified with ZeroFS v2.3.5 (ghcr.io/barre/zerofs) against `rustfs/rustfs-x86-musl:v2.3.1`. + +You need Docker and a Linux host with an NFS client (`nfs-common`). This deployment is intended for local integration testing, not production. + +## Architecture + +```mermaid +flowchart LR + POSIX["POSIX apps"] -->|"NFS :2049"| ZeroFS["ZeroFS"] + ZeroFS -->|"LSM SSTs, WAL, manifests"| RustFS["RustFS :9000"] +``` + +ZeroFS translates filesystem operations into an LSM key-value tree stored in the bucket: writes land in a write-ahead log, flush into SST segments, and compaction runs in the background. Clients see an ordinary directory tree over NFS (or 9P/NBD). + +## 1. Generate the configuration + +Create the bucket and the config file, replacing all connection placeholders: + +```bash +rc mb rustfs/zerofs-demo + +docker run --rm -u root:root -v /opt/zerofs:/cfg -w /cfg \ + --entrypoint /bin/sh ghcr.io/barre/zerofs:latest -c "zerofs init" +``` + +Then edit `zerofs.toml` so the storage and AWS sections point at RustFS: + +```toml title="zerofs.toml" +[cache] +dir = "/cache" +disk_size_gb = 5.0 + +[storage] +url = "s3://zerofs-demo/zerofs-data" +encryption_password = "${ZEROFS_PASSWORD}" + +[servers.nfs] +addresses = ["0.0.0.0:2049"] + +[servers.rpc] +addresses = ["0.0.0.0:7000"] + +[aws] +access_key_id = "${AWS_ACCESS_KEY_ID}" +secret_access_key = "${AWS_SECRET_ACCESS_KEY}" +endpoint = "http://:9000" +default_region = "us-east-1" +allow_http = "true" +``` + +The `endpoint` plus `allow_http` pair is what redirects ZeroFS from AWS to RustFS. Custom endpoints use path-style addressing, so no extra option is needed. + +## 2. Run ZeroFS + +Run the server with the config file, credentials, and a writable cache directory (the image runs as UID 1001): + +```bash +mkdir -p /opt/zerofs/cache && chown -R 1001:1001 /opt/zerofs/cache + +docker run -d --name zerofs --network oo-rustfs_default -p 2049:2049 \ + -e ZEROFS_PASSWORD= \ + -e AWS_ACCESS_KEY_ID= \ + -e AWS_SECRET_ACCESS_KEY= \ + -v /opt/zerofs/zerofs.toml:/zerofs.toml:ro \ + -v /opt/zerofs/cache:/cache \ + ghcr.io/barre/zerofs:latest run -c /zerofs.toml +``` + +```text +INFO zerofs::nfs: NFS server listening on 0.0.0.0:2049 +``` + +## 3. Mount over NFS + +On the host, mount the export with the options ZeroFS recommends: + +```bash +apt-get install -y nfs-common +mkdir -p /mnt/zerofs + +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +The mount is an ordinary POSIX filesystem: + +```bash +echo "written via zerofs nfs mount on rustfs" > /mnt/zerofs/hello.txt +dd if=/dev/urandom of=/mnt/zerofs/data/inner/blob.bin bs=1M count=8 +``` + +## 4. Verify persistence and objects in RustFS + +Force pending writes to the bucket, then restart ZeroFS and remount: + +```bash +docker exec zerofs zerofs flush -c /zerofs.toml +umount /mnt/zerofs +docker restart zerofs +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +Everything written before the restart is still there: + +```bash +cat /mnt/zerofs/hello.txt +sha1sum /mnt/zerofs/data/inner/blob.bin +``` + +```text +written via zerofs nfs mount on rustfs +645faaefe499f9ebda8edceeeb1a6261999aece7 /mnt/zerofs/data/inner/blob.bin +``` + +List the bucket to see where the files actually live: + +```bash +rc ls rustfs/zerofs-demo/ -r | head -4 +``` + +```text +zerofs-data/compacted/01M40Q1RA0X3AVG76VC0SBYE58.sst +zerofs-data/manifest/0000000000000000.json +zerofs-data/wal/00000000000000000001.sst +``` + +Files are not stored 1:1 — they are keys and values inside the LSM tree, which is what lets ZeroFS serve a bucket as a filesystem. + +![ZeroFS LSM data stored in the RustFS Console](./images/rustfs-zerofs-data.png) + +## 5. Stop or reset + +To tear down the demo while keeping the bucket objects: + +```bash +umount /mnt/zerofs +docker rm -f zerofs +``` + +To delete the stored data (this erases the filesystem itself): + +```bash +rc rm rustfs/zerofs-demo/ --recursive --force +``` + +## Troubleshooting + +### `Failed to parse config file: missing field uid` at `[servers.webui]` + +ZeroFS v2.3.5 requires `uid` and `gid` in the `[servers.webui]` section when it is present. Either add `uid = 1000` and `gid = 1000` or delete the section entirely if you do not need the Web UI. + +### `Permission denied` creating the cache directory + +The container runs as UID 1001. After mounting the cache volume, run `chown -R 1001:1001 ` before starting the container. + +### Mount fails or hangs + +Confirm the NFS client package is installed (`nfs-common`) and that ZeroFS is listening on `0.0.0.0:2049` inside a network your client can reach. The `port=2049,mountport=2049` options matter because ZeroFS serves the mountd traffic on the same port. + +### Writes vanish after a container crash + +ZeroFS buffers writes and flushes periodically. For the demo, run `docker exec zerofs zerofs flush -c /zerofs.toml`; in production, clients that need strict durability should fsync (or use the 9P mount, whose fsync waits for stable storage). + +## Next steps + +- Review [S3 compatibility notes](/administration/protocols/s3) before adopting additional ZeroFS backends. +- Create dedicated production credentials with [Access Key Management](/security-compliance/iam/access-token). +- Follow the [ZeroFS configuration guide](https://www.zerofs.net/configuration) for cache sizing, 9P/NBD serving, and high-availability replication over the same bucket. diff --git a/content/fr/developer/integration/index.md b/content/fr/developer/integration/index.md index d50853c1..a0ca8ead 100644 --- a/content/fr/developer/integration/index.md +++ b/content/fr/developer/integration/index.md @@ -10,7 +10,7 @@ Utilisez cette section pour connecter **RustFS** à des plateformes d'infrastruc - [Reverse Proxy](./reverse-proxy/index.md) couvre Nginx, Traefik, Caddy, HAProxy et Envoy. - [Backup](./backup/index.md) couvre Kopia, Longhorn, Restic et Velero. - [IA](./ai/index.md) couvre les plateformes d'IA incluant Ray et vLLM. -- [Analyse de données](./big-data/index.md) couvre les systèmes d'analyse incluant Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess et Zeppelin. +- [Analyse de données](./big-data/index.md) couvre les systèmes d'analyse incluant Airflow, ClickHouse, Delta Lake, Doris, Hudi, Iceberg, Kafka, lakeFS, Milvus, OpenDAL, Vitess, Zeppelin et ZeroFS. - [Cloud Native](./cloud-native/index.md) couvre Cortex et Flux. - [Observabilité](./observability/index.md) couvre les systèmes de télémétrie incluant Fluentd, GreptimeDB, Loki, OpenObserve, OpenTelemetry, Tempo, Thanos et VictoriaMetrics. - [Autres](./others/index.md) couvre le SDK capo, rclone, JuiceFS, Nextcloud et tusd. diff --git a/content/ja/developer/integration/big-data/images/rustfs-zerofs-data.png b/content/ja/developer/integration/big-data/images/rustfs-zerofs-data.png new file mode 100644 index 00000000..ee417c27 Binary files /dev/null and b/content/ja/developer/integration/big-data/images/rustfs-zerofs-data.png differ diff --git a/content/ja/developer/integration/big-data/index.md b/content/ja/developer/integration/big-data/index.md index e3adb48b..e37be8ad 100644 --- a/content/ja/developer/integration/big-data/index.md +++ b/content/ja/developer/integration/big-data/index.md @@ -24,6 +24,7 @@ Use **RustFS** as the object storage layer for data analytics systems that suppo - [Spark](./spark.md) - [Flink](./flink.md) - [Trino](./trino.md) +- [ZeroFS](./zerofs.md) - [Vitess](./vitess.md) Keep application data in a dedicated bucket and prefix, and use credentials scoped to the required bucket operations. \ No newline at end of file diff --git a/content/ja/developer/integration/big-data/meta.json b/content/ja/developer/integration/big-data/meta.json index ac3449c1..38c1139d 100644 --- a/content/ja/developer/integration/big-data/meta.json +++ b/content/ja/developer/integration/big-data/meta.json @@ -18,6 +18,7 @@ "pyiceberg", "spark", "trino", + "zerofs", "vitess", "zeppelin" ] diff --git a/content/ja/developer/integration/big-data/zerofs.md b/content/ja/developer/integration/big-data/zerofs.md new file mode 100644 index 00000000..2dd1640b --- /dev/null +++ b/content/ja/developer/integration/big-data/zerofs.md @@ -0,0 +1,174 @@ +--- +title: "ZeroFS" +description: "Serve a RustFS bucket as a POSIX filesystem over NFS with ZeroFS." +--- + +This guide connects [ZeroFS](https://github.com/Barre/ZeroFS) — the log-structured filesystem that serves S3 buckets as POSIX filesystems — to **RustFS** as its object storage backend. You will run ZeroFS with its LSM tree rooted in a RustFS bucket, mount the filesystem over NFS on a Linux host, write files through the mount, and verify they survive a ZeroFS restart as objects in the bucket. The workflow was verified with ZeroFS v2.3.5 (ghcr.io/barre/zerofs) against `rustfs/rustfs-x86-musl:v2.3.1`. + +You need Docker and a Linux host with an NFS client (`nfs-common`). This deployment is intended for local integration testing, not production. + +## Architecture + +```mermaid +flowchart LR + POSIX["POSIX apps"] -->|"NFS :2049"| ZeroFS["ZeroFS"] + ZeroFS -->|"LSM SSTs, WAL, manifests"| RustFS["RustFS :9000"] +``` + +ZeroFS translates filesystem operations into an LSM key-value tree stored in the bucket: writes land in a write-ahead log, flush into SST segments, and compaction runs in the background. Clients see an ordinary directory tree over NFS (or 9P/NBD). + +## 1. Generate the configuration + +Create the bucket and the config file, replacing all connection placeholders: + +```bash +rc mb rustfs/zerofs-demo + +docker run --rm -u root:root -v /opt/zerofs:/cfg -w /cfg \ + --entrypoint /bin/sh ghcr.io/barre/zerofs:latest -c "zerofs init" +``` + +Then edit `zerofs.toml` so the storage and AWS sections point at RustFS: + +```toml title="zerofs.toml" +[cache] +dir = "/cache" +disk_size_gb = 5.0 + +[storage] +url = "s3://zerofs-demo/zerofs-data" +encryption_password = "${ZEROFS_PASSWORD}" + +[servers.nfs] +addresses = ["0.0.0.0:2049"] + +[servers.rpc] +addresses = ["0.0.0.0:7000"] + +[aws] +access_key_id = "${AWS_ACCESS_KEY_ID}" +secret_access_key = "${AWS_SECRET_ACCESS_KEY}" +endpoint = "http://:9000" +default_region = "us-east-1" +allow_http = "true" +``` + +The `endpoint` plus `allow_http` pair is what redirects ZeroFS from AWS to RustFS. Custom endpoints use path-style addressing, so no extra option is needed. + +## 2. Run ZeroFS + +Run the server with the config file, credentials, and a writable cache directory (the image runs as UID 1001): + +```bash +mkdir -p /opt/zerofs/cache && chown -R 1001:1001 /opt/zerofs/cache + +docker run -d --name zerofs --network oo-rustfs_default -p 2049:2049 \ + -e ZEROFS_PASSWORD= \ + -e AWS_ACCESS_KEY_ID= \ + -e AWS_SECRET_ACCESS_KEY= \ + -v /opt/zerofs/zerofs.toml:/zerofs.toml:ro \ + -v /opt/zerofs/cache:/cache \ + ghcr.io/barre/zerofs:latest run -c /zerofs.toml +``` + +```text +INFO zerofs::nfs: NFS server listening on 0.0.0.0:2049 +``` + +## 3. Mount over NFS + +On the host, mount the export with the options ZeroFS recommends: + +```bash +apt-get install -y nfs-common +mkdir -p /mnt/zerofs + +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +The mount is an ordinary POSIX filesystem: + +```bash +echo "written via zerofs nfs mount on rustfs" > /mnt/zerofs/hello.txt +dd if=/dev/urandom of=/mnt/zerofs/data/inner/blob.bin bs=1M count=8 +``` + +## 4. Verify persistence and objects in RustFS + +Force pending writes to the bucket, then restart ZeroFS and remount: + +```bash +docker exec zerofs zerofs flush -c /zerofs.toml +umount /mnt/zerofs +docker restart zerofs +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +Everything written before the restart is still there: + +```bash +cat /mnt/zerofs/hello.txt +sha1sum /mnt/zerofs/data/inner/blob.bin +``` + +```text +written via zerofs nfs mount on rustfs +645faaefe499f9ebda8edceeeb1a6261999aece7 /mnt/zerofs/data/inner/blob.bin +``` + +List the bucket to see where the files actually live: + +```bash +rc ls rustfs/zerofs-demo/ -r | head -4 +``` + +```text +zerofs-data/compacted/01M40Q1RA0X3AVG76VC0SBYE58.sst +zerofs-data/manifest/0000000000000000.json +zerofs-data/wal/00000000000000000001.sst +``` + +Files are not stored 1:1 — they are keys and values inside the LSM tree, which is what lets ZeroFS serve a bucket as a filesystem. + +![ZeroFS LSM data stored in the RustFS Console](./images/rustfs-zerofs-data.png) + +## 5. Stop or reset + +To tear down the demo while keeping the bucket objects: + +```bash +umount /mnt/zerofs +docker rm -f zerofs +``` + +To delete the stored data (this erases the filesystem itself): + +```bash +rc rm rustfs/zerofs-demo/ --recursive --force +``` + +## Troubleshooting + +### `Failed to parse config file: missing field uid` at `[servers.webui]` + +ZeroFS v2.3.5 requires `uid` and `gid` in the `[servers.webui]` section when it is present. Either add `uid = 1000` and `gid = 1000` or delete the section entirely if you do not need the Web UI. + +### `Permission denied` creating the cache directory + +The container runs as UID 1001. After mounting the cache volume, run `chown -R 1001:1001 ` before starting the container. + +### Mount fails or hangs + +Confirm the NFS client package is installed (`nfs-common`) and that ZeroFS is listening on `0.0.0.0:2049` inside a network your client can reach. The `port=2049,mountport=2049` options matter because ZeroFS serves the mountd traffic on the same port. + +### Writes vanish after a container crash + +ZeroFS buffers writes and flushes periodically. For the demo, run `docker exec zerofs zerofs flush -c /zerofs.toml`; in production, clients that need strict durability should fsync (or use the 9P mount, whose fsync waits for stable storage). + +## Next steps + +- Review [S3 compatibility notes](/administration/protocols/s3) before adopting additional ZeroFS backends. +- Create dedicated production credentials with [Access Key Management](/security-compliance/iam/access-token). +- Follow the [ZeroFS configuration guide](https://www.zerofs.net/configuration) for cache sizing, 9P/NBD serving, and high-availability replication over the same bucket. diff --git a/content/ja/developer/integration/index.md b/content/ja/developer/integration/index.md index 54d85ff5..7bf4fd08 100644 --- a/content/ja/developer/integration/index.md +++ b/content/ja/developer/integration/index.md @@ -10,7 +10,7 @@ description: "RustFS をリバースプロキシ、バックアップツール - [Reverse Proxy](./reverse-proxy/index.md) は Nginx、Traefik、Caddy、HAProxy、Envoy を扱います。 - [Backup](./backup/index.md) は Kopia、Longhorn、Restic、Velero を扱います。 - [AI](./ai/index.md) は Ray、vLLM などの AI プラットフォームを扱います。 -- [データ分析](./big-data/index.md) は Airflow、ClickHouse、Delta Lake、Doris、Hudi、Iceberg、Kafka、lakeFS、Milvus、OpenDAL、Vitess、Zeppelin などの分析システムを扱います。 +- [データ分析](./big-data/index.md) は Airflow、ClickHouse、Delta Lake、Doris、Hudi、Iceberg、Kafka、lakeFS、Milvus、OpenDAL、Vitess、Zeppelin、ZeroFS などの分析システムを扱います。 - [クラウドネイティブ](./cloud-native/index.md) は Cortex、Flux を扱います。 - [オブザーバビリティ](./observability/index.md) は Fluentd、GreptimeDB、Loki、OpenObserve、OpenTelemetry、Tempo、Thanos、VictoriaMetrics などのテレメトリシステムを扱います。 - [その他](./others/index.md) は capo SDK、rclone、JuiceFS、Nextcloud、tusd などのツールを扱います。 diff --git a/content/zh/developer/integration/big-data/images/rustfs-zerofs-data.png b/content/zh/developer/integration/big-data/images/rustfs-zerofs-data.png new file mode 100644 index 00000000..e8a09736 Binary files /dev/null and b/content/zh/developer/integration/big-data/images/rustfs-zerofs-data.png differ diff --git a/content/zh/developer/integration/big-data/index.md b/content/zh/developer/integration/big-data/index.md index eb84c3b2..317d0222 100644 --- a/content/zh/developer/integration/big-data/index.md +++ b/content/zh/developer/integration/big-data/index.md @@ -24,6 +24,7 @@ description: "通过 S3 兼容的对象存储接口将数据分析系统连接 - [Spark](./spark.md) - [Flink](./flink.md) - [Trino](./trino.md) +- [ZeroFS](./zerofs.md) - [Vitess](./vitess.md) 将应用程序数据保存在专用存储桶和前缀中,并使用作用域限定为所需存储桶操作的凭证。 \ No newline at end of file diff --git a/content/zh/developer/integration/big-data/meta.json b/content/zh/developer/integration/big-data/meta.json index a4a40862..876032d9 100644 --- a/content/zh/developer/integration/big-data/meta.json +++ b/content/zh/developer/integration/big-data/meta.json @@ -18,6 +18,7 @@ "pyiceberg", "spark", "trino", + "zerofs", "vitess", "zeppelin" ] diff --git a/content/zh/developer/integration/big-data/zerofs.md b/content/zh/developer/integration/big-data/zerofs.md new file mode 100644 index 00000000..344cd2d8 --- /dev/null +++ b/content/zh/developer/integration/big-data/zerofs.md @@ -0,0 +1,174 @@ +--- +title: "ZeroFS" +description: "用 ZeroFS 把 RustFS 桶作为 POSIX 文件系统通过 NFS 提供。" +--- + +本指南将"以 S3 为底的日志结构文件系统"[ZeroFS](https://github.com/Barre/ZeroFS) 连接到 **RustFS** 作为其对象存储后端。你将运行一个 LSM 树根植于 RustFS 桶的 ZeroFS 实例,在 Linux 主机上通过 NFS 挂载该文件系统,经挂载点写入文件,并验证它们在 ZeroFS 重启后作为桶内对象持久存在。整个流程使用 ZeroFS v2.3.5(ghcr.io/barre/zerofs)对 `rustfs/rustfs-x86-musl:v2.3.1` 验证通过。 + +你需要 Docker 以及装有 NFS 客户端(`nfs-common`)的 Linux 主机。本部署用于本地集成测试,不适用于生产环境。 + +## 架构 + +```mermaid +flowchart LR + POSIX["POSIX apps"] -->|"NFS :2049"| ZeroFS["ZeroFS"] + ZeroFS -->|"LSM SSTs, WAL, manifests"| RustFS["RustFS :9000"] +``` + +ZeroFS 把文件系统操作翻译为存放在桶内的 LSM 键值树:写入先进 WAL,再刷成 SST 段,压实(compaction)在后台进行。客户端通过 NFS(或 9P/NBD)看到的就是一棵普通目录树。 + +## 1. 生成配置 + +创建桶和配置文件,替换全部连接占位符: + +```bash +rc mb rustfs/zerofs-demo + +docker run --rm -u root:root -v /opt/zerofs:/cfg -w /cfg \ + --entrypoint /bin/sh ghcr.io/barre/zerofs:latest -c "zerofs init" +``` + +然后编辑 `zerofs.toml`,把 storage 与 aws 段指向 RustFS: + +```toml title="zerofs.toml" +[cache] +dir = "/cache" +disk_size_gb = 5.0 + +[storage] +url = "s3://zerofs-demo/zerofs-data" +encryption_password = "${ZEROFS_PASSWORD}" + +[servers.nfs] +addresses = ["0.0.0.0:2049"] + +[servers.rpc] +addresses = ["0.0.0.0:7000"] + +[aws] +access_key_id = "${AWS_ACCESS_KEY_ID}" +secret_access_key = "${AWS_SECRET_ACCESS_KEY}" +endpoint = "http://:9000" +default_region = "us-east-1" +allow_http = "true" +``` + +`endpoint` 加 `allow_http` 两个键负责把 ZeroFS 从 AWS 重定向到 RustFS。自定义端点使用路径风格寻址,无需额外选项。 + +## 2. 运行 ZeroFS + +带配置文件、凭证和可写缓存目录启动(镜像以 UID 1001 运行): + +```bash +mkdir -p /opt/zerofs/cache && chown -R 1001:1001 /opt/zerofs/cache + +docker run -d --name zerofs --network oo-rustfs_default -p 2049:2049 \ + -e ZEROFS_PASSWORD= \ + -e AWS_ACCESS_KEY_ID= \ + -e AWS_SECRET_ACCESS_KEY= \ + -v /opt/zerofs/zerofs.toml:/zerofs.toml:ro \ + -v /opt/zerofs/cache:/cache \ + ghcr.io/barre/zerofs:latest run -c /zerofs.toml +``` + +```text +INFO zerofs::nfs: NFS server listening on 0.0.0.0:2049 +``` + +## 3. 通过 NFS 挂载 + +在主机上用 ZeroFS 推荐的参数挂载导出: + +```bash +apt-get install -y nfs-common +mkdir -p /mnt/zerofs + +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +挂载点就是一个普通的 POSIX 文件系统: + +```bash +echo "written via zerofs nfs mount on rustfs" > /mnt/zerofs/hello.txt +dd if=/dev/urandom of=/mnt/zerofs/data/inner/blob.bin bs=1M count=8 +``` + +## 4. 验证持久化与 RustFS 中的对象 + +强制把未落盘写入刷进桶,然后重启 ZeroFS 并重新挂载: + +```bash +docker exec zerofs zerofs flush -c /zerofs.toml +umount /mnt/zerofs +docker restart zerofs +mount -t nfs -o async,nolock,rsize=1048576,wsize=1048576,tcp,port=2049,mountport=2049,hard \ + 127.0.0.1:/ /mnt/zerofs +``` + +重启前写入的内容完好无损: + +```bash +cat /mnt/zerofs/hello.txt +sha1sum /mnt/zerofs/data/inner/blob.bin +``` + +```text +written via zerofs nfs mount on rustfs +645faaefe499f9ebda8edceeeb1a6261999aece7 /mnt/zerofs/data/inner/blob.bin +``` + +列举桶,看文件实际存放的位置: + +```bash +rc ls rustfs/zerofs-demo/ -r | head -4 +``` + +```text +zerofs-data/compacted/01M40Q1RA0X3AVG76VC0SBYE58.sst +zerofs-data/manifest/0000000000000000.json +zerofs-data/wal/00000000000000000001.sst +``` + +文件并非一对一存放——它们是 LSM 树里的键值,这正是 ZeroFS 能把桶当文件系统服务的原因。 + +![存储在 RustFS 控制台中的 ZeroFS LSM 数据](./images/rustfs-zerofs-data.png) + +## 5. 停止或重置 + +保留桶内对象、仅拆除演示环境: + +```bash +umount /mnt/zerofs +docker rm -f zerofs +``` + +删除已存储的数据(等同于销毁文件系统本身): + +```bash +rc rm rustfs/zerofs-demo/ --recursive --force +``` + +## 故障排查 + +### 启动报 `Failed to parse config file: missing field uid`(位于 `[servers.webui]`) + +ZeroFS v2.3.5 中 `[servers.webui]` 段一旦存在就必须包含 `uid` 与 `gid`。补上 `uid = 1000`、`gid = 1000`,不需要 Web UI 时也可以整段删除。 + +### 创建缓存目录报 `Permission denied` + +容器以 UID 1001 运行。挂载缓存卷后先执行 `chown -R 1001:1001 ` 再启动容器。 + +### 挂载失败或卡住 + +确认已安装 NFS 客户端(`nfs-common`),且 ZeroFS 在客户端可达的网络里监听 `0.0.0.0:2049`。`port=2049,mountport=2049` 两个参数很关键——ZeroFS 把 mountd 流量也放在同一端口上。 + +### 容器崩溃后写入丢失 + +ZeroFS 会缓冲写入并周期性刷盘。演示环境可执行 `docker exec zerofs zerofs flush -c /zerofs.toml`;生产环境中需要严格持久性的客户端应调用 fsync(或使用 9P 挂载,其 fsync 会等到数据进入稳定存储才返回)。 + +## 下一步 + +- 在启用更多 ZeroFS 后端前,先阅读 [S3 兼容性说明](/administration/protocols/s3)。 +- 使用[访问密钥管理](/security-compliance/iam/access-token)创建专用的生产凭证。 +- 按照 [ZeroFS 配置指南](https://www.zerofs.net/configuration)了解缓存容量、9P/NBD 服务以及基于同一桶的高可用复制。 diff --git a/content/zh/developer/integration/index.md b/content/zh/developer/integration/index.md index 131694e6..3a039635 100644 --- a/content/zh/developer/integration/index.md +++ b/content/zh/developer/integration/index.md @@ -10,7 +10,7 @@ description: "将 RustFS 与反向代理、备份工具、数据分析系统、A - [反向代理](./reverse-proxy/index.md)涵盖 Nginx、Traefik、Caddy、HAProxy 和 Envoy。 - [备份](./backup/index.md)涵盖 Kopia、Longhorn、Restic 和 Velero。 - [AI](./ai/index.md)涵盖 Ray、vLLM 等 AI 平台。 -- [数据分析](./big-data/index.md)涵盖 Airflow、ClickHouse、Delta Lake、Doris、Hudi、Iceberg、Kafka、lakeFS、Milvus、OpenDAL、Vitess 和 Zeppelin 等数据分析系统。 +- [数据分析](./big-data/index.md)涵盖 Airflow、ClickHouse、Delta Lake、Doris、Hudi、Iceberg、Kafka、lakeFS、Milvus、OpenDAL、Vitess、Zeppelin 和 ZeroFS 等数据分析系统。 - [云原生](./cloud-native/index.md)涵盖 Cortex 与 Flux。 - [可观测性](./observability/index.md)涵盖 Fluentd、GreptimeDB、Loki、OpenObserve、OpenTelemetry、Tempo、Thanos 和 VictoriaMetrics 等遥测系统。 - [其他](./others/index.md)涵盖 capo SDK、rclone、JuiceFS、Nextcloud 和 tusd 等工具。