后起之秀——rustfs对象存储
rustfs介绍 RustFS 是用 Rust 从零写成的分布式对象存储,完全兼容 S3 协议。处理小对象时,吞吐量达到 MinIO 的 2.3 倍;许可证选用宽松的 Apache 2.0(MinI
后起之秀——rustfs对象存储
发布时间:2026-01-21 (2026-01-21)

rustfs介绍

RustFS 是用 Rust 从零写成的分布式对象存储,完全兼容 S3 协议。处理小对象时,吞吐量达到 MinIO 的 2.3 倍;许可证选用宽松的 Apache 2.0(MinIO 为 AGPLv3)。WORM 合规、加密、多站点复制——企业级功能一应俱全。

项目目前仍处于 Beta 阶段,但对于被 MinIO 协议卡住的团队,它已经是最值得关注的替代选项。

本课程就从rustfs的安装、界面基本操作、基于s3协议的go语言操作以及rustfs的分布式部署进行课程学习

rustfs中文官方文档:https://docs.rustfs.com.cn/installation/

rustfs的安装

还是首推使用docker进行rustfs的安装,主要是为了方便做版本管理

直接两条命令快速搞定

mkdir -p rustfs/data && chown -R 10001:10001 rustfs
docker run -d --name rustfs  -p 9000:9000  -p 9001:9001 -v $(pwd)/rustfs/data:/data rustfs/rustfs:1.0.0-alpha.80 /data

默认用户名密码都是 rustfsadmin

如果需要修改,配置RUSTFS_ACCESS_KEYRUSTFS_SECRET_KEY环境变量

docker run -d --name rustfs  -p 9000:9000 -e RUSTFS_ACCESS_KEY="fengfeng" -e RUSTFS_SECRET_KEY="12345678" -p 9001:9001 -v $(pwd)/rustfs/data:/data rustfs/rustfs:1.0.0-alpha.80 /data

或者使用docker-compose

version: "3.9"

services:
  rustfs:
    image: rustfs/rustfs:1.0.0-alpha.80
    container_name: rustfs
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - RUSTFS_VOLUMES=/data
    volumes:
      - ./data:/data
    restart: unless-stopped

9001端口就是rustfs的web管理界面,默认用户名密码都是 rustfsadmin

9000端口就是s3 api接口的端口

rustfs web界面的基本操作

存储桶操作

创建和minio的区别不大,都有版本控制、对象锁、存储桶大小限制

区别就是版本控制目前没有前缀过滤

修改存储桶权限

存储桶右边有一个编辑,点开就可以更改它的访问策略

文件的访问路径是 http://host/<桶名>/<对象名>

用户操作

创建一个只能查看文件列表的用户

在用户菜单创建一个只有readonly策略的用户,然后可以打开存储桶的访问策略

然后登录新创建的用户,它能看到的页面是这样的

默认的readonly是直接存储桶列表、对象下载策略的,没有对象列表策略的

所以点进存储桶会报错

所以可以自定义一个策略,分配给用户

{
  "ID": "",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "",
      "Effect": "Allow",
      "Action": [
        "s3:ListBucket",
        "s3:GetObject"
      ],
      "NotAction": [],
      "Resource": [
        "arn:aws:s3:::*"
      ],
      "NotResource": [],
      "Condition": {}
    }
  ]
}

rustfs预览图片的方式是直接将认证信息带到查询参数上的,所以存储桶私有的情况下,访问这个预览地址也是可以访问到的

s3 api操作

不想改之前的代码,可以直接用minio的那个客户端

或者可以用go s3这个客户端

本课程的minio-go版本

github.com/minio/minio-go/v7 v7.0.97 // indirect
package main

import (
  "context"
  "encoding/json"
  "fmt"
  "github.com/gin-gonic/gin"
  "github.com/minio/minio-go/v7"
  "github.com/minio/minio-go/v7/pkg/credentials"
  "io"
  "os"
)

var client *minio.Client
var endPoint = "192.168.80.188:9000"

func init() {
  accessKey := "rustfsadmin"
  accessSecret := "rustfsadmin"

  // 初始化minio客户端
  _client, err := minio.New(endPoint, &minio.Options{
    Creds:  credentials.NewStaticV4(accessKey, accessSecret, ""),
    Secure: false,
  })
  if err != nil {
    fmt.Println(err)
    os.Exit(0)
  }
  client = _client
}

func bucketList() {
  list, err := client.ListBuckets(context.Background())
  if err != nil {
    fmt.Println(err)
    return
  }
  for _, info := range list {
    fmt.Println(info.Name)
  }
}

func bucketCreate() {
  err := client.MakeBucket(context.Background(), "demo2", minio.MakeBucketOptions{})
  fmt.Println(err)
}

func uploadFile1() {
  info, err := client.FPutObject(context.Background(), "demo2", "0114/ssh隧道命令.jpg", "ssh隧道命令.jpg", minio.PutObjectOptions{
    UserMetadata: map[string]string{
      "userId": "1",
      "userIp": "2.5.21.22",
    },
  })
  if err != nil {
    fmt.Println(err)
    return
  }

  byteData, _ := json.Marshal(info)
  fmt.Println(string(byteData))
}

func fileList() {
  ch := client.ListObjects(context.Background(), "demo2", minio.ListObjectsOptions{
    Recursive:    true,
    Prefix:       "uploads",
    WithMetadata: true,
    MaxKeys:      1,
  })
  for info := range ch {
    fmt.Println(info.Key, info.LastModified, info.UserMetadata)
  }
}

func main() {
  //bucketCreate()
  //bucketList()
  uploadFile1()
  fileList()
}

rustfs配置SSL

参考文档:https://docs.rustfs.com.cn/integration/tls-configured.html

证书对的名称必须为 rustfs_cert.pem 和 rustfs_key.pem

先生成证书

#!/bin/bash
# 证书有效期(天)
VALID_DAYS=3650
# 证书输出目录(和 docker-compose.yml 同目录)
CERT_DIR="./certs"

# 1. 创建证书目录
mkdir -p ${CERT_DIR}

cat > ${CERT_DIR}/cert_ssl.conf <<EOF
[req]
req_extensions = v3_req
distinguished_name = req_distinguished_name
prompt = no

[req_distinguished_name]
C = CN
ST = Beijing
L = Beijing
O = MyOrg
OU = MyDept
CN = 192.168.80.174

[v3_req]
basicConstraints = CA:TRUE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
IP.1 = 192.168.80.174
IP.2 = 192.168.80.176
IP.3 = 127.0.0.1
EOF


openssl req -x509 -nodes -days ${VALID_DAYS} -newkey rsa:2048  -keyout ${CERT_DIR}/rustfs_key.pem -out ${CERT_DIR}/rustfs_cert.pem  -config ${CERT_DIR}/cert_ssl.conf

# 4. 清理临时配置文件(可选)
rm -f ${CERT_DIR}/cert_ssl.conf

# 5. 验证证书(输出关键信息)
echo -e "\n证书生成完成!路径:${CERT_DIR}"
echo "证书包含的 SAN 扩展:"
openssl x509 -in ${CERT_DIR}/rustfs_cert.pem -text -noout | grep -A 1 "Subject Alternative Name"

docker的方式

docker run -d --name rustfs1  -e RUSTFS_TLS_PATH=/opt/tls/   -v /opt/rustfs_study/rustfs/certs:/opt/tls  -p 9000:9000  -p 9001:9001  -v /opt/rustfs/data/:/data   rustfs/rustfs:1.0.0-alpha.80

docker compose的方式

version: "3.9"

services:
  rustfs:
    image: rustfs/rustfs:1.0.0-alpha.80
    container_name: rustfs
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - RUSTFS_VOLUMES=/data
      - RUSTFS_TLS_PATH=/opt/tls/
    volumes:
      - /opt/rustfs/data/:/data
      - /opt/rustfs_study/rustfs/certs/:/opt/tls/
    restart: unless-stopped

分布式部署

用docker compose的方式

目前我测试下来,只能用docker的host模式可以部署成功,其他发方式好像不太行

有几个注意点需要注意:

  1. RUSTFS_VOLUMES必须是连续的主机名,一般通过修改hosts来完成

先修改hosts的ip映射,这样就可以设置连续的域名节点了

192.168.80.188 node0
192.168.80.189 node1

先批量创建目录

rm -rf /opt/rustfs
mkdir -p /opt/rustfs/data{0..3} && chown -R 10001:10001 /opt/rustfs
version: "3.9"

services:
  rustfs:
    image: rustfs/rustfs:1.0.0-alpha.80
    container_name: rustfs
    environment:
      - RUSTFS_VOLUMES=http://node{0...1}:9000/data{0...3}
      - RUSTFS_ACCESS_KEY=rustfsadmin
      - RUSTFS_SECRET_KEY=rustfsadmin
    volumes:
      - /opt/rustfs/data0/:/data0
      - /opt/rustfs/data1/:/data1
      - /opt/rustfs/data2/:/data2
      - /opt/rustfs/data3/:/data3
    network_mode: host
    restart: unless-stopped