云镜之端

RustFS使用文档

RustFS 完整手册 适用版本:RustFS 1.0.x 官网:https://rustfs.org.cn | 文档中心:https://docs.rustfs.com/zh | 仓库:https://github.com/rustfs/rustfs 许可证:Apache License 2.0

  • 作者
  • 1 分钟阅读
评论
RustFS使用文档

RustFS 完整手册

适用版本:RustFS 1.0.x
官网:https://rustfs.org.cn | 文档中心:https://docs.rustfs.com/zh | 仓库:https://github.com/rustfs/rustfs
许可证:Apache License 2.0

版本说明: 本手册描述撰写时有文档记载的 RustFS 行为。RustFS 仍在积极开发中,命令名称、选项、环境变量和控制台标签可能发生变化。标记为 (verify) 的条目,请对照你所部署版本的官方文档(https://docs.rustfs.com)和代码仓库(https://github.com/rustfs/rustfs)进行确认。在 RustFS 遵循 Amazon S3 API 的地方,S3 示例使用标准的 AWS CLI 和 SDK,它们可对接任何兼容端点。


目录

第一部分 — 基础与规划

第二部分 — 安装与初始设置

第三部分 — 身份与访问

第四部分 — 数据管理

第五部分 — 存储策略

第六部分 — 程序接入与接口

第七部分 — 运维

第八部分 — 高级特性

第九部分 — 配置与性能

第十部分 — 生产与参考


第一部分 — 基础与规划


1. RustFS 是什么

RustFS 是一款使用 Rust 语言开发的、100% 兼容 S3 协议的开源分布式对象存储系统。它采用 Apache 2.0 许可证,是 MinIO 和 Ceph 的国产平替,面向 AI 数据中心、云原生与大规模企业工作负载。

关键特征:

维度说明
开发语言Rust(内存安全、高性能、低开销)
开源许可证Apache 2.0(商业友好,无厂商锁定)
协议兼容 Amazon S3 API(V2 / V4 签名)
部署形态单机单盘、单机多盘、多机多盘、Docker、Kubernetes(Helm/Operator)
扩展能力PB 级 / EB 级
二进制体积约 100 MB 静态二进制,单进程运行
实测性能读取最高 323 GB/s、写入最高 183 GB/s

RustFS 实现了数据存储、纠删码(Erasure Coding)、版本控制、对象锁定、生命周期、跨区域复制、加密、事件通知、可观测性(Prometheus/OTel)等企业级对象存储能力,并提供 Web 控制台(Console)、命令行客户端(rc)、兼容 mc / AWS CLI、多种 SDK 以及 MCP 服务器。

1.1 设计哲学

  • 无元数据中心:所有节点地位对等,无 Master / NameNode / MetaData 节点,消除元数据单点故障;
  • 数据与元数据共同存储:作为对象一起写入,无需元数据数据库;
  • 内联操作:纠删码、bitrot 检查、加密均作为内联、严格一致的操作执行;
  • 云原生:单进程、轻量协程高并发,可作为轻量容器运行,支持多租户共置。

1.2 典型部署场景

  • 自托管的主对象存储,用于应用数据、上传文件和媒体资源
  • 私有云或本地部署,替代公有云存储桶
  • 热/冷分层,近期数据保留在本地,较旧数据迁移到更廉价的远程存储
  • 备份与归档目标,用于数据库、容器平台和终端备份
  • 数据湖与分析存储,服务于 Spark、Trino 等支持 S3 协议的引擎

2. RustFS 能解决什么问题

2.1 解决存储的高性能与海量扩展问题

  • 数据量达到 PB 级甚至 EB 级时,传统 NAS/SAN 或单机文件系统无法线性扩展;
  • RustFS 采用无元数据中心的对称架构,可线性水平扩展,且不存在元数据节点单点故障。

2.2 解决数据安全与高可用问题

  • 通过 Reed-Solomon 纠删码(默认 12 数据块 + 4 校验块),容忍任意 4 块磁盘或任意 1 台服务器故障而数据不丢失;
  • 自动 bitrot 检测与自愈(healing),发现并修复静默损坏。

2.3 解决厂商锁定与成本问题

  • 标准 S3 协议让应用无需修改即可从 AWS S3 / MinIO 迁移;
  • 开源(Apache 2.0)+ 自托管,存储规模增大后价格与支持成本可预测;
  • 无元数据中心,部署运维难度远低于 Ceph。

2.4 解决合规与安全要求

  • 对象锁定 / WORM(SEC 17a-4(f)、FINRA 4511、CFTC 1.31 合规,获 Cohasset 认证);
  • 服务端加密(SSE-S3 / SSE-C / SSE-KMS),数据静态加密 + 传输加密;
  • 审计日志、事件通知,可对接 SIEM;
  • 支持国产信创与国密(SM)体系。

2.5 解决 AI 与云原生基础设施问题

  • 面向 AI 工作负载(模型、数据集、Checkpoint 存储);
  • 支持 S3 Tables(Apache Iceberg 表);
  • 原生 RDMA / DPU 卸载(NVIDIA Inception Program 合作伙伴);
  • 可通过 MCP 让 AI 智能体(Claude、Cursor、Trae 等)直接操控对象存储。

3. 什么情况需要使用 RustFS

在以下场景,使用 RustFS 是理想选择:

  1. 需要 S3 兼容对象存储,但不想依赖公有云:私有化部署 / 混合云 / 边缘计算。
  2. 要替代 MinIO / Ceph:尤其看重 Apache 2.0 许可、内存安全、国产化替换。
  3. 有海量非结构化数据:图片、视频、日志、备份、文档、AI 数据集等。
  4. 需要高性能读写:AI 训练、大数据计算存储分离、量化交易等低延迟、高吞吐场景。
  5. 需要企业级数据安全与合规:金融、政务、医疗、档案馆等需要 WORM、加密、审计的行业。
  6. 团队需要快速集成:已有 S3 SDK / mc / AWS CLI,或需要 MCP 接入 AI 工具链。
  7. 需要多租户、多用户、精细权限管理:IAM 用户/组/策略/服务账户。

4. RustFS 相比其他方案的优势

4.1 与 Ceph / MinIO 对比

参数CephMinIORustFS
开发语言C++GoRust
开源许可证GPL/LGPLAGPL-3.0Apache-2.0(优)
元数据中心有无无
块存储 / 文件存储支持不支持不支持(专注 S3)
使用难度高低低
硬件需求资源占用高中低,硬件要求低
内存稳定性稳定高并发下抖动较高稳定
扩容难度高难度低难度低
再平衡资源占用高低低
内存安全依赖实现规范依赖运行时Rust 原生内存安全
遥测/日志—部分可能离开本地自托管,不外发日志
性能依赖硬件配置高(与 RustFS 同属唯二领先)高(读 323 GB/s / 写 183 GB/s)

许可证优势:MinIO 使用 AGPL-3.0(商用分发有严格互惠条款),RustFS 使用 Apache 2.0,商业友好、无厂商绑定,适合二次开发和商业集成。

性能优势:RustFS 与 MinIO 是全世界速度唯二领先的分布式对象存储,同等配置下显著快于 Ceph。

4.2 架构优势:无元数据中心

特性有元数据中心(Ceph)无元数据中心(RustFS/MinIO)
元数据管理集中在元数据服务器分布在存储节点
单点故障元数据服务器可能单点无单点故障
部署复杂度高低
高并发瓶颈元数据服务器可能成为瓶颈无集中瓶颈
小文件表现好占用更多 IOPS(需注意)

5. 概念与架构

5.1 存储层级

术语含义
磁盘/驱动器(Drive)提供给 RustFS 用于存储数据的磁盘或目录。
节点(Node)运行 RustFS 进程并管理一个或多个驱动器的服务器。
纠删集(Erasure set)一组驱动器,对象以数据分片和校验分片的形式在其中编码。对象分散在同一个集的各驱动器上。
服务器池(Server pool)作为整体加入的一组节点和驱动器。集群可以通过增加池来扩容。
集群(Cluster)服务同一个命名空间的所有节点和池。
存储桶(Bucket)对象的顶层容器。
对象(Object)数据加元数据,在存储桶内由一个键(key)标识。
对象版本(Object version)启用版本控制后,由版本 ID 标识的对象的特定修订。
删除标记(Delete marker)一个占位版本,表示对象已被删除但旧版本仍保留。
层(Tier)远程存储目标(另一个 RustFS 集群或第三方 S3 兼容/云服务),生命周期规则可将对象转入其中。
生命周期规则(Lifecycle rule)存储桶级规则,基于对象年龄、前缀或标签使其过期或转层。
主体(Principal)发起请求的身份:根账户、IAM 用户、服务账户,或通过 SSO 来自外部提供者的身份。
策略(Policy)授予或拒绝某些资源操作的 JSON 文档。
访问密钥(Access key)用于签名 API 请求的 ID 与密钥对。

5.2 纠删编码与数据保护

RustFS 通过将每个对象拆分为数据分片并计算校验分片来保护数据,然后把这些分片分布到同一纠删集内的各驱动器上。借助校验分片,集群在丢失部分驱动器或节点后仍能重建对象。在数据保持可读的前提下允许失效的驱动器比例,取决于部署所配置的纠删级别。

纠删编码保护的是硬件故障。它不能防止误删除、勒索软件、逻辑损坏或人为操作失误。针对这些风险,你需要版本控制、对象锁(如可用)、生命周期控制和集群外备份(见第 15、14 和 20 章)。

5.3 命名空间与寻址

所有节点对外呈现单一命名空间。客户端可以连接任意节点,或连接节点前的负载均衡器。多节点部署建议使用负载均衡器,避免客户端绑定到某一台服务器。

5.4 控制台与 API

  • S3 API,默认端口 9000:供应用程序、SDK 和命令行工具使用。
  • Web 控制台(Console),默认端口 9001:供管理员和最终用户浏览、配置和身份管理使用。
  • Admin API,位于 API 端点的 /rustfs/admin/ 路径下:供 CLI 和自动化使用,承载分层等 RustFS 特有功能,需要管理权限。

5.5 核心术语

概念说明
Object(对象)存储的基本单位,如文件、字节流、Anything
Bucket(桶)存储对象的逻辑空间,桶之间数据相互隔离,相当于顶层文件夹
Drive(磁盘)存储数据的物理磁盘,启动时作为参数传入
Set(集合)一组 Drive 的集合,一个对象存储在一个 Set 上
Strips(条带)Set 组合,若干驱动器组成纠删集
Erasure Coding(纠删码)Reed-Solomon 算法,数据块 + 校验块

5.6 架构要点

  • 一致性模型:所有读写严格遵循 read-after-write(写后读)一致性;
  • 对称架构:所有节点功能对等,无 Master / MetaData / Data Node 之分,一条命令即可启动集群;
  • 部署三种模式:
    • SNSD(单机单盘):零纠删校验,适合本地测试;
    • SNMD(单机多盘):单机内多盘形成纠删集;
    • MNMD(多机多盘):生产级分布式集群。

5.7 对象放置规则

  1. 一个对象存储在一个 Set 上;
  2. 一个集群划分为多个 Set;
  3. 一个 Set 包含的 Drive 数量默认由系统根据集群规模自动计算;
  4. 一个 Set 中的 Drive 尽可能分布在不同的节点上。

6. 规划部署

6.1 选择拓扑

拓扑典型用途冗余说明
单节点单驱动器(SNSD)评估、开发、CI无驱动器故障即数据丢失,绝不用于生产。
单节点多驱动器小型部门存储、边缘场景驱动器级纠删编码节点故障会导致存储离线。
多节点多驱动器生产、高可用节点级与驱动器级纠删编码生产环境推荐基线。弹性布局至少使用四个节点。(verify:你版本的最小值)
多服务器池集群增长、分阶段硬件更新按池隔离每个池是独立的纠删布局,见第 19 章。
Kubernetes Operator(Tenant)平台团队运行多租户视拓扑而定通过 RustFS Kubernetes Operator 和 Helm Chart 管理。(verify:当前 Operator CRD)

6.2 容量规划

按如下方式估算容量:

  1. 原始数据量 = 预计存储总量(包含版本和保留需求)。
  2. 开销 = 原始数据量 ×(总分片数 ÷ 数据分片数),按所选纠删布局计算。
  3. 余量 = 至少保留 20–30% 空闲,用于再平衡、增长和修复操作。

示例:100 TB 可用数据,12+4 纠删布局(16 个分片,12 个数据分片),30% 余量:

  • 受保护容量:100 TB × 16 ÷ 12 ≈ 133 TB
  • 含 30% 余量:133 TB ÷ 0.7 ≈ 190 TB 裸驱动器容量

采购硬件前,请先核实你版本的校验位设置和布局规则。(verify)

6.3 性能考量

  • 元数据密集或小对象工作负载使用 NVMe 或 SSD。
  • 大对象、容量导向且每美元吞吐重要的工作负载使用 HDD 阵列。
  • 多节点集群之间使用 10 GbE 或更高速网络。
  • 操作系统与数据驱动器分盘存放。
  • 在确定布局前,用真实的对象大小和并发量做基准测试。

6.4 存储策略:热、温、冷

一种常见策略是将本地 RustFS 存储与分层结合:

层级数据存储访问模式
热近期且频繁访问NVMe/SSD 上的本地 RustFS低延迟,读写频繁
温较旧但仍偶尔访问HDD 上的独立 RustFS 集群(见下方警示)中等延迟
冷极少访问,为合规或历史保留第三方对象存储(如低成本归档类型)或远程 RustFS 集群可接受恢复时间

生命周期规则根据数据年龄将对象从热层移到冷层。分层配置见第 17 章。

警示:不要在一个集群中混用性能等级。 RustFS 没有存储类感知能力。数据放置不遵循磁盘速度,集群以其最慢存储类的速度运行。请将热、温性能层放在独立集群或 Tenant 中,并使用生命周期分层(第 17 章)把冷数据移出热集群。

部署前先确定策略:

  • 哪些数据必须留在本地(延迟、数据主权、出口费用)。
  • 哪些数据可以迁移、多少天后迁移。
  • 取回预期:从冷存储恢复需要多长时间、费用多少。
  • 第三方提供者的出口与请求费用。
  • 退出计划:如有需要,如何把数据迁出该提供者。

第二部分 — 安装与初始设置


7. 安装

任选一种方式。Docker 是最快的评估方式;systemd 或独立二进制常用于裸金属;Kubernetes Operator 适合平台团队。

7.1 Docker(单节点,评估)

mkdir -p ./rustfs/data ./rustfs/logs

docker run -d \
  --name rustfs \
  -p 9000:9000 \
  -p 9001:9001 \
  -v "$(pwd)/rustfs/data:/data" \
  -v "$(pwd)/rustfs/logs:/logs" \
  rustfs/rustfs:<pinned-version>

生产环境请固定版本标签,而不是使用 latest。查看状态:

docker ps --filter name=rustfs
docker logs --tail 100 rustfs

7.2 Docker Compose(快速开始)

克隆仓库并使用其 Compose 文件,其中包含可选的可观测性服务:

git clone https://github.com/rustfs/rustfs.git
cd rustfs
docker compose --profile observability up -d

使用前请审阅 Compose 文件中的服务和环境变量(以你版本为准)。(verify)

快速开始到此即可用于评估。生产环境请继续按 7.3 起的完整 Docker 流程(前置准备 → 镜像 → 数据卷 → 权限 → Compose → Nginx → 验证)操作。

7.3 前置准备

  • 已安装 Docker(≥ 20.10),并能正常拉取镜像与运行容器;
  • 宿主机 9000 端口(S3 API)、9001 端口(Console)可用或自定义;
  • 数据目录(如 /mnt/rustfs/data)用于持久化对象数据。

7.4 拉取官方镜像

docker pull rustfs/rustfs:latest

7.5 最简单节点启动(SNSD)

docker run -d \
  --name rustfs_local \
  --restart unless-stopped \
  -p 9000:9000 \
  -p 9001:9001 \
  -v /mnt/rustfs/data:/data \
  rustfs/rustfs:latest \
  /data

参数说明:

参数说明
-p 9000:9000映射 S3 API Endpoint 端口
-p 9001:9001映射 Console 控制台端口
-v /mnt/rustfs/data:/data挂载数据卷
/data命令末尾的卷路径(必需参数)

7.6 使用命名卷(推荐)

docker volume create rustfs-data

docker run -d \
  --name rustfs \
  --restart unless-stopped \
  -p 9000:9000 \
  -p 9001:9001 \
  -v rustfs-data:/data \
  -e RUSTFS_ACCESS_KEY="<your-access-key>" \
  -e RUSTFS_SECRET_KEY="<your-secret-key>" \
  -e RUSTFS_ADDRESS=":9000" \
  -e RUSTFS_CONSOLE_ADDRESS=":9001" \
  -e RUSTFS_CONSOLE_ENABLE=true \
  -e RUSTFS_OBS_LOGGER_LEVEL=error \
  -e RUSTFS_OBS_LOG_DIRECTORY="/var/log/rustfs/" \
  rustfs/rustfs:latest \
  /data

安全提醒:生产环境请使用 openssl rand -base64 24 生成强密钥,切勿使用默认 rustfsadmin。

7.7 环境变量与命令行参数对照

RustFS 支持两种配置方式,命令行参数优先级更高:

# 环境变量方式(推荐)
-e RUSTFS_ADDRESS=:9000 \
-e RUSTFS_SERVER_DOMAINS=example.com \
-e RUSTFS_ACCESS_KEY=rustfsadmin \
-e RUSTFS_SECRET_KEY=rustfsadmin \
-e RUSTFS_CONSOLE_ENABLE=true
# 命令行参数方式
--address :9000 \
--server-domains example.com \
--access-key rustfsadmin \
--secret-key rustfsadmin \
--console-enable

7.8 绑定挂载主机目录的权限问题

官方镜像以非 root 用户 rustfs(UID 10001)运行。若使用主机目录挂载,必须先修正属主:

chown -R 10001:10001 /path/to/host_directory

7.9 常用配置组合

基础配置:

docker run -d \
  -p 9000:9000 -p 9001:9001 \
  -v /mnt/data:/data \
  rustfs/rustfs:latest /data

启用控制台:

docker run -d \
  -p 9000:9000 -p 9001:9001 \
  -v /mnt/data:/data \
  -e RUSTFS_CONSOLE_ENABLE=true \
  rustfs/rustfs:latest --console-enable /data

自定义认证密钥:

docker run -d \
  -p 9000:9000 -p 9001:9001 \
  -v /mnt/data:/data \
  -e RUSTFS_ACCESS_KEY=rustfsadmin \
  -e RUSTFS_SECRET_KEY=rustfsadmin \
  rustfs/rustfs:latest \
  --access-key rustfsadmin --secret-key rustfsadmin /data

7.10 Docker Compose 安装(详解)

官方 docker-compose.yml 包含 grafana、prometheus、otel-collector、jaeger 等可观测性服务。

git clone https://github.com/rustfs/rustfs.git
cd rustfs
docker compose --profile observability up -d

仅安装 RustFS(不启动可观测性服务):

docker compose -f docker-compose.yml up -d rustfs

自定义 Compose 示例(含权限修正 init 容器):

services:
  rustfs_perms:
    image: alpine
    user: root
    volumes:
      - /path/to/host_directory/volumes:/fix_path
    command: chown -R 10001:10001 /fix_path

  rustfs:
    image: rustfs/rustfs:latest
    depends_on:
      rustfs_perms:
        condition: service_completed_successfully
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - /path/to_host_directory/volumes/data:/data
      - /path/to_host_directory/volumes/logs:/var/log/rustfs/
    environment:
      - RUSTFS_ADDRESS=":9000"
      - RUSTFS_CONSOLE_ADDRESS=":9001"
      - RUSTFS_CONSOLE_ENABLE=true
      - RUSTFS_OBS_LOGGER_LEVEL=error
      - RUSTFS_OBS_LOG_DIRECTORY="/var/log/rustfs/"
    restart: unless-stopped

7.11 生产级 Compose 示例(双端口 + 双域名 + Nginx + SSL)

services:
  rustfs:
    image: rustfs/rustfs:latest
    container_name: rustfs-server
    security_opt:
      - "no-new-privileges:true"
    ports:
      - "9000:9000"
      - "9001:9001"
    environment:
      - RUSTFS_VOLUMES=/data/rustfs0
      - RUSTFS_ADDRESS=0.0.0.0:9000
      - RUSTFS_CONSOLE_ADDRESS=0.0.0.0:9001
      - RUSTFS_CONSOLE_ENABLE=true
      - RUSTFS_CORS_ALLOWED_ORIGINS=*
      - RUSTFS_CONSOLE_CORS_ALLOWED_ORIGINS=*
      - RUSTFS_ACCESS_KEY=rustfsadmin
      - RUSTFS_SECRET_KEY=rustfsadmin
      - RUSTFS_OBS_LOGGER_LEVEL=info
    volumes:
      - ./deploy/data/pro:/data
      - ./deploy/logs:/app/logs
    networks:
      - rustfs-network
    restart: unless-stopped
    healthcheck:
      test: ["CMD", "sh", "-c", "curl -f http://localhost:9000/health && curl -f http://localhost:9001/health"]
      interval: 30s
      timeout: 10s
      retries: 3
      start_period: 40s

networks:
  rustfs-network:
    driver: bridge
    ipam:
      config:
        - subnet: 172.20.0.0/16

7.12 Nginx 反向代理关键配置

关键:Nginx 必须加 proxy_cache_convert_head off,否则 Nginx 会把 HEAD 转成 GET,导致 S3 V4 签名失败(报 Bucket not found 或 403 AccessDenied)。

S3 API 端 Nginx 配置:

upstream rustfs {
    least_conn;
    server 127.0.0.1:9000;
}

server {
    listen 80;
    server_name s3.example.com;
    return 301 https://$host$request_uri;
}

server {
    listen 443 ssl http2;
    server_name s3.example.com;

    ssl_certificate     /www/server/panel/vhost/cert/s3.example.com/fullchain.pem;
    ssl_certificate_key /www/server/panel/vhost/cert/s3.example.com/privkey.pem;
    ssl_protocols       TLSv1.2 TLSv1.3;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_cache_convert_head off;   # 关键
        proxy_http_version 1.1;
        proxy_set_header Connection "";

        proxy_pass http://rustfs;
    }
}

控制台端 Nginx 配置(同理,端口 9001):

upstream rustfs-console {
    least_conn;
    server 127.0.0.1:9001;
}

server {
    listen 443 ssl http2;
    server_name console.example.com;

    ssl_certificate     /www/server/panel/vhost/cert/console.example.com/fullchain.pem;
    ssl_certificate_key /www/server/panel/vhost/cert/console.example.com/privkey.pem;

    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_cache_convert_head off;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        proxy_pass http://rustfs-console;
    }
}
nginx -t && nginx -s reload

7.13 验证部署

docker ps
docker logs rustfs_local
curl -f http://localhost:9000/health
curl -f http://localhost:9001/health

使用 mc 验证:

mc alias set rustfs http://localhost:9000 rustfsadmin rustfsadmin
mc mb rustfs/mybucket
mc ls rustfs

控制台访问:http://localhost:9001(默认账号密码均为 rustfsadmin)。

7.14 Podman

podman run -d --name rustfs \
  -p 9000:9000 -p 9001:9001 \
  -v "$(pwd)/rustfs/data:/data" \
  -v "$(pwd)/rustfs/logs:/logs" \
  rustfs/rustfs:<pinned-version>

7.15 Linux + systemd(安装脚本)

官方脚本会把二进制安装到 /usr/local/bin/rustfs,创建 rustfs systemd 服务并启动它。在生产主机上运行前请先审阅脚本:

curl -O https://rustfs.com/install_rustfs.sh
less install_rustfs.sh        # 先审阅
bash install_rustfs.sh
sudo systemctl status rustfs --no-pager

前置条件:带 systemd 的 x86_64 或 aarch64 Linux、unzip、root 或 sudo 权限,以及安装期间的外网访问。脚本的快速安装以单节点单驱动器模式运行。多驱动器或多节点生产部署,应在服务配置中定义驱动器布局,而不是使用快速安装默认值。(verify configuration variables)

7.16 独立二进制

sudo install -m 755 ./rustfs /usr/local/bin/rustfs
rustfs --help

创建专用系统用户和权限受限的数据目录:

sudo useradd --system --home /var/lib/rustfs --shell /usr/sbin/nologin rustfs
sudo mkdir -p /var/lib/rustfs/data /var/log/rustfs
sudo chown -R rustfs:rustfs /var/lib/rustfs /var/log/rustfs

在 systemd 下以该用户运行(unit 模板见 27.8 节)。(verify:你版本的选项与变量)

7.17 Kubernetes

使用 RustFS Kubernetes Operator 及其 Helm Chart。Operator 管理租户(集群)、池、调度、TLS 以及增删池等生命周期操作。关于 values、存储类选择和 Ingress,请遵循 Chart 的 README。将示例 Tenant 清单应用到生产集群前,请先审阅仓库中的示例清单及其行内注释。(verify current CRDs and values)

7.18 验证新安装

curl -I http://<host>:9000/
curl -I http://<host>:9001/

然后登录控制台,创建测试存储桶,上传并下载一个文件,再删除它。只有这一切成功后,才应继续进行加固。


8. 多节点集群安装与使用

8.1 部署模式概览

模式磁盘节点适用场景
SNSD11本地测试
SNMD≥21单机高可用
MNMD≥1/节点≥4生产级分布式

最少需要 4 台服务器,每台至少 1 块磁盘,才能安全启动生产级分布式集群。

8.2 架构目标

默认 12 + 4 纠删码模式:1 个数据块拆成 12 个数据块 + 4 个校验块,分散到不同服务器的不同磁盘。

  • 任意 1 台服务器损坏/维护,不影响数据安全;
  • 任意 4 块磁盘以内损坏,不影响数据安全。

8.3 先决条件

  1. 操作系统:Linux 内核 4.x 及以上(5.x/6.x 更佳),Ubuntu 22.04 或 RHEL 8.x;
  2. 内存:测试 ≥ 2 GB,生产 ≥ 128 GB;
  3. 时间同步:所有节点必须一致(ntp / timedatectl / timesyncd),否则可能无法启动;
  4. 磁盘:推荐 JBOD 直通模式,禁用 NFS 作为底层存储;建议 NVMe SSD;文件系统强烈推荐 XFS;
  5. 网络:所有节点使用相同端口(默认 9000),主机名连续可解析。

8.4 主机名配置(多机必须)

在所有节点的 /etc/hosts 配置连续的别名:

192.168.1.1 node1
192.168.1.2 node2
192.168.1.3 node3
192.168.1.4 node4

8.5 防火墙配置

systemctl status firewalld

# 禁用(或放行端口)
systemctl stop firewalld
systemctl disable firewalld

# 或仅放行端口
firewall-cmd --zone=public --add-port=9000/tcp --permanent
firewall-cmd --reload

所有 RustFS 服务器必须使用相同的监听端口。

8.6 磁盘文件系统格式化(XFS)

sudo lsblk

# 格式化,推荐选项
sudo mkfs.xfs -i size=512 -n ftype=1 -L RUSTFS0 /dev/sdb

选项说明:

  • -L:磁盘标签,方便识别和挂载;
  • -i size=512:inode 大小 512 字节,利于大量小对象;
  • -n ftype=1:开启 ftype,提升 readdir/unlink 性能。

挂载:

# /etc/fstab 追加
LABEL=RUSTFS0 /data/rustfs0 xfs defaults,noatime,nodiratime 0 0
sudo mount -a

禁止 NFS:NFS 高 IO 下会产生幻写和锁问题。推荐 JBOD(Just a Bunch of Disks),把物理磁盘直接独立暴露给操作系统,由 RustFS 软件层负责冗余。硬件 RAID 会成为性能瓶颈,也不推荐。

8.7 下载安装包

wget https://dl.rustfs.com/artifacts/rustfs/release/rustfs-linux-x86_64-musl-latest.zip
unzip rustfs-linux-x86_64-musl-latest.zip
chmod +x rustfs
mv rustfs /usr/local/bin/

快速安装脚本(SNSD 模式):

curl -O https://rustfs.com/install_rustfs.sh && bash install_rustfs.sh

8.8 配置环境变量(多机多盘)

在每台节点创建:

sudo tee /etc/default/rustfs <<EOF
RUSTFS_ACCESS_KEY=rustfsadmin
RUSTFS_SECRET_KEY=rustfsadmin
RUSTFS_VOLUMES="http://node{1...4}:9000/data/rustfs{0...3}"
RUSTFS_ADDRESS=":9000"
RUSTFS_CONSOLE_ENABLE=true
RUST_LOG=error
RUSTFS_OBS_LOG_DIRECTORY="/var/logs/rustfs/"
EOF

RUSTFS_VOLUMES 中 http://node{1...4}:9000/data/rustfs{0...3} 表示 4 个节点 × 4 块盘 = 16 个驱动器。

创建存储目录:

sudo mkdir -p /data/rustfs{0..3} /var/logs/rustfs /opt/tls
sudo chmod -R 750 /data/rustfs* /var/logs/rustfs

8.9 创建 systemd 服务

sudo tee /etc/systemd/system/rustfs.service <<'EOF'
[Unit]
Description=RustFS Object Storage Server
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
NotifyAccess=main
User=root
Group=root
WorkingDirectory=/usr/local
EnvironmentFile=-/etc/default/rustfs
ExecStart=/usr/local/bin/rustfs $RUSTFS_VOLUMES
LimitNOFILE=1048576
LimitNPROC=32768
TasksMax=infinity
Restart=always
RestartSec=10s
OOMScoreAdjust=-1000
TimeoutStartSec=30s
TimeoutStopSec=30s
NoNewPrivileges=true
ProtectHome=true
PrivateTmp=true
PrivateDevices=true

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now rustfs
systemctl status rustfs

8.10 Docker 多节点部署(重点)

Docker 默认桥接网络不支持多节点部署,必须使用 --network host。

在每个节点上运行:

docker run -d \
  --name rustfs \
  --network host \
  -v /mnt/rustfs/data:/data \
  -e RUSTFS_ACCESS_KEY="<your-access-key>" \
  -e RUSTFS_SECRET_KEY="<your-secret-key>" \
  -e RUSTFS_ADDRESS=":9000" \
  -e RUSTFS_CONSOLE_ADDRESS=":9001" \
  -e RUSTFS_CONSOLE_ENABLE=true \
  -e RUSTFS_OBS_LOGGER_LEVEL=error \
  -e RUSTFS_VOLUMES="http://node{1...4}:9000/data/rustfs{0...3}" \
  rustfs/rustfs:latest

每个节点的 /etc/hosts 需配置 node1~node4。

8.11 验证集群

netstat -ntpl                # 检查端口
tail -f /var/logs/rustfs/rustfs*.log
curl http://<ip>:9000/health

使用 rc 检查集群:

rc alias set rustfs http://<node-ip>:9000 <access-key> <secret-key>
rc admin info cluster rustfs
rc admin pool list rustfs

9. 初始配置与加固

9.1 根凭据

根账户拥有不受限的访问权限,仅用于初始设置和应急(break-glass)场景。文档记载的默认根访问密钥为 rustfsadmin,也就是说全新安装会以一个公开已知的身份启动。请在执行任何其他步骤之前更改访问密钥和秘密密钥。

  1. 通过你所用安装方式的环境变量设置根访问密钥和长随机秘密(RUSTFS_ACCESS_KEY 和 RUSTFS_SECRET_KEY,均见第 35 章环境变量参考)。
  2. 重启服务。
  3. 确认新凭据可用、默认凭据已被拒绝。
  4. 将根凭据存入密码管理器或密钥保险库,并指定两名具名保管人。

生成秘密:

openssl rand -base64 36

不要在应用、备份或日常管理中使用根凭据。第 11 章介绍如何避免这一点。

9.2 网络暴露

  • 仅将 S3 端点(9000)暴露给需要它的网络和应用。
  • 控制台(9001)应保留在内网,或置于 VPN / 零信任访问之后,不应从公网可达。
  • 如有条件,在反向代理上对不可信网络阻断管理路径,因为它们承载管理操作。

9.3 TLS

任何跨网络边界的客户端都应使用 HTTPS。两种常见方式:

  • 反向代理终止 TLS(多数场景推荐)。Nginx、Caddy、Traefik 或云负载均衡器终止 TLS,然后通过回环或私有地址转发到 RustFS。
  • RustFS 内置 TLS,使用 RUSTFS_TLS_PATH 和 31.1 节所述的证书目录。

Nginx 前端示例:

server {
    listen 443 ssl http2;
    server_name storage.example.com;

    ssl_certificate     /etc/ssl/certs/storage.example.com.fullchain.pem;
    ssl_certificate_key /etc/ssl/private/storage.example.com.key;
    ssl_protocols       TLSv1.2 TLSv1.3;

    client_max_body_size 0;          # 代理层不限制对象大小
    proxy_request_buffering off;     # 流式上传
    proxy_buffering off;

    location / {
        proxy_pass http://127.0.0.1:9000;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_read_timeout 900s;
    }
}

server {
    listen 443 ssl http2;
    server_name console.storage.example.com;

    ssl_certificate     /etc/ssl/certs/storage.example.com.fullchain.pem;
    ssl_certificate_key /etc/ssl/private/storage.example.com.key;

    location / {
        proxy_pass http://127.0.0.1:9001;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

对控制台的 server 块按 IP 限制访问,或将其置于访问网关之后。

9.4 时间同步

带签名的 S3 请求包含时间戳。客户端与服务端之间的时钟偏差会导致 RequestTimeTooSkewed 和签名错误。每个节点和客户端都要运行 NTP 或 chrony。

timedatectl status    # 确认 "System clock synchronized: yes"

9.5 基线检查清单(摘要)

  • 根凭据已更改并安全保存
  • 控制台不对公网开放
  • 所有外部端点已启用 TLS
  • 所有节点运行 NTP
  • 数据目录属主为服务用户且非全局可读
  • 防火墙规则限制 9000 与 9001 端口
  • 已配置集群外备份(第 26 章)

第三部分 — 身份与访问


10. 使用 OpenID Connect(OIDC)单点登录

RustFS 支持通过 OpenID Connect(OIDC)实现 控制台 单点登录。用户在身份提供者(IdP,如 Keycloak 或 GitLab)处登录,RustFS 再依据自身的 IAM 策略决定每个人可以做什么。IdP 负责认证,RustFS 负责授权。

应用程序不应使用 SSO。请为它们提供带访问密钥的服务账户(见 11.4 节)。

10.1 登录流程

RustFS 使用 OIDC 授权码流程 + 代码交换证明密钥(PKCE,S256):

  1. RustFS 携带 S256 PKCE 挑战值将用户浏览器重定向到 IdP。
  2. 用户在 IdP 完成认证。密码、MFA 和条件访问都在 IdP 强制执行。
  3. IdP 携带授权码重定向回 RustFS 回调 URL。
  4. RustFS 用授权码到令牌端点换取令牌。
  5. RustFS 校验 ID 令牌:签名(通过 JWKS 端点)、签发者、受众、过期时间和 nonce。
  6. RustFS 将配置的声明(claim)映射到本地 IAM 策略,并创建由临时凭据支撑的控制台会话。

10.2 控制台登录方式

方式出现时机用途
Key Login始终显示使用访问密钥的本地管理员。保留作为应急访问。
STS Login使用临时凭据时使用身份工作流签发的 STS 凭据登录。仅当该工作流能签发有效会话令牌时使用。
OIDC Login配置了提供者时选择提供者并在 IdP 登录。

10.3 前置条件

  • 控制台具备公网 HTTPS 源,例如 https://rustfs.example.com。
  • <issuer>/.well-known/openid-configuration 处有 OIDC 发现文档,暴露授权、令牌和 JWKS 端点。
  • 在 IdP 中为 RustFS 创建专用客户端,不要复用其他应用的客户端。
  • 一个扁平的组或角色声明,其值与现有 RustFS 策略名称完全一致(见 10.7 节)。

10.4 RustFS OIDC 端点

用途URL
回调(需在 IdP 注册)https://<rustfs-host>/rustfs/admin/v3/oidc/callback/<provider-id>
发起登录(用于浏览器测试)https://<rustfs-host>/rustfs/admin/v3/oidc/authorize/<provider-id>
列出已配置的提供者https://<rustfs-host>/rustfs/admin/v3/oidc/providers

单个无后缀配置的 <provider-id> 为 default;如 keycloak 之类的命名提供者使用各自的路径。

10.5 在身份提供者处注册 RustFS

通用步骤(各产品标签略有不同):

  1. 为 RustFS 创建一个 Web 客户端。文档示例使用无客户端密钥的客户端(关于密钥见 10.6 节)。
  2. 将重定向 URI 设置为精确的回调 URL。协议、主机、端口、路径和结尾斜杠都必须匹配。
  3. 将 Web origins 或允许的来源设置为控制台的公网源。
  4. 启用授权码流程和 PKCE(S256),如果 IdP 提供的话。
  5. 请求 openid、profile 和 email 作用域。缺少 openid 时,RustFS 会报告未收到 ID 令牌。
  6. 添加映射器或声明,把组或角色名称以扁平字符串列表形式放入令牌。

Keycloak 示例(issuer https://keycloak.example.com/realms/rustfs):

  • Client ID:rustfs-console
  • 有效重定向 URI:https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default
  • Web origins:https://rustfs.example.com
  • 作用域:openid、profile、email
  • 组成员映射器:输出组名称而非完整路径,使 /rustfs/admins 在令牌中变为 rustfs-admins

GitLab 示例(issuer https://gitlab.example.com):

  • 应用名称:RustFS OIDC
  • 重定向 URI:https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default
  • 作用域:openid、profile、email

10.6 配置 RustFS

设置以下变量,任何更改后都要重启 RustFS:

变量用途示例
RUSTFS_BROWSER_REDIRECT_URL浏览器返回的控制台公网源https://rustfs.example.com
RUSTFS_IDENTITY_OPENID_CONFIG_URL签发者:/.well-known/openid-configuration 之前的基 URLhttps://keycloak.example.com/realms/rustfs
RUSTFS_IDENTITY_OPENID_CLIENT_ID来自 IdP 的客户端 IDrustfs-console
RUSTFS_IDENTITY_OPENID_SCOPES逗号分隔的作用域openid,profile,email
RUSTFS_IDENTITY_OPENID_REDIRECT_URI在 IdP 注册的回调 URLhttps://rustfs.example.com/rustfs/admin/v3/oidc/callback/default
RUSTFS_IDENTITY_OPENID_USERNAME_CLAIM用作显示用户名的声明preferred_username

单提供者:

export RUSTFS_BROWSER_REDIRECT_URL="https://rustfs.example.com"
export RUSTFS_IDENTITY_OPENID_CONFIG_URL="https://keycloak.example.com/realms/rustfs"
export RUSTFS_IDENTITY_OPENID_CLIENT_ID="rustfs-console"
export RUSTFS_IDENTITY_OPENID_SCOPES="openid,profile,email"
export RUSTFS_IDENTITY_OPENID_REDIRECT_URI="https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default"
export RUSTFS_IDENTITY_OPENID_USERNAME_CLAIM="preferred_username"

多提供者使用与提供者 ID 匹配的后缀:

export RUSTFS_IDENTITY_OPENID_CONFIG_URL_keycloak="https://keycloak.example.com/realms/rustfs"
export RUSTFS_IDENTITY_OPENID_CLIENT_ID_keycloak="rustfs-console"
export RUSTFS_IDENTITY_OPENID_SCOPES_keycloak="openid,profile,email"
export RUSTFS_IDENTITY_OPENID_REDIRECT_URI_keycloak="https://rustfs.example.com/rustfs/admin/v3/oidc/callback/keycloak"

在 Docker 中用 -e 传入相同名称,或写入 Compose 读取的环境文件。

客户端密钥。 文档中的 Keycloak 和 GitLab 示例没有展示客户端密钥变量。如果你的 IdP 要求机密客户端,请在部署前查环境变量参考(第 35 章)中的密钥设置。(verify)

验证配置:

curl -fsS "https://keycloak.example.com/realms/rustfs/.well-known/openid-configuration" \
  | jq '{issuer, authorization_endpoint, token_endpoint, jwks_uri}'

curl -fsS "https://rustfs.example.com/rustfs/admin/v3/oidc/providers" | jq

providers 响应应列出你的提供者及其显示名称。然后在浏览器中打开 https://rustfs.example.com/rustfs/admin/v3/oidc/authorize/default,或使用控制台登录页,页面会显示该提供者的 OIDC 选项。

10.7 将 IdP 组映射到 RustFS 策略

授权按名称工作。声明中的组或角色值必须与现有 RustFS 策略名称完全一致。不匹配任何策略的名称不授予任何权限;匹配某个策略的名称恰好获得该策略允许的权限。

推荐设计:

  1. 先创建 RustFS 策略(第 12 章),按 IdP 组命名,例如 rustfs-admins、rustfs-readwrite、rustfs-readonly。
  2. 配置 IdP,把那些名称以扁平列表形式输出到 RustFS 读取的声明中,嵌套组路径要打平。
  3. 推广前,每个组先用一个账户测试。
  4. 保持策略集小而经过评审。把策略名称视为与 IdP 团队之间的访问契约。

两点说明:

  • 选择声明名称的变量未出现在文档示例中,请在你版本的 OIDC 参考中确认。(verify)
  • Microsoft Entra ID 默认返回组对象 ID 而非名称。请使用名称匹配的应用角色,或在前面加一个代理 IdP。(verify)

10.8 会话与撤销

  • 控制台会话使用临时凭据,其生命周期跟随令牌时长和 RustFS 会话设置。请确认你版本的确切时长。(verify)
  • 在 IdP 处缩短管理员组的令牌时长。
  • 要撤销访问:在 IdP 禁用用户或将其移出对应组,并在 IdP 结束其会话。请确认你版本中刷新令牌的行为。(verify)

10.9 应急访问与安全检查清单

  • 为少量具名保管人保留可用的 Key Login,每季度测试一次。
  • 控制台和 OIDC 端点仅通过 HTTPS 提供。
  • 对映射到写入或管理策略的每个组,在 IdP 强制 MFA。
  • 限制谁能访问控制台登录页:VPN、零信任网关或白名单。
  • 如果 IdP 使用私有 CA,设置 RUSTFS_TRUST_SYSTEM_CA=true,使出站连接信任系统 CA 存储(见 31.1 节);否则将 CA 安装到系统存储中。
  • 每季度评审组到策略的映射以及策略本身。

10.10 SSO 故障排查

症状原因与修复
IdP 报告重定向 URI 不匹配注册的回调与 RUSTFS_IDENTITY_OPENID_REDIRECT_URI 在协议、主机、端口、路径或结尾斜杠上不一致。
RustFS 报告未收到 ID 令牌缺少 openid 作用域,或客户端未使用授权码流程。
登录成功但用户什么都看不到声明缺失、名称不同、嵌套,或其值不匹配任何策略名称。解码 ID 令牌比对。
/providers 中不出现提供者某个变量错误、后缀与提供者 ID 不匹配,或 RustFS 未重启。
发现(discovery)因 TLS 错误失败IdP 的 CA 不被出站连接信任,见 10.9 节。
令牌被拒绝为已过期或尚未生效时钟偏差。在所有 RustFS 节点和 IdP 上运行 NTP。
IdP 故障期间用户被锁在外面用应急账户通过 Key Login 登录(10.9 节)。

RustFS 使用 OIDC 授权码流程 + PKCE(S256) 实现控制台单点登录,支持 Keycloak、GitLab、Authing 等标准 IdP。

10.11 工作流程

  1. RustFS 发送带 S256 PKCE 质询的授权请求;
  2. IdP 验证身份,将授权码重定向回 RustFS 回调 URL;
  3. RustFS 在令牌端点交换授权码;
  4. RustFS 验证 ID 令牌的签名、签发者、受众、有效期、nonce;
  5. RustFS 将令牌声明映射到本地 IAM 策略,签发临时 STS 凭证创建会话。

10.12 提供商要求

  • OIDC discovery URL(授权端点、令牌端点、JWKS 端点);
  • 机密客户端,支持授权码流程 + S256 PKCE + client_secret_post;
  • 精确回调 URL:https://<rustfs-host>/rustfs/admin/v3/oidc/callback/<provider-id>;
  • 扁平的 group/role 声明,值与 RustFS 策略名精确匹配。

10.13 Keycloak 配置要点

Keycloak 侧:

  1. 创建 realm rustfs,创建 OIDC 客户端 rustfs-console;
  2. 启用 Client authentication、Standard flow,关闭 Implicit / Direct access grants;
  3. Valid redirect URIs 设为 https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default;
  4. PKCE 设为 S256;
  5. 添加 Group Membership mapper(Token Claim Name = groups,Full group path 关闭)。

RustFS 侧(/etc/default/rustfs):

RUSTFS_BROWSER_REDIRECT_URL="https://rustfs.example.com"
RUSTFS_IDENTITY_OPENID_ENABLE=on
RUSTFS_IDENTITY_OPENID_CONFIG_URL="https://keycloak.example.com/realms/rustfs"
RUSTFS_IDENTITY_OPENID_CLIENT_ID="rustfs-console"
RUSTFS_IDENTITY_OPENID_CLIENT_SECRET="<keycloak-client-secret>"
RUSTFS_IDENTITY_OPENID_SCOPES="openid,profile,email"
RUSTFS_IDENTITY_OPENID_REDIRECT_URI="https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default"
RUSTFS_IDENTITY_OPENID_REDIRECT_URI_DYNAMIC=off
RUSTFS_IDENTITY_OPENID_DISPLAY_NAME="Keycloak"
RUSTFS_IDENTITY_OPENID_GROUPS_CLAIM="groups"
RUSTFS_IDENTITY_OPENID_ROLES_CLAIM="roles"
RUSTFS_IDENTITY_OPENID_EMAIL_CLAIM="email"
RUSTFS_IDENTITY_OPENID_USERNAME_CLAIM="preferred_username"

内网 IdP:若 Keycloak 解析到私网 IP,需把其源地址加入 RUSTFS_OUTBOUND_ALLOW_ORIGINS(格式 scheme://host:port,如 http://kc:8080)。

10.14 验证

# 验证发现信息
curl -fsS "https://keycloak.example.com/realms/rustfs/.well-known/openid-configuration" | jq '.issuer, .authorization_endpoint, .token_endpoint, .jwks_uri'

# 验证 RustFS 提供商
curl -fsS "https://rustfs.example.com/rustfs/admin/v3/oidc/providers" | jq

# 测试登录
# https://rustfs.example.com/rustfs/admin/v3/oidc/authorize/default

11. 多用户管理

11.1 身份类型

身份用途凭据推荐对象
根账户初始设置、应急根密钥对仅限两三名具名保管人
SSO 用户使用控制台的人IdP 登录全体员工
IAM 用户SSO 不可用时的本地人员或有限自动化用户名和密码,可选访问密钥特殊情况
服务账户应用、备份任务、流水线访问密钥对所有非人类工作负载

11.2 多租户模式

选择团队与客户之间的隔离方式:

模式做法隔离性最适合
每租户一个存储桶每团队或客户一个桶,策略限定到该桶桶级强隔离中等数量租户
每租户一个前缀共享桶,键以租户 ID 为前缀,策略限定到前缀逻辑隔离大量小租户;注意防止列出其他前缀
每租户一个集群独立 RustFS 集群(或 Kubernetes Tenant)物理隔离严格隔离、受监管数据、独立计费

说明:

  • 前缀隔离依赖策略条件,既要限制对象访问也要限制列举。请用非管理员账户尝试列举其他前缀来测试。
  • 配额和按租户计费需要按桶或前缀做容量监控。(verify quota features)

11.3 组

组可以简化管理。把策略赋给组、把用户加入组,而不是给每个用户挂策略。

rc admin group add rustfs analytics-team alice bob     # 创建组并加入成员
rc admin policy attach rustfs readwrite-analytics --group analytics-team

(verify subcommands)

11.4 服务账户与访问密钥

服务账户是拥有自己访问密钥的非人类身份,是让应用获得访问权的正确方式。

规则:

  • 每个应用或流水线一个服务账户。
  • 创建时附加最小权限策略,或在支持处继承父角色。
  • 尽可能设置过期日期。
  • 密钥存入密钥管理器,绝不写进代码或容器镜像。
  • 按计划轮换密钥(例如每 90 天),疑似泄露后立即轮换。

用 CLI 创建:

rc admin user svcacct add rustfs app-web-uploader \
  --policy readwrite-uploads \
  --description "Web app uploads service"

(verify command and flags)

响应中包含访问密钥和秘密,秘密通常只显示一次。

11.5 访问密钥轮换流程

  1. 为同一服务账户创建新的访问密钥。
  2. 将新密钥部署到应用的密钥存储中。
  3. 确认应用使用新密钥正常工作(观察日志与指标)。
  4. 停用旧密钥。
  5. 宽限期后删除旧密钥。
rc admin user svcacct list rustfs app-web-uploader
rc admin user svcacct disable rustfs <old-access-key>   # verify
rc admin user svcacct remove rustfs <old-access-key>    # verify

11.6 用户离职(Offboarding)

  1. 在 IdP 禁用该用户(SSO 用户在下次登录或令牌过期时失去访问权)。
  2. 禁用本地 IAM 用户并移除其访问密钥。
  3. 将其服务账户的所有权移交给其他管理员。
  4. 检查任何点名该用户的存储桶策略或 ACL。
  5. 在审计系统中记录该变更。

11.7 特权访问

  • 限制持有 consoleAdmin 或等效策略的人数,通常两三到四人。
  • 通过 IdP 对管理员强制 MFA。
  • 如组织要求,管理用途与日常使用使用不同账户。
  • 记录管理操作并定期评审。

12. 策略与权限管理

12.1 授权评估方式

对每个请求,RustFS 检查:

  1. 任一适用策略中的显式拒绝 → 拒绝。
  2. 适用策略中的显式允许 → 允许。
  3. 没有匹配的允许 → 拒绝(默认拒绝)。

适用策略来自:

  • 身份策略:附属于用户、组或服务账户。
  • 存储桶策略:附属于存储桶,可授予其他主体或匿名访问。

对于跨账户式的访问,当请求来自不同主体时,身份策略和存储桶策略必须同时允许该操作。(verify evaluation behavior for your version)

12.2 策略文档结构

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadWriteUploads",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": ["arn:aws:s3:::app-uploads/*"],
      "Condition": { }
    }
  ]
}
元素用途
Version策略语言版本,使用 2012-10-17。
Sid可选的语句标识。
EffectAllow 或 Deny。
ActionS3 操作如 s3:GetObject,或支持处的管理操作。
Resource存储桶或对象 ARN。桶级操作用 arn:aws:s3:::bucket;对象级操作用 arn:aws:s3:::bucket/*。
Condition可选约束,如前缀、源 IP、是否使用 TLS。

12.3 常用构件

桶级 vs 对象级操作。 s3:ListBucket 适用于桶 ARN;s3:GetObject 和 s3:PutObject 适用于 bucket/*。混用这两者是最常见的策略错误。

列举的前缀限制:

{
  "Effect": "Allow",
  "Action": "s3:ListBucket",
  "Resource": "arn:aws:s3:::reports",
  "Condition": { "StringLike": { "s3:prefix": ["teamA/*", "teamA"] } }
}

强制 TLS:

{
  "Sid": "DenyInsecureTransport",
  "Effect": "Deny",
  "Action": "s3:*",
  "Resource": ["arn:aws:s3:::*", "arn:aws:s3:::*/*"],
  "Condition": { "Bool": { "aws:SecureTransport": "false" } }
}

按来源网络限制:

{
  "Effect": "Deny",
  "Action": "s3:*",
  "Resource": ["arn:aws:s3:::finance", "arn:aws:s3:::finance/*"],
  "Condition": { "NotIpAddress": { "aws:SourceIp": ["10.20.0.0/16"] } }
}

依赖条件键之前,请先用你的 RustFS 版本测试。(verify supported condition keys)

12.4 示例策略

A. 跨所有存储桶的只读分析师

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:ListAllMyBuckets"], "Resource": ["arn:aws:s3:::*"] },
    { "Effect": "Allow", "Action": ["s3:ListBucket", "s3:GetBucketLocation"], "Resource": ["arn:aws:s3:::*"] },
    { "Effect": "Allow", "Action": ["s3:GetObject", "s3:GetObjectVersion"], "Resource": ["arn:aws:s3:::*/*"] }
  ]
}

B. 团队仅可写入某一个前缀

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::shared-data"],
      "Condition": { "StringLike": { "s3:prefix": ["marketing/*", "marketing"] } }
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
      "Resource": ["arn:aws:s3:::shared-data/marketing/*"]
    }
  ]
}

C. 备份服务账户:可写可列举,不可删除、不可读版本

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:ListBucket"], "Resource": ["arn:aws:s3:::backups"] },
    { "Effect": "Allow", "Action": ["s3:PutObject", "s3:GetObject"], "Resource": ["arn:aws:s3:::backups/*"] },
    { "Effect": "Deny", "Action": ["s3:DeleteObject", "s3:DeleteObjectVersion", "s3:PutLifecycleConfiguration"], "Resource": ["arn:aws:s3:::backups", "arn:aws:s3:::backups/*"] }
  ]
}

这个模式保护备份不被持有备份凭据的勒索软件删除。可用时请与对象锁结合使用(第 18 章)。

D. 除指定管理员组外一律拒绝删除

使用带条件(排除管理员角色)的 Deny 语句,或者干脆不把删除权限放进通用策略。显式 Deny 语句永远优先,因此用作护栏。

12.5 创建与附加策略

控制台:Policies → Create policy,粘贴 JSON,校验,保存,然后附加到用户或组。

CLI:

rc admin policy create rustfs backup-writer ./backup-writer.json   # verify
rc admin policy attach rustfs backup-writer --user svc-backup      # verify

12.6 存储桶策略

存储桶策略附属于存储桶,可授予主体访问权或将内容公开。公开读很少是合适的;优先使用预签名 URL 或带源站访问的 CDN。

示例:允许一个服务账户只读访问某存储桶:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ReadOnlyForReporting",
      "Effect": "Allow",
      "Principal": { "AWS": ["arn:aws:iam:::user/svc-reporting"] },
      "Action": ["s3:GetObject", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::reports", "arn:aws:s3:::reports/*"]
    }
  ]
}

用 S3 API 应用:

aws --endpoint-url https://storage.example.com s3api put-bucket-policy \
  --bucket reports --policy file://reports-bucket-policy.json

Principal 语法因版本而异。(verify)

12.7 测试策略

在把访问权授予生产数据之前:

  1. 创建一个附加了该策略的测试用户。
  2. 测试应用需要的每项操作(列举、get、put、删除、分片上传)。
  3. 测试本应失败的操作(在前缀外写入、删除、列举其他存储桶)。
  4. 将结果记录到变更工单中。
aws --endpoint-url https://storage.example.com --profile test-user s3 cp ./t.txt s3://reports/t.txt
# 预期:上传被拒,返回 AccessDenied

12.8 权限管理实践

  • 使用组和角色,而不是按用户挂策略。
  • 按用途和范围命名策略(readonly-finance、backup-writer-prod)。
  • 策略纳入版本控制,变更经评审后发布。
  • 对绝不能发生的事情(公开暴露、删除备份)优先使用 Deny 护栏。
  • 每季度与数据所有者一起评审访问权限。
  • 记录策略变更。

RustFS 内置一套以 AWS IAM 策略语言为模型的 IAM 系统。每个请求(S3 数据访问、控制台操作、管理 API)都先通过凭证认证,再根据附加策略授权。

12.9 身份类型

身份创建方式典型用途
根凭证启动时 RUSTFS_ACCESS_KEY / RUSTFS_SECRET_KEY初始设置、紧急管理,绕过 IAM 身份策略(所有者语义)
IAM 用户控制台或 add-user面向人/应用的长期命名账户
组控制台或 update-group-members一次将策略批量附加到多个用户
服务账户(访问密钥)控制台或 add-service-account父用户的派生凭证,可设置过期时间
STS 临时凭证AssumeRole / AssumeRoleWithWebIdentity15 分钟~12 小时短期凭证
外部 OIDC 身份Keycloak / GitLab / Authing 等控制台 SSO

12.10 创建 / 删除访问密钥(AK/SK)

  1. 登录控制台 → 左侧「访问密钥」→ 右上角「添加访问密钥」;
  2. 输入过期时间、名称、描述 → 提交;
  3. 复制或导出保存(仅显示一次)。

12.11 策略评估语义(Deny 优先与所有者规则)

  1. 显式拒绝优先:任何匹配的 Deny 语句都会拒绝请求;
  2. 所有者快捷规则:根账户绕过 IAM 身份策略评估;
  3. 必须显式允许:其他身份必须至少有一条匹配的 Allow 语句;
  4. 默认拒绝:无语句匹配则拒绝。

带会话策略的服务账户 / STS 会话,有效权限取交集(父策略与会话策略都必须允许)。

12.12 内置策略

策略权限
readwrite所有 S3 操作(s3:*)+ sts:AssumeRole
readonlys3:GetBucketLocation、s3:GetObject、s3:GetBucketQuota + sts:AssumeRole
writeonlys3:PutObject + sts:AssumeRole
diagnostics诊断类管理操作 + sts:AssumeRole
consoleAdmin所有 admin:*、kms:*、s3:* + sts:AssumeRole

注意:内置 readonly 不含 s3:ListBucket/s3:ListAllMyBuckets。需列举存储桶内对象时,需自定义策略。

12.13 自定义策略文档格式

对单个存储桶的只读访问:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:GetBucketLocation", "s3:ListBucket"],
      "Resource": ["arn:aws:s3:::reports"]
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject"],
      "Resource": ["arn:aws:s3:::reports/*"]
    }
  ]
}

限制到前缀的读写:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": ["s3:ListBucket"],
      "Resource": ["arn:aws:s3:::app-data"],
      "Condition": {
        "StringLike": { "s3:prefix": ["tenant-42/*"] }
      }
    },
    {
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": ["arn:aws:s3:::app-data/tenant-42/*"]
    }
  ]
}

完全访问但禁止删除(Deny 覆盖 Allow):

{
  "Version": "2012-10-17",
  "Statement": [
    { "Effect": "Allow", "Action": ["s3:*"], "Resource": ["arn:aws:s3:::archive", "arn:aws:s3:::archive/*"] },
    { "Effect": "Deny", "Action": ["s3:DeleteObject", "s3:DeleteObjectVersion", "s3:DeleteBucket"], "Resource": ["arn:aws:s3:::archive", "arn:aws:s3:::archive/*"] }
  ]
}

支持的条件运算符:StringEquals、StringNotEquals、StringLike、StringNotLike、ArnEquals、IpAddress、NotIpAddress、Null、Bool、NumericEquals、NumericLessThan、DateGreaterThan、DateLessThan 等,均可加 IfExists 后缀。

12.14 管理 API(REST,需 SigV4 签名)

操作方法与路径
创建/更新用户PUT /rustfs/admin/v3/add-user?accessKey=<name>
列出用户GET /rustfs/admin/v3/list-users
用户详情GET /rustfs/admin/v3/user-info?accessKey=<name>
启用/禁用用户PUT /rustfs/admin/v3/set-user-status?accessKey=<name>&status=<enabled|disabled>
删除用户DELETE /rustfs/admin/v3/remove-user?accessKey=<name>
列出组GET /rustfs/admin/v3/groups
组详情GET /rustfs/admin/v3/group?group=<name>
添加/移除组成员PUT /rustfs/admin/v3/update-group-members
设置用户/组策略PUT /rustfs/admin/v3/set-user-or-group-policy?policyName=<p>&userOrGroup=<n>&isGroup=<bool>
附加策略POST /rustfs/admin/v3/idp/builtin/policy/attach
分离策略POST /rustfs/admin/v3/idp/builtin/policy/detach
列出策略GET /rustfs/admin/v3/list-canned-policies
创建/替换策略PUT /rustfs/admin/v3/add-canned-policy?name=<policy>
删除策略DELETE /rustfs/admin/v3/remove-canned-policy?name=<policy>
导出 IAM 数据GET /rustfs/admin/v3/export-iam
导入 IAM 数据PUT /rustfs/admin/v3/import-iam

创建用户示例(curl + SigV4):

curl -s -X PUT "http://localhost:9000/rustfs/admin/v3/add-user?accessKey=alice" \
  --user "<admin-ak>:<admin-sk>" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  -H "Content-Type: application/json" \
  -d '{"secretKey": "alice-secret", "status": "enabled"}'

12.15 服务账户与 STS 临时凭证

服务账户:属于父用户的长期访问密钥,可用过期时间(RFC 3339),可选内联会话策略。

创建服务账户请求体:

{
  "policy": { "Version": "2012-10-17", "Statement": [] },
  "targetUser": "alice",
  "accessKey": "myserviceaccount",
  "secretKey": "mysecret",
  "name": "ci-pipeline",
  "description": "Key used by CI",
  "expiration": "2027-01-01T00:00:00Z"
}

管理端点:PUT /rustfs/admin/v3/add-service-account、GET /rustfs/admin/v3/list-service-accounts?user=<name>、DELETE /rustfs/admin/v3/delete-service-account?accessKey=<key> 等。

STS AssumeRole(获取临时凭证):

curl -s -X POST "http://localhost:9000/" \
  --user "<ak>:<sk>" \
  --aws-sigv4 "aws:amz:us-east-1:s3" \
  -d "Action=AssumeRole" \
  -d "Version=2011-06-15" \
  -d "DurationSeconds=3600"

响应为 XML AssumeRoleResponse,含 AccessKeyId、SecretAccessKey、SessionToken、Expiration。后续 S3 请求用这三元组,会话令牌放在 X-Amz-Security-Token 头。

AssumeRoleWithWebIdentity(OIDC 场景,无需 SigV4):

curl -s -X POST "http://localhost:9000/" \
  -d "Action=AssumeRoleWithWebIdentity" \
  -d "Version=2011-06-15" \
  -d "WebIdentityToken=<OIDC-id-token>" \
  -d "DurationSeconds=3600"

DurationSeconds 默认 3600 秒,取值范围 900(15 分钟)~ 43200(12 小时)。

12.16 多用户 / 多租户

RustFS 通过「用户 + 组 + 策略 + 服务账户 + 桶策略」实现多租户隔离:

  • 每个租户可创建一个 IAM 用户,附加针对其专有桶前缀的读写策略;
  • 使用 StringLike 前缀条件限制访问范围;
  • 服务账户为每个应用/服务分配独立凭证,可单独轮换与吊销。

第四部分 — 数据管理


13. 存储桶

13.1 创建存储桶

控制台:Buckets → Create bucket,然后设置名称、版本控制、对象锁定(如需要)以及可用的加密选项。

CLI:

rc bucket create rustfs/finance-archive

或使用 S3 API:

aws --endpoint-url https://storage.example.com s3api create-bucket --bucket finance-archive

13.2 命名规则

  • 3 到 63 个字符
  • 小写字母、数字、连字符和句点
  • 以字母或数字开头和结尾
  • 不得形如 IP 地址
  • 不得有连续句点;若配合 TLS 使用 virtual-hosted 风格 URL,避免使用句点

使用一致的命名约定,例如 <部门>-<用途>-<环境>,如 finance-archive-prod。

13.3 存储桶配置

设置用途
版本控制保留对象的历史版本(第 15 章)
生命周期规则对象过期或转层(第 16 章)
对象锁 / 保留一次写入多次读取(WORM)保护(第 18、30 章)
加密默认服务端加密,SSE-S3 或 SSE-KMS(第 31 章)
标签成本分摊与策略条件
配额限制每个桶的大小 (verify)
通知对象创建/删除事件推送给下游系统(第 29 章)
CORS浏览器访问规则(22.8 节)
存储桶策略基于资源的访问(12.6 节)

查看和设置标签:

aws --endpoint-url https://storage.example.com s3api put-bucket-tagging \
  --bucket finance-archive \
  --tagging 'TagSet=[{Key=owner,Value=finance},{Key=cost-center,Value=4410}]'

13.4 删除存储桶

存储桶必须为空才能删除。若启用过版本控制,需删除所有版本和删除标记。删除是永久性的。

rc rm --recursive --versions rustfs/old-bucket/    # verify flags
rc bucket remove rustfs/old-bucket

删除前确认没有生命周期规则、层级或应用仍依赖它。


13.5 创建存储桶(mc / rc / curl 实操)

Console UI:首页 → 创建存储桶 → 输入名称 → 创建。

mc:

mc mb rustfs/bucket-name

rc:

rc bucket create rustfs/bucket-name

REST API(S3):

curl --location --request PUT 'http://<ip>:9000/bucket-name' \
  --header 'Authorization: AWS4-HMAC-SHA256 Credential=<AK>/<date>/cn-east-1/s3/aws4_request, SignedHeaders=host;x-amz-date, Signature=<sig>'

13.6 删除存储桶(mc / rc 实操)

mc rb rustfs/bucket-name
# 或
rc bucket remove rustfs/bucket-name

13.7 桶策略(Bucket Policy)

Python (Boto3) 设置桶策略:

import json
import boto3
from botocore.client import Config

s3 = boto3.client('s3', endpoint_url='http://localhost:9000',
    aws_access_key_id='ak', aws_secret_access_key='sk',
    config=Config(signature_version='s3v4'), region_name='us-east-1')

policy = {
    "Version": "2012-10-17",
    "Statement": [{
        "Effect": "Allow",
        "Principal": {"AWS": ["*"]},
        "Action": ["s3:GetObject"],
        "Resource": ["arn:aws:s3:::my-bucket/*"]
    }]
}
s3.put_bucket_policy(Bucket='my-bucket', Policy=json.dumps(policy))

14. 对象

14.1 键与文件夹

对象键是扁平字符串,斜杠只是约定。reports/2026/10/summary.csv 是一个键。控制台把前缀显示为文件夹。空文件夹标记是可选的。

为列举和生命周期过滤设计键。例如 app/env/yyyy/mm/dd/file 很适合前缀策略和按龄规则。

14.2 上传

  • 单次 PUT:最大到某个大小限制。更大的文件使用分片上传。
  • 分片上传:数据拆分为多个分片并行上传,由客户端完成或中止上传。
  • 正确设置 Content-Type,浏览器和下载行为才正确。
aws --endpoint-url https://storage.example.com s3 cp ./video.mp4 s3://media/video.mp4 \
  --content-type video/mp4

AWS CLI 在超过配置阈值时自动使用分片上传,可用以下参数调整:

aws configure set default.s3.multipart_threshold 64MB
aws configure set default.s3.multipart_chunksize 64MB

未完成的分片上传会占用空间。请添加生命周期规则中止它们(16.4 节)。

14.3 下载与范围读取

aws --endpoint-url https://storage.example.com s3 cp s3://media/video.mp4 ./video.mp4
aws --endpoint-url https://storage.example.com s3api get-object \
  --bucket media --key video.mp4 --range bytes=0-1023 part.bin

范围读取让播放器和分析引擎可以获取对象的一部分。

14.4 元数据

  • 系统元数据:内容类型、缓存控制、内容编码等头部。
  • 用户元数据:S3 请求中以 x-amz-meta- 为前缀的键值对。
  • 标签:可在生命周期过滤和策略条件中使用的键值标签。
aws --endpoint-url https://storage.example.com s3api put-object-tagging \
  --bucket media --key video.mp4 \
  --tagging 'TagSet=[{Key=retention,Value=short}]'

14.5 预签名 URL

预签名 URL 无需凭据即可授予对单个对象的限时访问:

aws --endpoint-url https://storage.example.com s3 presign s3://media/video.mp4 --expires-in 900

使用短过期时间(分钟级,不是天级)。应在后端授权用户之后再生成 URL。

14.6 删除对象

aws --endpoint-url https://storage.example.com s3 rm s3://media/old.mp4

启用版本控制时,这会创建一个删除标记,之前的版本仍然保留(第 15 章)。


14.7 上传 / 下载 / 删除 / 列举(mc / AWS CLI / rc)

mc:

mc cp file_name rustfs/bucket-name/            # 上传
mc get rustfs/bucket-name/file_name ./file_name # 下载
mc rm rustfs/bucket-name/file_name             # 删除
mc ls rustfs/bucket-name                       # 列举

AWS CLI:

# 配置
aws configure
# AWS Access Key ID: <ak>
# AWS Secret Access Key: <sk>
# Default region: us-east-1

aws --endpoint-url http://localhost:9000 s3 mb s3://my-bucket
aws --endpoint-url http://localhost:9000 s3 cp hello.txt s3://my-bucket/
aws --endpoint-url http://localhost:9000 s3 ls s3://my-bucket/
aws --endpoint-url http://localhost:9000 s3 rm s3://my-bucket/hello.txt

rc:

rc object copy /path/to/file rustfs/my-bucket/file
rc object show rustfs/my-bucket/file
rc object remove rustfs/my-bucket/file

14.8 对象扫描(Scanner / bitrot 检测)

RustFS 提供对象扫描能力,用于发现静默损坏并配合 healing 自动修复。通过控制台或管理 API 可触发扫描任务。


15. 版本控制

版本控制把对对象的每次写入都保留为由版本 ID 标识的独立版本,是防止意外覆盖和删除的首要保护。

15.1 版本控制状态

状态行为
未版本化(默认)覆盖会替换对象,删除会永久移除。
已启用每次写入创建新版本,删除会添加删除标记,旧版本保留。
已暂停新写入获得 null 版本 ID,已有版本保留。用于临时停止累积版本。

一旦启用版本控制,可以暂停,但不能回到从未版本化的状态。在用于备份或合规的存储桶上启用前先做好规划。

15.2 启用与查看版本控制

aws --endpoint-url https://storage.example.com s3api put-bucket-versioning \
  --bucket finance-archive \
  --versioning-configuration Status=Enabled

aws --endpoint-url https://storage.example.com s3api get-bucket-versioning \
  --bucket finance-archive

暂停(已有版本保留):

aws --endpoint-url https://storage.example.com s3api put-bucket-versioning \
  --bucket finance-archive \
  --versioning-configuration Status=Suspended

控制台:Bucket → Properties → Versioning。(verify menu)

15.3 列出版本

aws --endpoint-url https://storage.example.com s3api list-object-versions \
  --bucket finance-archive --prefix invoices/2026-09.csv

输出包含 Versions(每项含 VersionId、IsLatest、LastModified)和 DeleteMarkers。

15.4 恢复历史版本

方式 1:把旧版本复制覆盖到当前对象

aws --endpoint-url https://storage.example.com s3api copy-object \
  --bucket finance-archive --key invoices/2026-09.csv \
  --copy-source "finance-archive/invoices/2026-09.csv?versionId=<VERSION_ID>"

这会创建一个与旧版本一致的新当前版本,历史保持完整。

方式 2:误删后恢复

删除删除标记,使前一个版本重新成为当前版本:

aws --endpoint-url https://storage.example.com s3api delete-object \
  --bucket finance-archive --key invoices/2026-09.csv \
  --version-id <DELETE_MARKER_VERSION_ID>

方式 3:下载特定版本用于审查

aws --endpoint-url https://storage.example.com s3api get-object \
  --bucket finance-archive --key invoices/2026-09.csv \
  --version-id <VERSION_ID> recovered.csv

15.5 永久删除特定版本

用于合规清理或移除敏感数据:

aws --endpoint-url https://storage.example.com s3api delete-object \
  --bucket finance-archive --key invoices/2026-09.csv --version-id <VERSION_ID>

删除版本的权限应限制给小型管理员组(见 12.4 节示例 D)。

15.6 非当前版本与成本

旧版本占用容量,用生命周期规则管理:

  • NoncurrentVersionExpiration:N 天后删除已非当前的版本。
  • NoncurrentVersionTransition:把非当前版本转移到某个层(第 17 章)。
  • 如生命周期引擎支持,保留一个保留数量。(verify)

按存储桶监控增长。频繁被覆盖的大对象会使存储成本快速倍增。

15.7 MFA 删除

部分 S3 兼容系统支持在删除版本或更改版本状态时要求一次性验证码。(verify whether RustFS supports this) 如可用,在归档和备份桶上启用。

15.8 版本控制最佳实践

  • 对承载业务数据、备份以及任何无法再生的数据的存储桶启用版本控制。
  • 版本控制要与非当前版本的生命周期过期搭配,避免存储无限增长。
  • 限制删除版本的权限。
  • 每季度测试一次恢复。
  • 版本控制不是备份:一次损坏的写入也是新版本,而删除存储桶会移除所有版本。请保留集群外副本(第 26 章)。

RustFS 提供 AWS S3 兼容的对象级版本控制。

15.9 三种存储桶状态(启用 / 暂停 / 未启用)

  1. 未启用(默认);
  2. 已启用:为每个对象版本分配唯一 ID;
  3. 已暂停:停止累积新版本,保留现有版本。

一旦启用无法撤销,只能暂停。系统要求:纠删码 + 至少四个磁盘。

15.10 启用版本控制(AWS CLI / mc 实操)

# 使用 AWS CLI
aws --endpoint-url http://localhost:9000 s3api put-bucket-versioning \
  --bucket my-bucket --versioning-configuration Status=Enabled

# 使用 mc
mc version enable rustfs/my-bucket           # 启用
mc version suspend rustfs/my-bucket          # 暂停

15.11 核心操作(版本列举 / 回滚 / undo)

# 查看所有版本
aws --endpoint-url http://localhost:9000 s3api list-object-versions --bucket my-bucket

# 下载指定版本
aws --endpoint-url http://localhost:9000 s3api get-object \
  --bucket my-bucket --key hello.txt --version-id <version-id> out.txt

# mc 撤销操作(恢复到误删/误改前)
mc undo rustfs/my-bucket --recursive

# mc 时间点回看
mc rewind rustfs/my-bucket --older-than 24h

15.12 核心特性

  • 唯一版本 ID:可访问任意时间点快照;
  • 删除标记(delete marker):删除版本化对象时创建删除标记而非物理删除,可删除标记恢复对象;
  • 覆盖对象时创建新版本,旧版本可恢复;
  • 是桶复制、对象锁、生命周期等功能的基础。

16. 生命周期管理

生命周期规则基于对象年龄、前缀或标签自动执行动作。常见动作有过期(删除)、转层(转移到某个层)以及清理未完成的上传。

16.1 规则模型

元素含义
规则 ID唯一名称
状态Enabled 或 Disabled
过滤器规则适用的前缀和/或标签
动作过期、转层、非当前版本处理、中止未完成分片上传

规则异步执行。对象满足条件与动作实际执行之间会有延迟。不要把生命周期当作法定删除的精确计时机制。(verify scheduling behavior)

16.2 过期

删除超过 N 天的当前对象:

{
  "Rules": [
    {
      "ID": "expire-logs-90d",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Expiration": { "Days": 90 }
    }
  ]
}

应用:

aws --endpoint-url https://storage.example.com s3api put-bucket-lifecycle-configuration \
  --bucket app-logs --lifecycle-configuration file://lifecycle-logs.json

读回:

aws --endpoint-url https://storage.example.com s3api get-bucket-lifecycle-configuration --bucket app-logs

16.3 非当前版本过期

保留当前版本,清理旧版本:

{
  "Rules": [
    {
      "ID": "trim-noncurrent-30d",
      "Status": "Enabled",
      "Filter": { "Prefix": "" },
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30 }
    }
  ]
}

16.4 中止未完成的分片上传

{
  "Rules": [
    {
      "ID": "abort-incomplete-7d",
      "Status": "Enabled",
      "Filter": { "Prefix": "" },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}

16.5 转移到某个层

转层把对象移动到配置的远程层(第 17 章)。使用 RustFS CLI:

rc bucket lifecycle rule add rustfs/app-archive \
  --transition-days 30 \
  --storage-class COLDTIER

确认:

rc bucket lifecycle rule list rustfs/app-archive

转层与过期可与前缀或标签过滤器组合。保持规则简单并有文档。(verify exact flags for prefix, tag, and noncurrent transitions)

16.6 按标签过滤

{
  "Rules": [
    {
      "ID": "expire-temp-tagged",
      "Status": "Enabled",
      "Filter": { "Tag": { "Key": "retention", "Value": "short" } },
      "Expiration": { "Days": 14 }
    }
  ]
}

16.7 停用与删除规则

rc bucket lifecycle rule edit rustfs/app-archive --id <rule-id> --disable true

删除规则前先停用,以便观察效果。删除规则的方式是用不含该规则的完整生命周期配置替换,或使用 CLI 的 remove 命令。(verify)

警告:将对象转层的规则依赖该层的存在。规则仍引用某层时,不要删除或更改该层(17.7 节)。

16.8 生命周期治理

  • 生命周期 JSON 纳入版本控制,每条规则写明所有者和用途。
  • 在非生产存储桶上用合成对象和较短天数值测试规则。
  • 保留需求变更时评审规则。
  • 除非启用了版本控制,过期不可逆。在重要存储桶上启用过期前,先确认版本控制能保护数据。

16.9 生命周期规则(XML 配置示例)

RustFS 生命周期管理提供对象过期与分层过渡两类规则,按存储桶配置,与 AWS Lifecycle Management 兼容,支持导入 JSON 格式规则。

生命周期规则 XML 示例(通过 S3 API 设置):

<LifecycleConfiguration>
  <Rule>
    <ID>expire-old-logs</ID>
    <Status>Enabled</Status>
    <Filter>
      <Prefix>logs/</Prefix>
    </Filter>
    <Expiration>
      <Days>90</Days>
    </Expiration>
  </Rule>
  <Rule>
    <ID>cleanup-noncurrent-versions</ID>
    <Status>Enabled</Status>
    <NoncurrentVersionExpiration>
      <NoncurrentDays>30</NoncurrentDays>
    </NoncurrentVersionExpiration>
  </Rule>
</LifecycleConfiguration>
aws --endpoint-url http://localhost:9000 s3api put-bucket-lifecycle-configuration \
  --bucket my-bucket --lifecycle-configuration file://lifecycle.xml

16.10 rc 管理生命周期

rc bucket lifecycle rule list rustfs/my-bucket
rc bucket lifecycle rule add rustfs/my-bucket <...>      # 添加规则
rc bucket lifecycle rule export rustfs/my-bucket         # 导出规则
rc bucket lifecycle restore rustfs/my-bucket/hello.txt --days 7   # 恢复请求(解冻)

旧版 rc ilm 形式仍可用,推荐新脚本使用 rc bucket lifecycle。

16.11 与 WORM 的关系

存储桶过期规则完全符合 WORM 锁定与法定保留:锁定状态的对象在锁过期前不会被生命周期规则删除。


第五部分 — 存储策略


17. 存储分层与第三方对象存储

分层(Tiering)把对象从本地 RustFS 存储桶转移到远程存储目标,同时 RustFS 继续管理源存储桶及其元数据。应用继续使用相同的桶名和键;对象被转层后,由 RustFS 负责取回。

17.1 支持的层类型

RustFS 客户端库列出的层类型:s3、rustfs、minio、aliyun、tencent、huaweicloud、azure、gcs、r2。

层类型目标典型用途
s3Amazon S3 或 S3 兼容服务云端归档或冷存储
rustfs另一个 RustFS 部署自有集群之间的热转冷
minioMinIO 或本地 S3 兼容存储迁移或第二站点
aliyun阿里云 OSS区域云存储
tencent腾讯云 COS区域云存储
huaweicloud华为云 OBS区域云存储
azureAzure Blob Storage企业云归档
gcsGoogle Cloud Storage云端归档
r2Cloudflare R2低出口费用存储

请确认当前发行版支持你的目标提供者和存储类 (verify)。每个提供者在存储、请求、取回和出口上各有定价。请把取回与归档类的最低存储时长等计入总拥有成本。

17.2 架构

客户端 ──► RustFS 存储桶(热)
              │  生命周期转层规则
              ▼
          层(COLDTIER) ──► 第三方存储上的远程桶
  • 被转层的对象仍可通过源存储桶寻址。
  • RustFS 保留每个对象位置的本地元数据。
  • 转层是异步的。注册的层在被生命周期规则引用之前不做事。

17.3 前置条件

  • 源 RustFS 部署及管理访问权限。
  • 提供者处已存在的目标存储桶,以及专用服务身份的访问密钥和秘密。
  • 每个 RustFS 节点到目标端点的网络连通性和防火墙出站规则。
  • 关于层名称、保留、取回预期和退出计划的书面决定。
  • 已确认的提供者存储类名称及任何最短存储时长费用。

17.4 创建层

控制台:Lifecycle / Tiers → Add tier,选择提供者类型、端点、存储桶、区域、凭据,以及大写的层名(例如 COLDTIER)。保存时会运行探测检查端点、凭据和桶权限;探测失败则保存失败。

CLI,以 RustFS 目标为例:

rc bucket lifecycle tier list local

rc bucket lifecycle tier add rustfs COLDTIER local \
  --endpoint https://cold.storage.example.com \
  --bucket cold-archive \
  --region us-east-1 \
  --access-key <service-access-key> \
  --secret-key <service-secret-key>

不同提供者的选项不同。运行 rc bucket lifecycle tier <command> --help 查看你所用类型的选项。(verify exact flags)

S3 兼容提供者示例:

rc bucket lifecycle tier add s3 ARCHIVE local \
  --endpoint https://s3.us-west-2.amazonaws.com \
  --bucket my-org-archive \
  --region us-west-2 \
  --access-key <key> \
  --secret-key <secret>      # verify flags

查看:

rc bucket lifecycle tier info COLDTIER local

不删除层而更新凭据:

rc bucket lifecycle tier edit COLDTIER local --access-key <new> --secret-key <new>   # verify

17.5 创建转层规则

rc bucket lifecycle rule add rustfs/app-archive \
  --transition-days 30 \
  --storage-class COLDTIER

rc bucket lifecycle rule list rustfs/app-archive

推荐做法:先对你控制的某个前缀做过滤,观察第一批转层,再扩大范围。

17.6 验证转层

  • 检查存储桶的对象列表和元数据,已转层对象会显示其存储类或层。
  • 确认目标存储桶收到了对象。不要在目标存储桶中直接重命名、覆盖或删除生成的对象。
  • 通过源存储桶读取一个已转层对象,确认校验和一致。
aws --endpoint-url https://storage.example.com s3api head-object --bucket app-archive --key 2026/09/file.parquet
sha256sum downloaded-file.parquet

17.7 安全维护层

  • 不要在目标存储桶中重命名、覆盖或删除对象。 从 RustFS 集群管理数据,使本地转层元数据与远程数据保持一致。
  • 对象仍引用某层时不要删除该层。 删除会使已转层对象无法从源集群读取。
  • 退役一个层的步骤:
    1. 停用引用该层的生命周期规则。
    2. 将剩余已转层对象恢复/迁移回本地存储或新层。
    3. 确认没有对象引用该层。
    4. 备份层配置并记录目标位置。
    5. 删除该层。
  • 层凭据按与其他服务账户相同的计划轮换。

17.8 恢复已转层数据

取回方式取决于层和提供者。许多归档类需要提交恢复请求且有取回延迟。流程:

  1. 确定需要的对象(前缀、日期范围或版本)。
  2. 通过源 RustFS 工作流触发恢复。(verify restore command or Console action)
  3. 等待完成并校验校验和。
  4. 根据出口和取回费用规划恢复量。

17.9 把第三方存储作为策略

常见模式:

  • 本地热、云端冷: RustFS 本地保留 30–90 天数据,更旧的数据转入低成本云归档类,过期规则在保留期后删除数据。
  • 通过层做多站点复制: 另一站点的第二个 RustFS 集群作为层目标,提供异地副本。
  • 厂商中立的退出: 层目标保持 S3 兼容格式,数据可用标准工具(rclone、AWS CLI 或提供者的迁移服务)在提供者之间迁移。
  • 备份放在不同提供者: 使用与主提供者不同的提供者或账户以降低关联风险。

警告:

  • 转层不能替代备份。源端的删除或损坏会传播过去。请使用版本控制和独立备份。
  • 考虑最短存储时长、提前删除费和取回费用。
  • 定期测试恢复。

17.10 兼容性

RustFS 100% 兼容 S3 协议,可无缝对接几乎所有 S3 客户端和生态:

  • AWS SDK(boto3、aws-sdk-java、aws-sdk-go 等);
  • MinIO SDK 与工具:改 Endpoint 与 AK/SK 即可直接兼容;
  • mc(MinIO Client)、AWS CLI;
  • 应用生态:Docker、Elastic、Grafana、Kafka、MySQL、Nginx、PostgreSQL、ClickHouse、Prometheus、Spark、TensorFlow 等。

提示:Boto3 需设置 signature_version='s3v4',JS SDK 需设置 forcePathStyle: true,Java SDK 需使用 path-style(endpointOverride)。

17.11 从 MinIO 迁移

RustFS 支持二进制替换式迁移——替换二进制或容器镜像即可原地迁移(无需搬数据),大幅降低迁移成本。

17.12 对接第三方 S3 兼容云(作为数据源/目标)

通过 mc mirror / aws s3 sync / rclone 实现跨存储迁移:

# mc mirror 镜像同步
mc alias set src https://s3.amazonaws.com <src-ak> <src-sk>
mc alias set dst http://rustfs-host:9000 <dst-ak> <dst-sk>
mc mirror --overwrite src/my-bucket dst/my-bucket

# rclone 同步
rclone sync mys3:my-bucket rustfs:my-bucket

17.13 rclone 完整用法

rclone 是一个强大的命令行文件同步工具,号称「云存储界的瑞士军刀」,支持 40+ 种存储后端。由于 RustFS 100% 兼容 S3,可直接用 rclone 的 S3 后端对接 RustFS,用于迁移、同步、备份、挂载、加密等场景。相比 mc mirror 和 aws s3 sync,rclone 在过滤规则、并发调优、限速、校验、加密、多后端中转方面能力更强。

13.4.1 安装 rclone

# macOS
brew install rclone

# Linux(二进制快速安装)
curl -O https://downloads.rclone.org/rclone-current-linux-amd64.zip
unzip rclone-current-linux-amd64.zip
cd rclone-*-linux-amd64
sudo cp rclone /usr/local/bin/
sudo chmod 755 /usr/local/bin/rclone

# Windows(Scoop)
scoop install rclone

# 验证
rclone version

13.4.2 配置 RustFS remote

方式一:交互式配置(推荐新手)

rclone config

按提示输入:

n) New remote                    # 新建
name> rustfs                     # 远程名称
Type of storage> s3              # 存储类型选择 s3
provider> Other                  # 选择 Other(兼容 S3)
env_auth> false                  # 手动输入密钥
access_key_id> rustfsadmin       # AK
secret_access_key> rustfssecret  # SK
region> cn-east-1                # 区域(RustFS 不校验,可随意)
endpoint> http://192.168.1.100:9000   # RustFS 地址
location_constraint>             # 留空
acl> private                     # 留空或默认
server_side_encryption>          # 留空
sse_kms_key_id>                  # 留空
storage_class>                   # 留空
y) Yes this is OK                 # 确认
q) Quit config                    # 退出

方式二:命令行非交互式创建

rclone config create rustfs s3 \
  provider=Other \
  env_auth=false \
  access_key_id=rustfsadmin \
  secret_access_key=rustfssecret \
  region=cn-east-1 \
  endpoint=http://192.168.1.100:9000 \
  force_path_style=true

方式三:直接编辑配置文件

编辑 ~/.config/rclone/rclone.conf:

[rustfs]
type = s3
provider = Other
env_auth = false
access_key_id = rustfsadmin
secret_access_key = rustfssecret
region = cn-east-1
endpoint = http://192.168.1.100:9000
force_path_style = true

方式四:环境变量 + 匿名远程(on the fly,不写配置文件)

适合临时操作或 CI/CD,避免密钥落盘:

export RCLONE_S3_PROVIDER=Other
export RCLONE_S3_ENV_AUTH=false
export RCLONE_S3_ACCESS_KEY_ID=rustfsadmin
export RCLONE_S3_SECRET_ACCESS_KEY=rustfssecret
export RCLONE_S3_REGION=cn-east-1
export RCLONE_S3_ENDPOINT=http://192.168.1.100:9000
export RCLONE_S3_FORCE_PATH_STYLE=true

# 使用 :s3: 匿名远端,格式 :s3:<bucket>/<path>
rclone lsd :s3:my-bucket
rclone ls :s3:my-bucket/uploads/

13.4.3 基本命令速查

命令功能
rclone config配置远程
rclone listremotes列出所有远程
rclone lsd <remote>:列出远程所有存储桶(只目录)
rclone ls <remote>:列出所有对象(含大小和路径)
rclone lsl <remote>:bucket列表(含时间、大小、Unix 时间戳)
rclone mkdir <remote>:bucket/path创建目录(S3 中即前缀占位对象)
rclone cat <remote>:bucket/key查看对象内容
rclone copy <src> <dst>复制(不删除目标多余文件)
rclone sync <src> <dst>同步(使目标与源一致,会删除目标多余文件)
rclone move <src> <dst>移动(复制后删除源)
rclone delete <remote>:bucket/key删除单个对象
rclone purge <remote>:bucket/path删除整个目录(含所有对象)
rclone check <src> <dst>校验两端是否一致
rclone size <remote>:bucket统计对象数量与总大小
rclone tree <remote>:bucket树形显示目录结构
rclone touch <remote>:bucket/key创建空对象
rclone copyto <src> <remote>:bucket/key复制到指定 key

13.4.4 常用操作示例

# 列出所有存储桶
rclone lsd rustfs:

# 查看某桶内对象
rclone ls rustfs:my-bucket

# 上传文件到指定 key
rclone copyto ./hello.txt rustfs:my-bucket/hello.txt

# 上传整个目录(保留目录结构)
rclone copy /data/images rustfs:my-bucket/images

# 下载
rclone copy rustfs:my-bucket/backup /local/backup

# 查看对象内容
rclone cat rustfs:my-bucket/config.json | jq .

# 统计桶大小
rclone size rustfs:my-bucket
# Total objects: 1234
# Total size: 10.5 GiB (11274289152 Byte)

13.4.5 sync 与 copy 的区别(重要)

  • copy:只把源有的、目标缺少或已变化的文件复制过去,不会删除目标多出来的文件。适合「只做增量备份」。
  • sync:让目标与源完全一致——源没有的、目标有的会被删除。适合「镜像」。误用时可能删除目标数据,需谨慎。
# 增量备份(安全,不删目标旧文件)
rclone copy rustfs:my-bucket rustfs-archive:my-bucket

# 完全镜像(会删除目标多余文件)
rclone sync /data/current rustfs:my-bucket

# 先演练,不真正执行(打印将要做什么)
rclone sync --dry-run /data/current rustfs:my-bucket

13.4.6 并发与性能调优

# --transfers:并行传输文件数(带宽充足时可调大)
# --checkers:并行检查文件数
# --multi-thread-cutoff/streams:大文件多线程分片并行(对有分块接口的对象存储很有效)
rclone copy --transfers 16 --checkers 16 \
  --multi-thread-cutoff 256M --multi-thread-streams 8 \
  /large-data rustfs:my-bucket
参数默认建议说明
--transfers48~32并行文件数,取决于带宽与后端限流
--checkers816~64并行检查文件数
--multi-thread-cutoff256M64M~256M超过该大小的文件启用多线程
--multi-thread-streams48大文件并行分片流数
--buffer-size16M32M~128M内存缓冲,提升大文件吞吐

S3 后端需注意:RustFS 支持 multipart 上传,多线程分片对大文件加速明显。

13.4.7 限速与调度

# 限制带宽(示例:每天 08:00-18:00 限速 20MB/s,其余时间不限)
rclone sync /data rustfs:my-bucket \
  --bwlimit "08:00,20M 18:00,off"

# 固定限速(u: 上行,d: 下行)
rclone copy rustfs:my-bucket /local --bwlimit 10M
rclone copy /local rustfs:my-bucket --bwlimit 10M:5M  # 上 10MB/s,下 5MB/s

# 限制并发事务数(降低对后端冲击)
rclone copy /data rustfs:my-bucket --tpslimit 20

13.4.8 过滤与排除规则

# 只同步特定类型
rclone sync /data rustfs:my-bucket --include "*.jpg" --include "*.png"

# 排除大文件、临时文件
rclone sync /data rustfs:my-bucket \
  --exclude "*.tmp" \
  --exclude "*.log" \
  --max-size 1G

# 按日期过滤(同步最近 7 天修改的文件)
rclone sync /data rustfs:my-bucket --max-age 7d

# 使用过滤规则文件
# filter.txt 内容示例:
#   - *.tmp
#   - .git/**
#   + *.dat
#   - *
rclone sync /data rustfs:my-bucket --filter-from filter.txt

13.4.9 校验与一致性保障

# 仅检查最近修改的文件(快)
rclone check /data rustfs:my-bucket --one-way

# 校验和对比(精准,但需下载/计算,慢)
rclone check rustfs:my-bucket rustfs-archive:my-bucket --checksum

# 只复制有差异/变化的对象
rclone copy /data rustfs:my-bucket --update --checksum

# 修改时间回溯(与 --update 配合,防止覆盖目标更新的文件)
rclone copy /data rustfs:my-bucket --update --use-mtime

13.4.10 加密备份(crypt 远程)

在对象存储里加密存储,rclone 端加解密:

# 1. 先建一个指向 RustFS 的加密远程
rclone config create rustfs-secret crypt \
  type=crypt \
  remote=rustfs:my-encrypted-bucket \
  filename_encryption=standard \
  directory_name_encryption=true \
  password="<你的强密码>"

# 2. 写数据(写时自动加密)
rclone copy /sensitive rustfs-secret:backup

# 3. 读数据(读时自动解密)
rclone cat rustfs-secret:backup/secret.txt

crypt 密码丢失将无法解密,务必妥善保管。

13.4.11 挂载为本地文件系统

把 RustFS 桶挂载成本地目录(需系统支持 FUSE):

# 简易挂载
rclone mount rustfs:my-bucket /mnt/rustfs

# 推荐:带缓存读写
rclone mount rustfs:my-bucket /mnt/rustfs \
  --vfs-cache-mode writes \
  --vfs-cache-max-size 5G \
  --dir-cache-time 5m

# 卸载
fusermount -u /mnt/rustfs

Windows 用 rclone mount rustfs:my-bucket X:;macOS 用 rclone mount rustfs:my-bucket ~/rustfs --vfs-cache-mode writes。

13.4.12 把 RustFS 对外提供服务(serve)

# 将某一桶作为只读 S3 服务暴露
rclone serve s3 rustfs:my-bucket --addr :9009

# 作为 HTTP 静态站点暴露
rclone serve http rustfs:my-bucket --addr :8080

# 作为 DLNA/WebDAV 暴露
rclone serve webdav rustfs:my-bucket --addr :8085 --user admin --pass admin123

13.4.13 迁移与备份场景示例

场景一:AWS S3 → RustFS 全量迁移

rclone config create aws-s3 s3 \
  provider=AWS \
  env_auth=false \
  access_key_id=<aws-ak> \
  secret_access_key=<aws-sk> \
  region=us-east-1

rclone copy aws-s3:source-bucket rustfs:target-bucket \
  --transfers 16 --checkers 32 --multi-thread-streams 8 -v

场景二:MinIO → RustFS 迁移

MinIO 与 RustFS 同为 S3 兼容,rclone 两端都配成 S3 类型(provider=Other)即可:

rclone config create old-minio s3 provider=Other \
  access_key_id=<minio-ak> secret_access_key=<minio-sk> \
  endpoint=http://old-minio:9000 force_path_style=true

rclone sync old-minio:my-bucket rustfs:my-bucket \
  --checksum --transfers 16 -v

场景三:定时增量备份(cron)

# /etc/cron.d/rustfs-backup
# 每天凌晨 2 点增量备份
0 2 * * * root /usr/local/bin/rclone sync /var/data rustfs:backup/$(date +\%F) --bwlimit 50M >> /var/log/rustfs-backup.log 2>&1

场景四:跨地域异地容灾同步

rclone copy rustfs-primary:my-bucket rustfs-dr:my-bucket \
  --checksum --bwlimit 100M --transfers 32 -v

13.4.14 rclone 常见问题

现象原因/解决
403 AccessDenied / SignatureDoesNotMatch检查 AK/SK 是否正确;确认 endpoint 带 http:// 前缀
Bucket not found用 path-style 访问,确保配置 force_path_style = true,或确认桶名在目的端已存在
Certificate verification failed自签证书/内网 HTTPS,加 --no-check-certificate 或配置 CA
同步后文件数对不上用 rclone check --checksum 校验,必要时 --size-only
大文件进度慢开启 --multi-thread-cutoff/streams 多线程分片
只想演练不执行加 --dry-run 预览将要执行的操作

17.14 与具体产品集成

官方提供集成指南:Nginx 反向代理、Milvus 对象存储、GitLab 对象存储(含 OIDC SSO + S3)、traefik 反向代理、TLS 配置等。


18. 归档与保留

归档意味着以低成本长期保留数据,通常因为政策或法律要求,且极少访问。归档与分层的意图不同:分层是自动的成本与性能优化,而归档是一项保留承诺。

18.1 归档设计

决策项选项
存放位置本地冷 RustFS、远程云归档层、离线介质
保留多久按数据类别设定保留期(例如财务记录 7 年)
不可变性对象锁(第 30 章)
访问谁可以恢复、审批工作流
验证定期校验和验证与恢复测试

18.2 保留模型

  • 基于时间的保留: 在 retain-until 日期之前对象不可删除或覆盖。若 RustFS 支持,使用治理(governance)或合规(compliance)模式的对象锁。(verify modes)
  • 法律保留(Legal hold): 无限期阻止删除,直到被解除。适用于诉讼场景。(verify)
  • 基于策略的保留: 期限后通过生命周期过期,并由策略拒绝访问。弱于对象锁,因为管理员可以修改策略。

大多数 S3 系统要求在创建存储桶时就启用对象锁。请核实 RustFS 是否允许稍后启用。

18.3 归档存储桶设置

aws --endpoint-url https://storage.example.com s3api create-bucket \
  --bucket records-archive-2026
aws --endpoint-url https://storage.example.com s3api put-bucket-versioning \
  --bucket records-archive-2026 --versioning-configuration Status=Enabled

然后:

  1. 创建专用归档服务账户,可写但不可删(见 12.4 节示例 C)。
  2. 为审计人员创建只读恢复组,另设独立的恢复审批组。
  3. 添加生命周期规则:N 天后转层、保留期后过期(仅当保留政策允许过期时)。
  4. 需要处启用对象锁或法律保留(verify)。

18.4 摄入与验证

  • 每批数据写清单:对象列表、大小、SHA-256 校验和。清单存放在单独位置。
  • 上传后通过 head-object(ETag 或校验和头部,如可用)比对校验和,或下载样本做哈希。
  • 在审计日志中记录验证结果。

18.5 恢复流程

  1. 提交恢复工单,包含请求人、原因、范围和审批人。
  2. 审批人确认范围和取回费用估算。
  3. 恢复到暂存存储桶而非原位置,避免覆盖。
  4. 对照清单校验校验和。
  5. 交付恢复的数据,工单关闭时删除暂存副本。

18.6 审计与合规

  • 保留谁在何时访问了归档桶的日志(第 25 章)。
  • 每年对照监管变化评审保留期。
  • 记录保留时间表、法律依据以及过期数据的销毁流程。

18.7 分层存储能力概览

RustFS 支持跨存储介质分层(NVMe/SSD → HDD → 长期冷存储)与跨云类型分层(私有云 + 公有云冷存储),解决海量冷数据的成本问题。

18.8 远程存储层(rc 分层命令)

rc 提供生命周期分层相关命令:

rc bucket lifecycle tier list rustfs
# 添加/检查/更新/删除远程存储层

18.9 冷归档方案

面向百年数据、离线容灾、金融合规归档等场景,支持智能分级(热→温→冷→深度冷)、介质无关性设计、自愈式数据巡检(CRC + 纠删码)、近零功耗存储(休眠模式 <1W/台)、冷数据直读(<15 秒)等能力。


19. 容量扩展

规划得当时,扩展可以在不中断的情况下增加容量或吞吐。两种模式:向集群添加驱动器或节点,以及添加服务器池。

19.1 扩展选项

选项增加什么说明
添加服务器池一组新的节点和驱动器,作为独立纠删布局最常见的增长方式。已有数据不会自动重排。(verify behavior)
向池中添加节点扩展现有池取决于布局规则,参见拓扑文档。(verify)
向节点添加驱动器每节点更多容量必须符合现有布局的纠删集规则。(verify)
更换驱动器修复或升级用同等或更大容量替换故障盘。

普遍适用的规则:

  • 同一池内保持纠删集大小和驱动器类型一致。
  • 不要在同一纠删集中混用性能差异很大的驱动器。
  • 扩展增加的是命名空间容量;请规划数据放置和再平衡时间。
  • 查看发行说明了解支持的最小扩展粒度。

19.2 扩展前检查清单

  • 当前利用率低于扩展阈值(例如低于可用容量的 70%)
  • 24 小时内已验证备份
  • 硬件符合现有拓扑规则
  • 已确认新节点与现有集群间的网络容量
  • 已记录维护窗口或变更审批
  • 已文档化回滚方案

19.3 添加服务器池(概念流程)

  1. 新节点使用与集群相同的操作系统和 RustFS 版本。
  2. 安装 RustFS 二进制或容器。配置定义好之前,不要让其加入旧集群。
  3. 按你安装方式的文档语法更新集群拓扑配置以包含新池。(verify)
  4. 按该版本文档的方式执行滚动重启或应用配置。
  5. 在控制台和 CLI 中确认新池健康。
  6. 创建测试对象并确认其落位且可读。
  7. 随后数日监控容量分布和后台修复。

在 Kubernetes 上,Operator 支持向 Tenant 添加池。请使用该 Operator 版本文档的池操作,并在应用前审阅示例清单的行内注释。(verify)

19.4 移除池(退役)

退役会在移除前把数据迁出该池。过程缓慢,必须规划。

  1. 确保剩余容量能在留有余量的情况下容纳该池的数据。
  2. 通过受支持的命令或 Operator 字段启动退役。(verify)
  3. 监控进度直到该池报告完全排空。
  4. 抽样确认对象数量和校验和。
  5. 从拓扑中移除该池。

池退役期间不要关机或擦除其驱动器。

19.5 容量监控

  • 跟踪每个池、每块盘的已用和空闲容量。
  • 在利用率 70% 和 85% 时告警。
  • 跟踪增长率并预测扩容日期。
  • 更换驱动器后监控修复任务;扩展和修复会竞争 I/O。

19.6 应避免的扩展错误

  • 向要求每集磁盘数相等的布局中只加一块盘。
  • 添加 RustFS 版本不同的节点。
  • 在降级状态下扩展。先修复。
  • 以为容量等于裸容量可用。要计入校验位开销。

19.7 存储池扩容(RUSTFS_VOLUMES 实操)

RustFS 通过向 RUSTFS_VOLUMES 追加存储池扩展容量。追加后新写入可用新增容量,现有对象保留在原池直到运行再均衡。

# 双存储池示例
RUSTFS_VOLUMES="http://rustfs-node1:9000/data/rustfs{1...4}/mnmd http://rustfs-node2:9000/data/rustfs{1...4}/mnmd"

关键:每个节点必须使用完整且顺序一致的存储池列表启动,遗漏或顺序不同会造成拓扑不一致。

扩容流程:

  1. 记录现有存储池;
  2. 新节点安装相同版本与配置;
  3. 所有节点 RUSTFS_VOLUMES 追加新表达式;
  4. 重启 RustFS,等待就绪;
  5. 验证:rc admin pool list rustfs、rc admin pool status rustfs 1 --by-id。

19.8 数据再均衡(Rebalance)

扩容后重新分布现有对象,使各存储池已用比例一致。

rc admin rebalance start rustfs
rc admin rebalance status rustfs
rc admin rebalance stop rustfs

需要至少两个活跃存储池;停止不会把已迁移对象移回。对象移动消耗资源,建议流量低峰执行。rc admin expand start|status|stop 是再均衡的别名。

19.9 存储池退役(Decommission 实操)

通过控制台或 rc 排空并退役存储池,验证数据迁移完成后下线。

19.10 可用性与扩展说明

RustFS 支持水平(加节点/加池)与垂直扩展,避免单点故障。再平衡资源占用低。站点复制(site replication)与节点修复(node healing)用于跨站点容灾。


第六部分 — 程序接入与接口


20. API 参考

RustFS 在同一端点上暴露两组 API:

  1. S3 兼容 API,用于对象操作、存储桶配置和标准 S3 功能集。
  2. Admin API,位于 /rustfs/admin/ 下,用于 RustFS 特有的管理功能,包括分层管理。

20.1 基础 URL 与认证

  • 基地址:https://storage.example.com(可信网络上也可为 http://host:9000)
  • 认证:AWS 签名版本 4(SigV4),使用访问密钥 ID 和秘密访问密钥
  • 区域:你的客户端所需值。如未配置其他区域,使用 us-east-1。(verify default)
  • 寻址:path-style(https://host/bucket/key)始终安全;virtual-hosted 风格(https://bucket.host/key)需要通配符 DNS 和 TLS 证书。

20.2 S3 操作(常用)

类别操作
服务ListBuckets
存储桶CreateBucket、DeleteBucket、HeadBucket、GetBucketLocation、GetBucketVersioning、PutBucketVersioning、GetBucketLifecycleConfiguration、PutBucketLifecycleConfiguration、DeleteBucketLifecycle、GetBucketPolicy、PutBucketPolicy、DeleteBucketPolicy、GetBucketTagging、PutBucketTagging、GetBucketCors、PutBucketCors
对象PutObject、GetObject(含 range)、HeadObject、DeleteObject、DeleteObjects(批量)、CopyObject、ListObjectsV2、ListObjectVersions、PutObjectTagging、GetObjectTagging
分片CreateMultipartUpload、UploadPart、CompleteMultipartUpload、AbortMultipartUpload、ListParts、ListMultipartUploads
访问预签名 GET 和 PUT URL

对具体操作、头部和条件键的支持因版本而异。上线前测试应用使用的操作。(verify compatibility matrix)

20.3 请求示例

使用预签名 URL 的原始 HTTP(由 SDK 或 CLI 生成):

curl -X PUT --upload-file ./report.pdf "https://storage.example.com/reports/report.pdf?X-Amz-Algorithm=...&X-Amz-Signature=..."

用 CLI 手动分片上传:

aws --endpoint-url https://storage.example.com s3api create-multipart-upload \
  --bucket media --key big.bin
aws --endpoint-url https://storage.example.com s3api upload-part \
  --bucket media --key big.bin --part-number 1 --upload-id <UPLOAD_ID> --body part1.bin
aws --endpoint-url https://storage.example.com s3api complete-multipart-upload \
  --bucket media --key big.bin --upload-id <UPLOAD_ID> --multipart-upload file://parts.json

分页: 列表响应是分页的。使用续传令牌(ListObjectsV2)或 NextKeyMarker 与 NextVersionIdMarker(版本列表)。客户端库通过分页器自动处理。

paginator = s3.get_paginator("list_objects_v2")
for page in paginator.paginate(Bucket="media", Prefix="2026/"):
    for obj in page.get("Contents", []):
        print(obj["Key"], obj["Size"])

20.4 用于分层的 Admin API

RustFS 源码和文档中展示的分层管理路由:

方法路径所需权限
PUT/rustfs/admin/v3/tieradmin:SetTier
POST/rustfs/admin/v3/tier/{tiername}admin:SetTier
DELETE/rustfs/admin/v3/tier/{tiername}admin:SetTier

尽可能通过 RustFS CLI 使用。直接调用需要管理凭据签名的请求和你版本所期望的请求格式。(verify request bodies)

示例形态(illustrative only,verify before use):

curl -X DELETE "https://storage.example.com/rustfs/admin/v3/tier/COLDTIER" \
  --aws-sigv4 "aws:amz:us-east-1:s3" --user "$ADMIN_KEY:$ADMIN_SECRET"

在对象仍引用某层时删除该层是危险的。请优先使用 CLI 和 17.7 节的流程。

20.5 错误处理

客户端应处理这些 S3 风格错误:

错误码含义典型修复
AccessDenied策略不允许该操作检查策略和主体
SignatureDoesNotMatch密钥或签名区域错误检查密钥和区域
RequestTimeTooSkewed时钟漂移用 NTP 同步时间
NoSuchBucket / NoSuchKey名称错误或对象已删除核对名称;检查版本
NoSuchVersion找不到版本 ID列出版本
BucketNotEmpty对非空桶执行删除先删除对象和版本
EntityTooLarge上传超过限制使用分片上传
SlowDown / 503被限流或繁忙指数退避加抖动重试
InternalError服务端问题查看日志、重试、提交支持工单

对幂等操作带退避重试。不要盲目重试非幂等的分片完成操作。

20.6 健康与状态端点

存活和就绪检查供负载均衡器和编排器使用。(verify paths) 通常检查 S3 端点根是否返回 HTTP 200,并单独监控控制台和遥测管道(第 36 章)。


21. 命令行客户端(rc)

rc 客户端管理别名、存储桶、对象、生命周期、层、用户、组和策略。以下命令名以撰写时的 RustFS 文档为准。请在你安装的版本中运行 rc --help 和 rc <group> --help。(verify)

21.1 安装命令行客户端 rc

# Linux x86_64
curl -fLO https://github.com/rustfs/cli/releases/download/v0.1.30/rustfs-cli-linux-amd64-v0.1.30.tar.gz
tar -xzf rustfs-cli-linux-amd64-v0.1.30.tar.gz
sudo install -m 0755 rc /usr/local/bin/rc

# Linux arm64
curl -fLO https://github.com/rustfs/cli/releases/download/v0.1.30/rustfs-cli-linux-arm64-v0.1.30.tar.gz
tar -xzf rustfs-cli-linux-arm64-v0.1.30.tar.gz
sudo install -m 0755 rc /usr/local/bin/rc

# macOS
brew install rustfs/tap/rc

# Windows
scoop bucket add rustfs https://github.com/rustfs/scoop-bucket
scoop install rustfs/rc

配置别名与常用命令:

rc alias set local http://localhost:9000 <access-key> <secret-key>
rc alias list
rc ping local            # 服务存活检查
rc ready local           # 依赖就绪检查
rc admin info cluster local
rc admin pool list local
rc bucket list local/
rc object list local/my-bucket
rc object stat local/my-bucket/hello.txt
rc --help                # 查看所有命令

21.2 别名

rc alias set rustfs https://storage.example.com <access-key> <secret-key>
rc alias list
rc alias remove old-alias

安全保存凭据。每个环境(prod、staging)使用专用 profile,避免用服务账户执行管理命令。

21.3 存储桶

rc bucket list rustfs
rc bucket create rustfs/app-data
rc bucket info rustfs/app-data
rc bucket remove rustfs/old-data

21.4 对象

rc object list rustfs/app-data/2026/
rc object copy ./local.txt rustfs/app-data/local.txt
rc object copy rustfs/app-data/local.txt ./restored.txt
rc object remove rustfs/app-data/local.txt
rc object versions rustfs/app-data/local.txt     # verify subcommand

21.5 Mirror 与同步

rc mirror ./site rustfs/web-assets/            # 单向同步到存储桶
rc mirror --overwrite ./site rustfs/web-assets/

21.6 生命周期与层

rc bucket lifecycle rule list rustfs/app-archive
rc bucket lifecycle rule add rustfs/app-archive --transition-days 30 --storage-class COLDTIER
rc bucket lifecycle rule edit rustfs/app-archive --id <rule-id> --disable true
rc bucket lifecycle tier list local
rc bucket lifecycle tier info COLDTIER local

21.7 管理

rc admin user list rustfs
rc admin user add rustfs alice '<temporary-password>'         # verify
rc admin policy list rustfs
rc admin policy attach rustfs readonly-all --user alice        # verify
rc admin group add rustfs analytics-team alice bob             # verify
rc admin user svcacct add rustfs app-web-uploader --policy readwrite-uploads   # verify

21.8 脚本技巧

  • 尽可能使用 --json 输出以便解析。(verify)
  • 每个环境使用独立别名,绝不把秘密硬编码在脚本中;从环境变量或密钥库读取。
  • 在 CI 任务中检查退出码。

RustFS 提供三种管理方式:

  1. Console 控制台(Web UI,默认端口 9001);
  2. 命令行客户端 rc(RustFS 官方 CLI);
  3. 兼容 mc / AWS CLI / SDK / REST API。

22. 第三方应用接入

任何 S3 兼容客户端都可以使用 RustFS。每个应用需要:

设置值
端点https://storage.example.com(或内网 http://host:9000)
访问密钥 / 秘密服务账户的密钥(绝不用 root)
区域客户端所需值,通常 us-east-1
寻址风格除非有 virtual-host DNS 和证书,否则用 path-style
存储桶策略允许的具名存储桶

22.1 应用接入流程

  1. 为应用创建服务账户。
  2. 编写最小权限策略并测试(12.7 节)。
  3. 把密钥存入应用的密钥管理器。
  4. 配置端点、区域和寻址风格。
  5. 运行冒烟测试:在测试前缀上执行列举、put、get、delete。
  6. 设置错误和吞吐监控。
  7. 在服务目录中记录所有者、用途、存储桶和轮换日期。

22.2 AWS CLI

aws configure --profile rustfs-prod
# 访问密钥、秘密密钥、区域 us-east-1、输出 json

aws --profile rustfs-prod --endpoint-url https://storage.example.com s3 ls
aws --profile rustfs-prod --endpoint-url https://storage.example.com s3 cp ./file.txt s3://app-data/

为方便设置 shell 别名:

alias rustfs-s3='aws --profile rustfs-prod --endpoint-url https://storage.example.com'

22.3 Python(boto3)

import os
import boto3
from botocore.client import Config

s3 = boto3.client(
    "s3",
    endpoint_url=os.environ["RUSTFS_ENDPOINT"],
    aws_access_key_id=os.environ["RUSTFS_ACCESS_KEY"],
    aws_secret_access_key=os.environ["RUSTFS_SECRET_KEY"],
    region_name="us-east-1",
    config=Config(signature_version="s3v4", s3={"addressing_style": "path"}),
)

s3.put_object(Bucket="app-data", Key="health/check.txt", Body=b"ok")
print(s3.get_object(Bucket="app-data", Key="health/check.txt")["Body"].read())

22.4 Node.js(AWS SDK v3)

import { S3Client, PutObjectCommand } from "@aws-sdk/client-s3";

const client = new S3Client({
  endpoint: process.env.RUSTFS_ENDPOINT,
  region: "us-east-1",
  forcePathStyle: true,
  credentials: {
    accessKeyId: process.env.RUSTFS_ACCESS_KEY,
    secretAccessKey: process.env.RUSTFS_SECRET_KEY,
  },
});

await client.send(new PutObjectCommand({
  Bucket: "app-data",
  Key: "health/check.txt",
  Body: "ok",
}));

22.5 Java、Go 等其他语言

使用该语言的官方 AWS SDK,同样配置四项:端点覆盖、区域、启用 path-style、凭据。多数 SDK 将其暴露为 endpointOverride、forcePathStyle 或 UsePathStyle 以及凭据提供者。

22.6 rclone

[rustfs]
type = s3
provider = Other
access_key_id = <access-key>
secret_access_key = <secret-key>
endpoint = https://storage.example.com
region = us-east-1
rclone lsd rustfs:
rclone sync ./photos rustfs:photos-2026 --dry-run    # 先测试

22.7 备份工具

工具配置
Restic-r s3:https://storage.example.com/backups,访问密钥放环境变量
Duplicati存储类型选 "S3 Compatible",服务器 URL、存储桶、密钥
Velero(Kubernetes)AWS 插件,s3Url 指向 RustFS 并设置 region
数据库备份工具使用其 S3 或自定义 S3 选项;优先用启用版本控制的专用桶

使用带版本控制和 backup-writer 策略的存储桶(见 12.4 节示例 C)。

22.8 浏览器应用与 CORS

前端代码不应持有长期密钥。模式:

  1. 浏览器请求你的后端上传文件。
  2. 后端检查授权并返回预签名 PUT URL。
  3. 浏览器直接上传到 RustFS。

如果浏览器直接调用 RustFS,请在存储桶上配置 CORS,仅允许你站点的源以及你使用的方法和头部:

{
  "CORSRules": [
    {
      "AllowedOrigins": ["https://app.example.com"],
      "AllowedMethods": ["GET", "PUT"],
      "AllowedHeaders": ["*"],
      "ExposeHeaders": ["ETag"],
      "MaxAgeSeconds": 3000
    }
  ]
}
aws --endpoint-url https://storage.example.com s3api put-bucket-cors \
  --bucket app-uploads --cors-configuration file://cors.json

22.9 桌面 GUI 客户端

Cyberduck、S3 Browser、Commander One 等工具支持自定义 S3 端点。选择 S3 兼容或自定义选项,填入端点、密钥,如有 path-style 选项则启用。这些适合偶尔需要访问的人员;应用应使用 SDK。

22.10 连接故障排查

症状原因修复
SignatureDoesNotMatch密钥、区域或寻址错误检查这四项设置
RequestTimeTooSkewed客户端时钟同步 NTP
大文件上传卡住代理超时或缓冲增大代理超时、禁用请求缓冲
服务器上可用、笔记本上失败防火墙或代理从同一网络用 curl 测试
virtual-host 错误DNS 未配置启用 path-style

23. MCP 使用

RustFS MCP 服务器是一个 Rust 编写的高性能 Model Context Protocol 服务器,让 AI/LLM 工具(Claude Desktop、Cursor、Windsurf、Trae 等)通过标准化协议操作 S3 兼容对象存储。

23.1 可用工具

工具功能参数
list_buckets列出所有存储桶无
list_objects列出对象bucket_name、prefix(可选)
upload_file上传文件local_file_path、bucket_name、object_key、content_type(可选)、storage_class(可选)
get_object获取对象bucket_name、object_key、version_id(可选)、mode(read/download)、local_path、max_content_size(可选)
create_bucket创建存储桶bucket_name
delete_bucket删除存储桶bucket_name

23.2 从源码构建

git clone https://github.com/rustfs/rustfs.git
cd rustfs
cargo build --release -p rustfs-mcp
# 二进制:./target/release/rustfs-mcp

23.3 命令行 / 环境变量配置

export AWS_ACCESS_KEY_ID=<access-key>
export AWS_SECRET_ACCESS_KEY=<secret-key>
export AWS_REGION=us-east-1
export AWS_ENDPOINT_URL=http://localhost:9000
rustfs-mcp --log-level info

命令行选项:

rustfs-mcp --access-key-id <ak> --secret-access-key <sk> --region us-east-1 --endpoint-url http://localhost:9000

23.4 接入 AI IDE(以 Trae 为例)

在 MCP 配置中(MCP → 添加)加入,使用 Docker 方式运行:

{
  "mcpServers": {
    "rustfs-mcp": {
      "command": "docker",
      "args": [
        "run", "--rm", "-i",
        "-e", "AWS_ACCESS_KEY_ID",
        "-e", "AWS_SECRET_ACCESS_KEY",
        "-e", "AWS_REGION",
        "-e", "AWS_ENDPOINT_URL",
        "rustfs/rustfs-mcp"
      ],
      "env": {
        "AWS_ACCESS_KEY_ID": "rustfs_access_key",
        "AWS_SECRET_ACCESS_KEY": "rustfs_secret_key",
        "AWS_REGION": "cn-east-1",
        "AWS_ENDPOINT_URL": "rustfs_instance_url"
      }
    }
  }
}

也可用命令行参数方式:

{
  "mcpServers": {
    "rustfs-mcp": {
      "command": "/path/to/rustfs-mcp",
      "args": [
        "--access-key-id", "<ak>",
        "--secret-access-key", "<sk>",
        "--region", "us-west-2"
      ]
    }
  }
}

配置成功后,在对话中直接说「帮我列出当前 rustfs 实例中的存储桶」,即可自动调用 list_buckets 工具。


24. 如何自己写程序接入

24.1 SDK 推荐

RustFS 官方推荐直接使用标准 AWS S3 SDK(经多年调优、稳定)。已提供官方 SDK 文档:Java、JavaScript、TypeScript、Python、Rust、Golang。

  • MinIO SDK 可改 Endpoint + AK/SK 后直接兼容;
  • 尽量使用 AWS SDK,避免使用部分“魔改”的国产云厂商 SDK。

24.2 Python (Boto3) 完整示例

pip install boto3
import boto3
import json
from botocore.client import Config

ENDPOINT = 'http://192.168.1.100:9000'
AK = 'rustfsadmin'
SK = 'rustfssecret'

s3 = boto3.client(
    's3',
    endpoint_url=ENDPOINT,
    aws_access_key_id=AK,
    aws_secret_access_key=SK,
    config=Config(signature_version='s3v4'),
    region_name='us-east-1'
)

bucket = 'my-bucket'

# 创建桶
try:
    s3.create_bucket(Bucket=bucket)
except s3.exceptions.BucketAlreadyOwnedByYou:
    pass

# 上传
s3.upload_file('hello.txt', bucket, 'hello.txt')

# 下载
s3.download_file(bucket, 'hello.txt', 'hello-downloaded.txt')

# 列举对象
resp = s3.list_objects_v2(Bucket=bucket)
for obj in resp.get('Contents', []):
    print(f"- {obj['Key']} ({obj['Size']} bytes)")

# 预签名 URL(GET 下载)
get_url = s3.generate_presigned_url(
    ClientMethod='get_object',
    Params={'Bucket': bucket, 'Key': 'hello.txt'},
    ExpiresIn=600
)

# 预签名 URL(PUT 上传)
put_url = s3.generate_presigned_url(
    ClientMethod='put_object',
    Params={'Bucket': bucket, 'Key': 'upload-by-url.txt'},
    ExpiresIn=600
)
print('Presigned PUT URL:', put_url)

# 分片上传大文件(>10MB)
import os
file_path = 'largefile.bin'
key = 'largefile.bin'
part_size = 5 * 1024 * 1024  # 5 MB

resp = s3.create_multipart_upload(Bucket=bucket, Key=key)
upload_id = resp['UploadId']
parts = []

try:
    with open(file_path, 'rb') as f:
        part_number = 1
        while True:
            data = f.read(part_size)
            if not data:
                break
            part = s3.upload_part(
                Bucket=bucket, Key=key, PartNumber=part_number,
                UploadId=upload_id, Body=data
            )
            parts.append({'ETag': part['ETag'], 'PartNumber': part_number})
            part_number += 1
    s3.complete_multipart_upload(
        Bucket=bucket, Key=key, UploadId=upload_id,
        MultipartUpload={'Parts': parts}
    )
except Exception as e:
    s3.abort_multipart_upload(Bucket=bucket, Key=key, UploadId=upload_id)
    raise e

# 删除对象与桶
s3.delete_object(Bucket=bucket, Key='hello.txt')
s3.delete_bucket(Bucket=bucket)

24.3 Java (AWS SDK v2) 完整示例

pom.xml:

<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
    <version>2.25.0</version>
</dependency>
import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
import software.amazon.awssdk.core.sync.RequestBody;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;

import java.net.URI;
import java.nio.file.Paths;
import java.time.Duration;

public class RustFSDemo {
    public static void main(String[] args) {
        String endpoint = "http://192.168.1.100:9000";
        String ak = "rustfsadmin";
        String sk = "rustfssecret";

        S3Client s3 = S3Client.builder()
            .endpointOverride(URI.create(endpoint))
            .forcePathStyle(true)          // 关键:path-style
            .region(Region.US_EAST_1)
            .credentialsProvider(StaticCredentialsProvider.create(
                AwsBasicCredentials.create(ak, sk)))
            .build();

        String bucket = "my-bucket";

        // 创建桶
        s3.createBucket(b -> b.bucket(bucket));

        // 上传
        s3.putObject(b -> b.bucket(bucket).key("hello.txt"),
            RequestBody.fromFile(Paths.get("hello.txt")));

        // 列出对象
        ListObjectsV2Response list = s3.listObjectsV2(b -> b.bucket(bucket));
        list.contents().forEach(o -> System.out.println(o.key() + " " + o.size()));

        // 下载
        byte[] data = s3.getObjectAsBytes(b -> b.bucket(bucket).key("hello.txt")).asByteArray();
        System.out.println(new String(data));

        // 预签名 URL(GET)
        try (S3Presigner presigner = S3Presigner.builder()
                .endpointOverride(URI.create(endpoint))
                .region(Region.US_EAST_1)
                .credentialsProvider(StaticCredentialsProvider.create(
                    AwsBasicCredentials.create(ak, sk)))
                .build()) {
            var presigned = presigner.presignGetObject(GetObjectPresignRequest.builder()
                .getObjectRequest(b -> b.bucket(bucket).key("hello.txt"))
                .signatureDuration(Duration.ofMinutes(10))
                .build());
            System.out.println("Presigned URL: " + presigned.url());
        }

        // 删除对象与桶
        s3.deleteObject(b -> b.bucket(bucket).key("hello.txt"));
        s3.deleteBucket(b -> b.bucket(bucket));

        s3.close();
    }
}

24.4 Golang (aws-sdk-go-v2) 完整示例

go get github.com/aws/aws-sdk-go-v2/service/s3
go get github.com/aws/aws-sdk-go-v2/credentials
package main

import (
    "context"
    "fmt"
    "log"
    "os"
    "strings"

    "github.com/aws/aws-sdk-go-v2/aws"
    "github.com/aws/aws-sdk-go-v2/credentials"
    "github.com/aws/aws-sdk-go-v2/service/s3"
)

func main() {
    ctx := context.Background()

    region := os.Getenv("RUSTFS_REGION")
    accessKeyID := os.Getenv("RUSTFS_ACCESS_KEY_ID")
    secretAccessKey := os.Getenv("RUSTFS_SECRET_ACCESS_KEY")
    endpoint := os.Getenv("RUSTFS_ENDPOINT_URL")

    if accessKeyID == "" || secretAccessKey == "" || region == "" || endpoint == "" {
        log.Fatal("missing env: RUSTFS_ACCESS_KEY_ID / RUSTFS_SECRET_ACCESS_KEY / RUSTFS_REGION / RUSTFS_ENDPOINT_URL")
    }

    cfg := aws.Config{
        Region:      region,
        Credentials: aws.NewCredentialsCache(credentials.NewStaticCredentialsProvider(accessKeyID, secretAccessKey, "")),
    }

    client := s3.NewFromConfig(cfg, func(o *s3.Options) {
        o.BaseEndpoint = aws.String(endpoint)
        o.UsePathStyle = true
    })

    // 创建桶
    _, err := client.CreateBucket(ctx, &s3.CreateBucketInput{Bucket: aws.String("go-sdk-rustfs")})
    if err != nil {
        log.Fatalf("create bucket failed: %v", err)
    }

    // 上传对象
    _, err = client.PutObject(ctx, &s3.PutObjectInput{
        Bucket: aws.String("go-sdk-rustfs"),
        Key:    aws.String("test.txt"),
        Body:   strings.NewReader("hello rustfs"),
    })
    if err != nil {
        log.Fatalf("upload failed: %v", err)
    }

    // 下载对象
    resp, err := client.GetObject(ctx, &s3.GetObjectInput{
        Bucket: aws.String("go-sdk-rustfs"),
        Key:    aws.String("test.txt"),
    })
    if err != nil {
        log.Fatalf("download failed: %v", err)
    }
    defer resp.Body.Close()

    // 列出对象
    listResp, err := client.ListObjectsV2(ctx, &s3.ListObjectsV2Input{
        Bucket: aws.String("go-sdk-rustfs"),
    })
    if err != nil {
        log.Fatalf("list failed: %v", err)
    }
    for _, obj := range listResp.Contents {
        fmt.Println(" -", *obj.Key)
    }

    // 预签名上传 URL
    presignClient := s3.NewPresignClient(client)
    putInput := &s3.PutObjectInput{Bucket: aws.String("go-sdk-rustfs"), Key: aws.String("a.txt")}
    putURL, err := presignClient.PresignPutObject(ctx, putInput)
    if err == nil {
        fmt.Println("Presigned PUT URL:", putURL.URL)
    }

    // 预签名下载 URL
    getInput := &s3.GetObjectInput{Bucket: aws.String("go-sdk-rustfs"), Key: aws.String("a.txt")}
    getURL, err := presignClient.PresignGetObject(ctx, getInput)
    if err == nil {
        fmt.Println("Presigned GET URL:", getURL.URL)
    }
}

24.5 Rust (aws-sdk-s3) 完整示例

Cargo.toml:

[dependencies]
aws-config = { version = "1", features = ["behavior-version-latest"] }
aws-sdk-s3 = "1"
aws-credential-types = "1"
tokio = { version = "1", features = ["full"] }
use aws_config::BehaviorVersion;
use aws_credential_types::Credentials;
use aws_sdk_s3::config::Region;
use aws_sdk_s3::primitives::ByteStream;
use aws_sdk_s3::Client;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let access_key_id = std::env::var("RUSTFS_ACCESS_KEY_ID")?;
    let secret_access_key = std::env::var("RUSTFS_SECRET_ACCESS_KEY")?;
    let region = std::env::var("RUSTFS_REGION")?;
    let endpoint_url = std::env::var("RUSTFS_ENDPOINT_URL")?;

    let credentials = Credentials::new(access_key_id, secret_access_key, None, None, "rustfs");

    let config = aws_config::defaults(BehaviorVersion::latest())
        .region(Region::new(region))
        .credentials_provider(credentials)
        .endpoint_url(endpoint_url)
        .load()
        .await;

    let client = Client::new(&config);

    // 创建桶
    client.create_bucket().bucket("rust-sdk-demo").send().await?;

    // 上传对象
    let data = tokio::fs::read("/path/to/1.txt").await?;
    client
        .put_object()
        .bucket("rust-sdk-demo")
        .key("1.txt")
        .body(ByteStream::from(data))
        .send()
        .await?;

    // 列出对象
    let res = client
        .list_objects_v2()
        .bucket("rust-sdk-demo")
        .send()
        .await?;
    for obj in res.contents() {
        println!("Object: {:?}", obj.key());
    }

    // 下载对象
    client
        .get_object()
        .bucket("rust-sdk-demo")
        .key("1.txt")
        .send()
        .await?;

    Ok(())
}

24.6 JavaScript / TypeScript (AWS SDK v3) 完整示例

npm install @aws-sdk/client-s3 @aws-sdk/s3-request-presigner
import { S3Client, CreateBucketCommand, PutObjectCommand,
         GetObjectCommand, ListObjectsV2Command, DeleteObjectCommand,
         CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { readFileSync, createReadStream, statSync } from "fs";

const s3 = new S3Client({
  endpoint: "http://192.168.1.100:9000",
  region: "us-east-1",
  credentials: {
    accessKeyId: "rustfsadmin",
    secretAccessKey: "rustfssecret",
  },
  forcePathStyle: true,   // 关键:path-style
});

// 创建桶
await s3.send(new CreateBucketCommand({ Bucket: "my-bucket" }));

// 上传
const data = readFileSync("hello.txt");
await s3.send(new PutObjectCommand({ Bucket: "my-bucket", Key: "hello.txt", Body: data }));

// 下载
const response = await s3.send(new GetObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" }));
const streamToBuffer = async (stream) => {
  const chunks = [];
  for await (const chunk of stream) chunks.push(chunk);
  return Buffer.concat(chunks);
};
const buffer = await streamToBuffer(response.Body);

// 列举
const res = await s3.send(new ListObjectsV2Command({ Bucket: "my-bucket" }));
res.Contents?.forEach((obj) => console.log(`${obj.Key} (${obj.Size} bytes)`));

// 预签名 URL
const getUrl = await getSignedUrl(s3, new GetObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" }), { expiresIn: 600 });
const putUrl = await getSignedUrl(s3, new PutObjectCommand({ Bucket: "my-bucket", Key: "upload.txt" }), { expiresIn: 600 });

// 删除
await s3.send(new DeleteObjectCommand({ Bucket: "my-bucket", Key: "hello.txt" }));

TypeScript 版本与 JS 相同,只需类型标注,初始化方式一致:

import { S3Client } from "@aws-sdk/client-s3";

const rustfs_client = new S3Client({
    region: "cn-east-1",
    credentials: {
        accessKeyId: process.env.RUSTFS_ACCESS_KEY_ID!,
        secretAccessKey: process.env.RUSTFS_SECRET_ACCESS_KEY!,
    },
    endpoint: process.env.RUSTFS_ENDPOINT_URL!,
    forcePathStyle: true,
});

24.7 S3 兼容性 API

原生管理 API 使用 /rustfs/admin/v3 前缀,需 AWS Signature V4 签名;数据面使用标准 S3 REST API(PUT/{bucket}、GET/PUT/DELETE/{bucket}/{object} 等)。

各语言关键点汇总:

语言关键配置
Python (boto3)signature_version='s3v4' + endpoint_url
Java (v2)endpointOverride + forcePathStyle(true)
Go (v2)BaseEndpoint + UsePathStyle: true
Rustendpoint_url
JS/TS (v3)endpoint + forcePathStyle: true

第七部分 — 运维


25. 监控、日志与审计

25.1 监控什么

领域指标
可用性端点健康、错误率、节点状态
容量每盘每池已用/空闲空间、增长率
性能请求延迟、吞吐、队列深度
修复(Healing)后台修复状态与耗时
生命周期转层与过期活动、失败
层各层连通性、转层积压、恢复延迟
身份SSO 登录失败、异常管理操作
成本按桶与按层的存储字节数、请求量、出口量

RustFS 通过 OTLP 推送指标、链路和日志,没有原生 Prometheus /metrics 端点。请运行 OpenTelemetry Collector,让 Prometheus 抓取该采集器。完整技术栈见第 36 章。

25.2 应定义的告警

  • 节点或端点宕机超过 2 分钟
  • 容量超过 70%(警告)和 85%(严重)
  • 错误率持续 5 分钟高于基线阈值
  • 层不可达或转层失败
  • 修复耗时超过目标窗口
  • 根账户被使用(任何使用都是告警)
  • 变更窗口之外的策略或层级变更

25.3 日志

  • Docker:docker logs 和挂载的 /logs 目录
  • systemd:journalctl -u rustfs
  • 用 logrotate 或平台日志驱动轮转日志,避免磁盘写满。

将日志发送到集中系统(例如 Loki、Elasticsearch 或 SIEM)。

25.4 审计追踪

审计应记录:

  • 认证事件(成功与失败)
  • 管理变更:用户、组、策略、层、生命周期规则、版本控制、存储桶策略
  • 对敏感存储桶的数据访问
  • 删除操作,包括版本删除和存储桶删除

按政策要求的保留期保存审计记录,尽可能一次写入存储,并限制对审计库的访问。审计目标见 29.6 节。


26. 备份、灾难恢复与升级

26.1 防护层次

对象存储通过纠删编码防护磁盘故障,但你仍需要:

  1. 版本控制,从覆盖和删除中恢复(第 15 章)
  2. 对象锁或保留,保护不得篡改的记录(第 18 章)
  3. 集群外副本,位于另一位置或提供者
  4. 配置备份(策略、生命周期、层、身份配置、拓扑)

26.2 集群外备份策略

  • 遵循 3-2-1 规则:三份副本、两种介质、一份异地。
  • 用计划同步(rc mirror 或 rclone sync)把关键存储桶复制到第二个 RustFS 集群或第三方提供者。
  • 使用不可删除的 backup-writer 服务账户(见 12.4 节示例 C)。
  • 每月恢复样本进行验证。

用 rclone 定时复制的示例:

rclone copy rustfs:critical-data remote-backup:critical-data-$(date +%F) --checksum

备份目标用 copy 而非 sync,使源端删除不会立即传播过去。

26.3 配置备份

备份以下项目(例如放入访问受限的 Git):

  • 环境文件和服务单元(去除或加密其中的秘密)
  • 策略 JSON 文件
  • 存储桶生命周期、CORS、版本控制和标签配置
  • 层配置(名称、类型、端点;密钥单独保存)
  • 身份提供者设置
  • 拓扑与 Operator 清单

秘密保存在密钥库中。记录恢复顺序:先拓扑,再身份,再层,最后存储桶和策略。

26.4 灾难恢复

定义:

  • RPO(恢复点目标):可接受多少数据丢失,决定复制或备份频率。
  • RTO(恢复时间目标):恢复允许花多长时间,决定待命容量和预案。

需要演练的场景:

场景响应
一块盘故障更换磁盘;监控修复
一个节点故障恢复节点;确认修复;检查仲裁
整个站点丢失应用切换到备用集群;从异地副本恢复
误删存储桶从异地副本恢复或按清单重建
应用侧勒索软件使用拒绝删除的备份凭据;恢复版本或备份
层提供者故障应用继续用本地数据服务;排队等待提供者恢复后恢复
根凭据丢失双保管人的应急流程和已文档化的 IdP 恢复路径

26.5 升级

  1. 阅读当前版本到目标版本之间每个版本的发行说明和升级指南。
  2. 在预发环境用生产配置副本测试升级。
  3. 备份配置并验证异地数据副本。
  4. 安排维护窗口并通知用户。
  5. 拓扑支持时逐节点滚动升级,节点间确认健康。
  6. 验证 S3 操作、控制台登录、SSO 登录、层连通性和一次生命周期测试。
  7. 升级被接受前保留上一版镜像或二进制以便回滚。

只有数据格式未变时回滚才安全。升级前查看发行说明。(verify rollback guidance)


26.6 备份策略检查清单

  1. 配置数据备份:定期备份 /etc/default/rustfs、systemd 服务、TLS 证书、KMS 密钥目录;
  2. IAM 数据备份:导出 GET /rustfs/admin/v3/export-iam,异地保存;
  3. 数据冗余:生产环境使用 EC ≥ 4 的 MNMD 集群保证单点失效不影响数据;
  4. 站点级容灾:使用跨区域复制(Replication)实现整桶异地备份;
  5. 对象级保护:启用版本控制 + 对象锁定防误删误改。

26.7 导出/导入 IAM

# 导出(含用户、组、策略、映射)
curl -s "http://localhost:9000/rustfs/admin/v3/export-iam" \
  --user "<ak>:<sk>" --aws-sigv4 "aws:amz:us-east-1:s3" > iam-backup.json

# 导入恢复
curl -s -X PUT "http://localhost:9000/rustfs/admin/v3/import-iam" \
  --user "<ak>:<sk>" --aws-sigv4 "aws:amz:us-east-1:s3" \
  -H "Content-Type: application/json" --data-binary @iam-backup.json

26.8 数据恢复

  • 磁盘故障 → 集群自动 healing 修复;
  • 误删对象 → 版本控制下删除标志可恢复(mc undo);
  • 时间点恢复 → 启用版本控制后 mc rewind 查看任意时间点。

26.9 滚动升级策略(多节点)

  • 多节点集群:一次替换一个节点或 Pod,等待其报告就绪后再继续;
  • 升级前阅读目标版本发行说明,确认集群健康。

26.10 三种升级工作流

部署方式说明
二进制升级由 systemd 管理的可执行文件替换与回滚
容器升级使用持久化数据卷替换镜像
Kubernetes 升级由 Helm 和 Operator 管理的工作负载

26.11 二进制升级示例

# 备份旧二进制
cp /usr/local/bin/rustfs /usr/local/bin/rustfs.bak

# 下载新版本
wget https://dl.rustfs.com/artifacts/rustfs/release/rustfs-linux-x86_64-musl-latest.zip
unzip -o rustfs-linux-x86_64-musl-latest.zip
chmod +x rustfs
mv rustfs /usr/local/bin/

# 逐个节点重启
systemctl restart rustfs
systemctl status rustfs

26.12 容器升级

docker pull rustfs/rustfs:latest
docker stop rustfs && docker rm rustfs
# 使用相同数据卷重新创建

27. 运维手册(Runbook)

27.1 添加新用户(SSO)

  1. 将用户加入相应的 IdP 组。
  2. 请用户登录一次控制台并确认可访问。
  3. 确认用户只能执行被允许的操作。
  4. 记录该变更。

27.2 添加新应用

遵循 22.1 节。

27.3 轮换服务账户密钥

遵循 11.5 节。

27.4 员工离职

遵循 11.6 节。另检查其个人访问密钥和共享存储桶策略。

27.5 调查意外删除

  1. 从审计日志确定存储桶、前缀和时间窗口。
  2. 检查是否启用了版本控制。若是,列出版本和删除标记。
  3. 通过删除删除标记或复制版本回来恢复(15.4 节)。
  4. 若未启用版本控制,从异地副本恢复。
  5. 确定责任主体及其策略,收紧策略。
  6. 撰写事后复盘记录。

27.6 从磁盘故障中恢复

  1. 确认磁盘已故障(控制台、日志或 smartctl)。
  2. 用同等或更大容量替换。
  3. 启动修复并监控直到完成。
  4. 验证对象数量和健康状况。

27.7 响应层故障

  1. 通过提供者状态页确认故障。
  2. 若依赖的生命周期规则会反复失败,先暂停它们。
  3. 继续用本地数据服务。需要该层的已转层对象在恢复前会失败。
  4. 提供者恢复后,恢复规则并确认积压清空。

27.8 systemd unit 模板(二进制安装)

[Unit]
Description=RustFS object storage
After=network-online.target
Wants=network-online.target

[Service]
User=rustfs
Group=rustfs
EnvironmentFile=/etc/rustfs/rustfs.env
ExecStart=/usr/local/bin/rustfs
Restart=on-failure
RestartSec=5
LimitNOFILE=1048576

[Install]
WantedBy=multi-user.target

将秘密放在 /etc/rustfs/rustfs.env,权限 0600,属主 root。(verify variable names and flags for your version)


28. 故障排查

领域问题诊断步骤
启动服务退出读日志;检查数据目录属主;用 ss -ltnp 检查端口冲突
启动端口被占用定位进程;改端口或停掉冲突服务
登录控制台登录失败检查凭据;检查 SSO 设置;检查时钟同步
SSO重定向循环或不匹配与 IdP 逐字符比对重定向 URI
SSO登录成功但无访问权检查令牌中的组声明;验证映射
访问AccessDenied用策略模拟;确认资源 ARN 和桶名
上传超过某大小失败代理请求体大小限制;改用分片
上传缓慢网络路径、磁盘饱和、代理缓冲
版本控制存储意外增长检查非当前版本;添加非当前版本过期
生命周期规则未执行确认规则状态和过滤器;等待异步处理;查日志
分层转层停滞检查层连通性、凭据和提供者配额
分层已转层对象不可读检查层是否存在、凭据是否有效;不要删除该层;提交支持工单
容量池接近满规划扩展;检查失控版本或未完成上传
修复换盘后修复时间长检查 I/O 争用;如可能降低客户端负载
扩展池已添加但数据未迁移新写入会进新池属正常;已有数据并非在所有情况下都会自动再平衡 (verify)
退役池排不空检查剩余容量;查看日志中的错误
时间签名失败在客户端和服务端同步 NTP

升级问题时,请提供 RustFS 版本、部署拓扑、去除秘密后的相关日志行、确切命令或请求,以及事件发生时间。


28.1 磁盘故障

磁盘故障时 RustFS 自动进入降级模式,通过纠删码重建数据(healing)。

rc admin info cluster rustfs       # 查看集群与磁盘健康
curl http://localhost:9000/health

28.2 对象检查与自动恢复

RustFS 持续 bitrot 检测,发现损坏自动 healing。

28.3 节点故障

  • 任意 1 台服务器故障不影响数据(EC 冗余);
  • 更换硬件后重新挂载磁盘(XFS label 相同)即可恢复;
  • 站点复制(site replication)与节点修复(node healing)用于跨站点容灾。

28.4 常见问题

症状可能原因解决
SignatureDoesNotMatch未用 v4 签名设置 signature_version='s3v4'(boto3)
EndpointConnectionError地址错误或服务未启动检查 endpoint 与状态
AccessDenied凭证错误或权限不足检查 AK/SK 或桶策略
Bucket not found / 403Nginx HEAD 转 GET加 proxy_cache_convert_head off
PermanentRedirect未启用 path-style设置 forcePathStyle=true
多节点无法启动时间不同步配置 NTP 时间同步
目录权限拒绝容器 UID 不匹配chown -R 10001:10001 /data
NoSuchKey对象不存在检查 Key 拼写
复制失败版本控制/对象锁定不匹配两端启用版本控制并保持锁定一致

第八部分 — 高级特性


29. 事件通知

事件通知把存储桶活动发送给外部系统。常见用途是文件到达时通过 webhook 启动工作流。通知默认禁用。

事件通知有两个独立部分:

  1. 通知目标: 事件投递到哪里。每个服务器用环境变量定义目标。
  2. 存储桶通知配置: 哪个桶、哪些事件类型、哪些键过滤器,发送到哪个目标 ARN。

支持的目标族包括 webhook、Kafka、MQTT、MySQL、PostgreSQL、NATS、Redis、AMQP 和 Pulsar。本节详细介绍 webhook,其他遵循相同的两部模型,各有自己的变量。

29.1 配置 webhook 目标

export RUSTFS_NOTIFY_WEBHOOK_ENABLE=true
export RUSTFS_NOTIFY_WEBHOOK_ENDPOINT_PRIMARY="https://hooks.example.com/rustfs"
export RUSTFS_NOTIFY_WEBHOOK_AUTH_TOKEN_PRIMARY="<your-webhook-token>"
export RUSTFS_NOTIFY_WEBHOOK_QUEUE_DIR_PRIMARY="/var/lib/rustfs/notify-primary"
export RUSTFS_NOTIFY_WEBHOOK_QUEUE_LIMIT_PRIMARY="10000"
  • 后缀以小写设置目标名称。_PRIMARY 创建名为 primary 的目标。
  • 目标 ARN 格式为 arn:rustfs:sqs:<region>:<target>:webhook。本例为 arn:rustfs:sqs:us-east-1:primary:webhook。
  • 更改环境变量管理的目标后重启 RustFS。
  • 队列目录在端点宕机时缓冲事件;队列上限限制缓冲数量。
  • 可选客户端证书使用 RUSTFS_NOTIFY_WEBHOOK_CLIENT_CERT_<SUFFIX> 和 RUSTFS_NOTIFY_WEBHOOK_CLIENT_KEY_<SUFFIX>。(verify suffix pattern for endpoint and certificates)

29.2 将目标绑定到存储桶

保存为 notification.json:

{
  "QueueConfigurations": [
    {
      "Id": "uploads-dat-events",
      "QueueArn": "arn:rustfs:sqs:us-east-1:primary:webhook",
      "Events": ["s3:ObjectCreated:Put", "s3:ObjectRemoved:Delete"],
      "Filter": {
        "Key": {
          "FilterRules": [
            { "Name": "prefix", "Value": "uploads/" },
            { "Name": "suffix", "Value": ".dat" }
          ]
        }
      }
    }
  ]
}

用 S3 API 应用并读回:

aws --endpoint-url https://storage.example.com s3api put-bucket-notification-configuration \
  --bucket my-bucket --notification-configuration file://notification.json

aws --endpoint-url https://storage.example.com s3api get-bucket-notification-configuration \
  --bucket my-bucket

用 rc 执行相同操作:

rc bucket event add rustfs/my-bucket arn:rustfs:sqs:us-east-1:primary:webhook --event put,delete
rc --json bucket event list rustfs/my-bucket
rc bucket event remove rustfs/my-bucket arn:rustfs:sqs:us-east-1:primary:webhook

重要: PutBucketNotificationConfiguration 会替换该存储桶的整份通知配置。要改一条规则,先读当前配置、编辑,再把整份文档写回。写入 {} 会移除该桶上的全部通知。

过滤器和事件字段布局遵循 S3 通知格式。请确认你版本的确切字段。(verify)

29.3 测试链路

printf 'hello from RustFS\n' > hello.txt
aws --endpoint-url https://storage.example.com s3 cp hello.txt s3://my-bucket/uploads/hello.dat

接收方应收到 event 字段为 s3:ObjectCreated:Put 的 POST。删除该对象后,应收到 s3:ObjectRemoved:Delete。

29.4 投递语义与接收方设计

  • 至少一次投递。 可能出现重复。让消费端幂等,按存储桶、键和版本标识去重。
  • 跨对象不保证顺序。 不要假设事件按写入顺序到达。
  • 仅在工作持久化后才确认。 只有事件被安全存储或处理后才返回 2xx,否则事件会被重试。
  • 对接收方做认证。 校验 Authorization 头中的 bearer token。请确认你版本通知的头部格式。(verify)
  • 限制暴露面。 接收方放在内网或白名单后,并做限流。

29.5 事件通知故障排查

症状检查项
收不到事件目标已启用且 RustFS 已重启;ARN 完全匹配;桶配置存在(get-bucket-notification-configuration);事件类型及前缀/后缀与测试对象匹配。
事件延迟队列目录在增长、端点慢,或重试在退避。
故障后事件丢失达到队列上限。提高上限和磁盘空间并查看日志。
事件重复至少一次投递的预期行为,在消费端去重。
通知消失某次写入替换了整份配置,可能写成了 {} 或不完整文档。从版本控制副本恢复。

29.6 审计目标(独立特性)

审计目标记录整个 RustFS 的请求和 API 活动,用于安全监控与合规。事件通知按存储桶划分范围。两者区别:

方面审计目标事件通知
范围整个 RustFS 的请求与 API 活动各存储桶配置选择的事件
过滤无按目标的事件过滤事件类型、前缀、后缀
典型用途SIEM、合规、调查应用工作流与数据管道

审计 webhook 配置:

export RUSTFS_AUDIT_WEBHOOK_ENDPOINT_PRIMARY="https://audit.example.com/rustfs"
export RUSTFS_AUDIT_WEBHOOK_AUTH_TOKEN_PRIMARY="<your-webhook-token>"
export RUSTFS_AUDIT_WEBHOOK_QUEUE_DIR_PRIMARY="/var/lib/rustfs/audit-primary"
  • RustFS 把每条审计记录发送到每个已启用的审计目标。
  • 每个目标要么用环境变量、要么用持久化配置定义,不要两者并用。
  • 更改环境变量后重启 RustFS。
  • rc bucket event 命令只管理存储桶通知规则,不控制审计投递。
  • 测试时执行一次带认证的 S3 操作,确认记录到达审计接收方。
  • 审计投递也是至少一次。尽可能一次写入存储审计记录,并限制对审计库的访问。

29.7 事件通知配置(webhook / Kafka / MQTT 等)

RustFS 支持将存储桶事件发送到 webhook、Kafka、MQTT、MySQL、PostgreSQL、NATS、Redis、AMQP、Pulsar 等目标。

Webhook 目标配置:

export RUSTFS_NOTIFY_ENABLE="true"
export RUSTFS_NOTIFY_WEBHOOK_ENABLE_PRIMARY="on"
export RUSTFS_NOTIFY_WEBHOOK_ENDPOINT_PRIMARY="https://events.example.com/rustfs"
export RUSTFS_NOTIFY_WEBHOOK_AUTH_TOKEN_PRIMARY="<token>"
export RUSTFS_NOTIFY_WEBHOOK_QUEUE_DIR_PRIMARY="/var/lib/rustfs/notify-primary"
export RUSTFS_OUTBOUND_ALLOW_ORIGINS="https://events.example.com"

存储桶规则(notification.json):

{
  "QueueConfigurations": [
    {
      "Id": "primary-uploads",
      "QueueArn": "arn:rustfs:sqs:us-east-1:primary:webhook",
      "Events": ["s3:ObjectCreated:*", "s3:ObjectRemoved:*"],
      "Filter": {
        "Key": {
          "FilterRules": [
            { "Name": "prefix", "Value": "uploads/" },
            { "Name": "suffix", "Value": ".dat" }
          ]
        }
      }
    }
  ]
}
aws --endpoint-url http://localhost:9000 --region us-east-1 \
  s3api put-bucket-notification-configuration \
  --bucket my-bucket --notification-configuration file://notification.json

rc 管理规则:

rc bucket event add rustfs/my-bucket arn:rustfs:sqs:us-east-1:primary:webhook --event put,delete
rc bucket event list rustfs/my-bucket
rc bucket event remove rustfs/my-bucket arn:rustfs:sqs:us-east-1:primary:webhook

29.8 审计日志配置(SIEM 接入)

审计目标用于请求级安全/合规记录,发送到 SIEM、合规或调查系统,支持与事件通知相同的目标系列。

审计 Webhook 配置:

export RUSTFS_AUDIT_ENABLE="true"
export RUSTFS_AUDIT_WEBHOOK_ENABLE_PRIMARY="on"
export RUSTFS_AUDIT_WEBHOOK_ENDPOINT_PRIMARY="https://audit.example.com/rustfs"
export RUSTFS_AUDIT_WEBHOOK_AUTH_TOKEN_PRIMARY="<token>"
export RUSTFS_AUDIT_WEBHOOK_QUEUE_DIR_PRIMARY="/var/lib/rustfs/audit-primary"
export RUSTFS_OUTBOUND_ALLOW_ORIGINS="https://audit.example.com"

审计记录示例:

{
  "version": "1",
  "time": 1719331200000,
  "event": "s3:ObjectCreated:Put",
  "api": { "name": "PutObject", "bucket": "my-bucket", "object": "hello.txt", "status": "OK", "statusCode": 200 },
  "remotehost": "192.0.2.10",
  "requestID": "<request-id>",
  "userAgent": "aws-cli",
  "accessKey": "<your-access-key>"
}

30. 对象锁、保留与法律保留

对象锁为单个对象版本提供一次写入多次读取(WORM)保护。每次覆盖都会创建新版本,保留或法律保留作用于该版本,而非整个键。

30.1 保护类型

类型行为到期
保留,GOVERNANCE阻止删除和覆盖。拥有 bypass 权限的身份可覆盖它。(verify bypass header and policy action)retain-until 日期
保留,COMPLIANCE阻止包括 root 在内的任何人删除,直到 retain-until 日期。retain-until 日期
法律保留阻止删除,直到保留被置为 OFF。无

由模型推出的规则:

  • 对象版本上的显式保留设置覆盖存储桶默认值。
  • 可通过提交新的锁定请求延长保留。
  • 法律保留与保留期可以并存;两者都结束前删除始终被阻止。
  • 保留期过期后,只要没有法律保留,该版本即可删除。

30.2 启用对象锁

  • 控制台:Buckets → Create bucket 并启用 Object Lock。控制台也会启用 Versioning,因为对象锁需要它。
  • 可选启用 Retention,为新对象版本应用默认保留期。
  • 对象锁须在创建存储桶时选择。帮助输出中有 rc bucket create --with-lock 选项,但 rc 0.1.29 返回 "not implemented"。请在控制台创建对象锁定桶。
  • 不要对对象锁定桶暂停版本控制。

30.3 对对象应用保护

上传时设置保留:

rc object copy ./hello.txt rustfs/my-bucket/hello.txt \
  -H "x-amz-object-lock-mode:GOVERNANCE" \
  -H "x-amz-object-lock-retain-until-date:2027-01-01T00:00:00Z"

上传时设置法律保留:

rc object copy ./contract.pdf rustfs/my-bucket/legal/contract.pdf \
  -H "x-amz-object-lock-legal-hold:ON"

同样的请求头适用于任何 S3 客户端:x-amz-object-lock-mode、x-amz-object-lock-retain-until-date 和 x-amz-object-lock-legal-hold。

30.4 查看受保护的版本

rc bucket version list rustfs/my-bucket --json
rc object stat rustfs/my-bucket/hello.txt
rc object stat rustfs/my-bucket/hello.txt --version-id <VERSION_ID>

在控制台中打开对象,用 Versions 标签列出版本,用 Info 标签查看 Legal Hold 和 RetentionPolicy 字段。

30.5 CLI 的限制

在 rc 0.1.29 中,可以在上传时设置保留和法律保留;不能更改已有保留期,也不能在 ON/OFF 之间切换法律保留。这些操作请用控制台,或在你版本支持时使用 S3 API 的 put-object-retention 和 put-object-legal-hold。(verify)

30.6 依赖前先证明锁有效

  1. 上传一个带 GOVERNANCE 保留的测试对象。
  2. 用没有 bypass 权限的标准身份尝试删除该确切版本,请求必须以 AccessDenied 失败。
  3. 确认该版本仍在控制台和 rc object stat 中可见。
  4. 用 COMPLIANCE 保留和法律保留重复测试。
  5. 把结果记录到变更记录中。
aws --endpoint-url https://storage.example.com s3api delete-object \
  --bucket my-bucket --key hello.txt --version-id <VERSION_ID>
# 预期结果:AccessDenied

30.7 与其他特性的交互

  • 生命周期: 过期无法移除受保留或法律保护的版本。生命周期规则继续运行,但受保护版本保留。规划容量时要考虑这点。
  • 版本控制: 保持启用。对象锁定桶不适合暂停版本控制。
  • 复制: 复制不会把保留或法律保留设置带到目标端。请在目标端施加锁定,并确认其支持兼容的对象锁。
  • 分层: 在组合这两个特性前,确认锁定版本转层后的行为。(verify)

30.8 合规设计

RustFS 文档称其保留与不可变特性已由 Cohasset Associates 对照 SEC Rule 17a-4(f)、FINRA Rule 4511 和 CFTC Regulation 1.31 进行过评估。请将其视为厂商声明。索取评估报告,并与合规团队确认评估覆盖的确切配置:模式、保留期、存储设计和审计追踪。


30.9 对象保留(保留期与法律保留设置)

对象存储保留规则确保对象在一段时间内受 WORM 保护。保留期可显式设置或通过存储桶默认设置。

启用对象锁定(需在创建桶时):

# 创建带对象锁定的桶
aws --endpoint-url http://localhost:9000 s3api create-bucket \
  --bucket my-bucket --object-lock-enabled-for-bucket true

设置对象保留(治理模式):

aws --endpoint-url http://localhost:9000 s3api put-object-retention \
  --bucket my-bucket --key hello.txt \
  --retention '{"Mode":"GOVERNANCE","RetainUntilDate":"2027-01-01T00:00:00Z"}'

设置法定保留:

aws --endpoint-url http://localhost:9000 s3api put-object-legal-hold \
  --bucket my-bucket --key hello.txt --legal-hold Status=ON

30.10 两种保留模式(GOVERNANCE / COMPLIANCE 详解)

模式说明
治理模式(Governance)防止标准用户删除;具有 s3:BypassGovernanceRetention 权限的用户可删除
合规模式(Compliance)限制性更强,保留期内无法撤销,root 也无法删除

30.11 法定保留(Legal Hold)

无限期 WORM 保护,无到期日期,只能由授权用户删除。

30.12 合规认证

RustFS 数据不变性达到或超过 Cohasset Associates 认证标准(SEC 17a-4(f)、FINRA 4511、CFTC 1.31)。


31. 加密

31.1 传输中:TLS 与双向 TLS

通过指向包含 rustfs_cert.pem 和 rustfs_key.pem 的目录来启用 TLS:

export RUSTFS_TLS_PATH="/opt/tls"
export RUSTFS_TLS_RELOAD_ENABLE=true

在 Docker 中挂载目录并设置变量:

docker run -d --name rustfs \
  -p 9000:9000 -p 9001:9001 \
  -v "$(pwd)/rustfs/data:/data" \
  -v /opt/tls:/opt/tls:ro \
  -e RUSTFS_TLS_PATH=/opt/tls \
  -e RUSTFS_ACCESS_KEY="<access-key>" \
  -e RUSTFS_SECRET_KEY="<secret-key>" \
  rustfs/rustfs:<pinned-version>
变量默认用途
RUSTFS_TLS_PATH未设置证书与密钥目录,设置即启用 TLS。
RUSTFS_TLS_RELOAD_ENABLEfalse监视目录并热重载证书,无需重启。
RUSTFS_SERVER_MTLS_ENABLEfalse在服务端监听上要求客户端证书(双向 TLS)。
RUSTFS_TRUST_SYSTEM_CAfalse出站连接信任操作系统 CA 存储,例如连接使用私有 CA 的 IdP 或层。
RUSTFS_TLS_KEYLOGfalse写出 TLS 会话密钥用于调试,生产环境绝不可启用。

在 RustFS 前放置反向代理(9.3 节)仍是有效模式。

31.2 静态数据:服务端加密

RustFS 在磁盘上加密对象,每个对象得到唯一数据密钥。文档记载的密码算法为 AES-256-GCM 和 ChaCha20-Poly1305。密钥保护模式取决于你如何配置存储桶或请求。

模式谁持有密钥客户端如何请求说明
SSE-S3RustFS,通过 KES 和 KMS头部 x-amz-server-side-encryption: AES256需要已配置 KMS。KMS 不可用时写入失败。
SSE-KMSKMS,使用显式密钥 ID请求上的 KMS 密钥 ID,或存储桶默认值需要显式控制 KMS 密钥时使用。
SSE-C客户端,每个请求一把 256 位密钥三个 x-amz-server-side-encryption-customer-* 头RustFS 不存储密钥。密钥丢失则数据不可读。

31.3 KMS 与 KES

SSE-S3 需要 KES(Key Encryption Service)。它位于 RustFS 集群与外部 KMS 之间,按需生成密钥并执行加密操作。文档记载的集成包括 HashiCorp Vault 和 Thales CipherTrust(原 Gemalto KeySecure)。

export RUSTFS_KMS_ENABLE=true
export RUSTFS_KMS_BACKEND=vault-transit          # local | vault | vault-kv2 | vault-transit
export RUSTFS_KMS_DEFAULT_KEY_ID="rustfs-default"
  • local 后端:RUSTFS_KMS_LOCAL_MASTER_KEY 保护本地密钥文件。
  • 生产环境 RUSTFS_KMS_ALLOW_INSECURE_DEV_DEFAULTS 必须保持 false。
  • 启用 SSE-S3 前先配置 KMS、创建默认密钥并确认密钥可用。即使 KMS 宕机,RustFS 也接受 SSE-S3 桶默认设置,但之后的加密写入会失败。
  • KMS 根密钥和主密钥与根凭据同级别备份管控。丢失它们会使 SSE-S3 数据不可读,请测试恢复。

31.4 存储桶默认值与单对象加密

rc bucket encryption set rustfs/my-bucket --mode sse-s3
rc bucket encryption info rustfs/my-bucket
rc bucket encryption clear rustfs/my-bucket

加密单个对象(使用桶默认值):

rc object copy ./hello.txt rustfs/my-bucket/hello.txt
rc object show rustfs/my-bucket/hello.txt

为目录指定目标的显式模式加密(文档示例,verify flag meaning):

rc object copy ./reports/ rustfs/my-bucket/reports/ --recursive --enc-s3 rustfs/my-bucket/reports/

规则:

  • 请求未指定模式时,RustFS 从存储桶配置解析模式。
  • 更改存储桶的 SSE-S3 或 SSE-KMS 默认值不会改变已存储的对象。
  • SSE-C 由每个请求上的客户密钥头部选择,并对该请求优先。

31.5 SSE-C 工作流

生成密钥及其 MD5 摘要:

export SSE_C_KEY_B64="$(openssl rand -base64 32)"
export SSE_C_KEY_MD5="$(printf '%s' "$SSE_C_KEY_B64" | base64 -d | openssl dgst -md5 -binary | base64)"

上传。rc 0.1.29 没有专用 SSE-C 选项,因此把三个头部作为签名自定义头部发送:

rc object copy ./hello.txt rustfs/my-bucket/hello.txt \
  -H "x-amz-server-side-encryption-customer-algorithm:AES256" \
  -H "x-amz-server-side-encryption-customer-key:$SSE_C_KEY_B64" \
  -H "x-amz-server-side-encryption-customer-key-md5:$SSE_C_KEY_MD5"

读取时在 rc object show 上带同样三个头部,然后用(例如 cmp)比对下载字节与源文件。

密钥保管: 把密钥存入有具名所有者的密钥管理器。密钥丢失则对象无法恢复,管理员也不例外。

31.6 模式选择

  • SSE-S3: 由 RustFS 管理密钥且有 KMS 可用时使用,运维最简单。
  • SSE-KMS: 审计需要显式 KMS 密钥标识和密钥策略时使用。
  • SSE-C: 仅当应用自己负责密钥管理,并接受密钥丢失即数据丢失时使用。

静态加密不能替代访问控制,请与传输中的 TLS 和最小权限策略结合。


31.7 加密体系

  • 网络加密:TLS 1.2+,集群内外加密,CPU 指令级优化;
  • 对象加密(静态):服务器端加密(SSE-S3、SSE-KMS)+ 客户端加密(SSE-C);
  • 加密算法:AES-256-GCM、ChaCha20-Poly1305、AES-CBC(AEAD,SIMD 加速);
  • 兼容:与 AWS S3 加密语义(SSE-S3)完全兼容。

31.8 支持的 KMS(提供方)

AWS KMS、HashiCorp Vault、Google Secret Manager、Azure Key Vault、Thales CipherTrust、Fortanix;内置无状态分布式密钥服务 KES。

31.9 SSE-S3(请求头与默认加密)

rc bucket encryption set rustfs/my-bucket --mode sse-s3
rc bucket encryption info rustfs/my-bucket
rc object copy /path/to/hello.txt rustfs/my-bucket/hello.txt
rc object show rustfs/my-bucket/hello.txt

# 清除默认
rc bucket encryption clear rustfs/my-bucket

S3 请求头:x-amz-server-side-encryption: AES256

31.10 SSE-KMS 配置

本地后端:

sudo install -d -m 0700 -o rustfs -g rustfs /var/lib/rustfs/kms

/etc/default/rustfs:

RUSTFS_KMS_ENABLE=true
RUSTFS_KMS_BACKEND=local
RUSTFS_KMS_KEY_DIR=/var/lib/rustfs/kms
RUSTFS_KMS_LOCAL_MASTER_KEY=<your-kms-master-key>

创建默认密钥:

rc admin kms status rustfs
rc admin kms key create rustfs --name rustfs-default-key
rc admin kms key status rustfs rustfs-default-key

设置默认密钥并重启后:

RUSTFS_KMS_DEFAULT_KEY_ID=rustfs-default-key

Vault KV2 后端:

RUSTFS_KMS_ENABLE=true
RUSTFS_KMS_BACKEND=vault-kv2
RUSTFS_KMS_VAULT_ADDRESS=https://vault.example.com:8200
RUSTFS_KMS_VAULT_TOKEN=<your-vault-token>
RUSTFS_KMS_VAULT_KV_MOUNT=secret
RUSTFS_KMS_VAULT_KEY_PREFIX=rustfs/kms/keys

Vault Transit 后端:

RUSTFS_KMS_ENABLE=true
RUSTFS_KMS_BACKEND=vault-transit
RUSTFS_KMS_VAULT_ADDRESS=https://vault.example.com:8200
RUSTFS_KMS_VAULT_TOKEN=<your-vault-token>
RUSTFS_KMS_VAULT_MOUNT_PATH=transit

密钥丢失会导致加密对象无法读取,务必备份主密钥。轮换主密钥不会重写对象数据(每个对象保留其封装的 DEK)。


32. 复制与迁移

三种不同需求常被混淆。选择与需求匹配的工具。

需求方式复制内容
从其他 S3 系统一次性迁移客户端复制:rc mirror、rclone 或 AWS CLI sync仅对象。不含策略、生命周期、通知、CORS、标签或加密默认值。
持续复制到第二站点计划的 rc mirror 或 rclone copy,或存储桶复制对象。存储桶复制是持续的。
多集群站点复制通过 rc 对等别名的站点复制还包括配置与身份。请确认你版本的功能集。

分层不是复制。 已转层对象移动到层,本地副本就没了。如果你需要一份在本地仍可用的第二副本,请用复制或 mirror。

32.1 从其他 S3 系统迁移

  1. 盘点源端。 列出存储桶、对象数、大小、版本、标签、策略、生命周期规则、CORS、通知配置和加密设置。

  2. 创建目标存储桶。 尽量使用相同名称。需要时在创建时启用版本控制和对象锁。

  3. 配置别名:

    rc alias set src https://old-s3.example.com <src-access-key> <src-secret-key>
    rc alias set rustfs https://storage.example.com <rustfs-access-key> <rustfs-secret-key>
    
  4. 复制对象:

    rc mirror src/app-data rustfs/app-data
    

    或用 rclone:

    rclone copy src:app-data rustfs:app-data --checksum --transfers 16 --s3-chunk-size 64M --progress
    

    请确认你版本中 rc mirror 保留元数据和试运行(dry run)的选项。(verify)

  5. 验证。 比较对象数和总大小。先做单向检查,再抽样校验和:

    rclone check src:app-data rustfs:app-data --one-way
    
  6. 重建配置。 策略、用户与服务账户、生命周期规则、CORS、标签、通知配置和加密默认值必须重新创建。镜像只复制对象。

  7. 增量同步与切换。 把源端设为只读或暂停写入,执行最终镜像,验证,切换应用端点,并观察错误率。

  8. 保留回滚路径。 在约定期内保持源端完好且只读,并文档化切回步骤。

MinIO 说明。 MinIO 文档称其服务端存储桶复制适用于 MinIO 部署之间,其他 S3 兼容目标需要 mc mirror 等客户端工具。MinIO 到 RustFS 的迁移请使用客户端复制,除非你确认存在受支持的 RustFS 路径。rc 文档包含面向 mc 用户的迁移指南。(verify)

32.2 用 rc 做存储桶复制

rc CLI 通过导出和导入复制配置来管理存储桶复制,需要远程别名和远程存储桶:

rc alias set dr https://dr.example.com <dr-access-key> <dr-secret-key>
rc replicate export rustfs/my-bucket > replication.json
rc replicate import rustfs/my-bucket replication.json

rc 示例用 --remote-bucket dr/my-bucket-replica 指定目标。请用 rc replicate --help 确认选项语法。(verify)

  • 若远程端点使用私有 CA,上传 PEM CA 包使 RustFS 信任它。若 CA 已安装在操作系统存储中,使用 RUSTFS_TRUST_SYSTEM_CA。
  • 存在用于重新同步问题对象的手动修复命令,请用 rc --help 确认语法。(verify)

需要规划的限制:

  • 保留和法律保留设置不会被转移,请在目标端施加。
  • 若源端使用对象锁,目标端必须支持兼容的对象锁。
  • 依赖前请确认加密对象如何复制、密钥如何在目标端解析。(verify)

32.3 跨集群站点复制

rc 文档描述了跨集群站点复制,对站点以别名形式给出。当备用集群需要与数据一同匹配配置时,用它做灾难恢复。启用前请确认你版本的这些要点:哪些设置会复制(身份、策略、存储桶、配置)、故障切换流程,以及网络分区期间的写入行为。(verify)

32.4 为 DR 需求选择正确工具

需求推荐方式
异地一份可读的第二副本存储桶复制,或计划 mirror 到第二集群
便宜的冷存储,数据在变旧前留在本地生命周期层(第 17 章)
防误删版本控制 + 受保护桶与副本上的对象锁
防管理员被攻陷独立的副本凭据、副本上的 Deny 策略、对象锁

RustFS 支持存储桶级主动-主动 / 主动-被动复制。

32.5 配置复制(AWS CLI 跨集群实操)

# 源桶启用版本控制
aws --endpoint-url http://src:9000 s3api put-bucket-versioning \
  --bucket my-bucket --versioning-configuration Status=Enabled

# 目标桶同样启用版本控制
aws --endpoint-url http://dst:9000 s3api put-bucket-versioning \
  --bucket my-bucket --versioning-configuration Status=Enabled

# 配置复制规则
aws --endpoint-url http://src:9000 s3api put-bucket-replication \
  --bucket my-bucket \
  --replication-configuration '{
    "Role": "arn:aws:iam::123456789012:role/replication-role",
    "Rules": [{
      "ID": "replicate-all",
      "Status": "Enabled",
      "Priority": 1,
      "Filter": {},
      "Destination": {
        "Bucket": "arn:aws:s3:::my-bucket",
        "StorageClass": "STANDARD"
      }
    }]
  }'

32.6 核心特性

  • 复制加密/未加密对象及其元数据、对象版本、对象标签、对象锁保留信息;
  • 源/目标存储桶同名能力;
  • 自动对象锁定/保留复制;
  • 近乎同步复制(数据中心内严格一致,跨中心最终一致);
  • 复制失败通知(可订阅事件)。

32.7 设计考虑

  • 基础设施:建议两端使用相同硬件;
  • 带宽:由数据变化率决定;
  • 延迟:建议 RTT ≤ 20ms、丢包率 ≤ 0.01%;
  • 架构:目前建议跨两个数据中心复制。

32.8 注意事项

  • 复制要求源/目标都启用版本控制;
  • 目标故障时源缓存变更,恢复后同步;
  • 两端的对象锁定配置需一致,否则可能复制失败。

33. WebDAV 网关参考

本节扩展 41.3 节。网关通过 HTTP 或 HTTPS 把存储桶和对象暴露给 WebDAV 客户端。

33.1 启用网关

标准 RustFS 二进制包含 WebDAV 支持,但网关默认禁用。

变量用途
RUSTFS_WEBDAV_ENABLE开启网关
RUSTFS_WEBDAV_ADDRESSWebDAV 监听的绑定地址和端口
RUSTFS_WEBDAV_TLS_ENABLED在 WebDAV 监听上启用 TLS
RUSTFS_WEBDAV_CERTS_DIRRustFS TLS 运行时使用的证书目录
export RUSTFS_WEBDAV_ENABLE=true
export RUSTFS_WEBDAV_ADDRESS="0.0.0.0:8080"
export RUSTFS_WEBDAV_TLS_ENABLED=true
export RUSTFS_WEBDAV_CERTS_DIR="/opt/tls"
rustfs /data/rustfs
  • 启用 TLS 但未设置 RUSTFS_WEBDAV_CERTS_DIR 或目录不存在时,WebDAV 初始化失败。
  • 使用 --no-default-features 的自定义构建必须显式启用 WebDAV 编译期特性,特性名请查看项目构建配置。(verify)

33.2 路径映射

存储桶是顶层文件夹,桶内文件夹成为对象键前缀:

WebDAV 路径RustFS 资源
/<bucket>该存储桶
/<bucket>/<folder>/键前缀 <folder>/
/<bucket>/<folder>/<file>键为 <folder>/<file> 的对象

映射表请查看你版本的 WebDAV 文档,包括根路径是否列举存储桶。(verify)

33.3 认证与授权

  • WebDAV 使用 HTTP Basic 认证:用户名是 RustFS 访问密钥,密码是秘密密钥。
  • RustFS 对照 IAM 校验凭据,然后把用户的 S3 策略应用于每个操作。
  • 为 WebDAV 用户创建专用服务账户,不要使用 root。
  • 授权失败时源文件保持不变,MOVE 操作有此文档记载。

33.4 支持的操作

WebDAV 方法用途说明
PROPFIND浏览文件夹、读属性用 Depth: 1 避免递归列举
MKCOL创建文件夹映射为键前缀
PUT上传文件大文件优先用 SDK 或 rclone
GET下载文件
DELETE删除文件或文件夹适用版本控制规则
MOVE在同一端点内重命名或移动目标必须在同一端点
COPY在同一端点内复制请确认你版本是否支持。(verify)

用 curl 测试。明文 HTTP 上的 Basic 认证会暴露凭据,可信网络之外请使用 TLS:

export AK="<access-key>"; export SK="<secret-key>"
curl -u "$AK:$SK" -X PROPFIND -H "Depth: 1" https://dav.example.com:8080/app-data/
curl -u "$AK:$SK" -T ./report.pdf https://dav.example.com:8080/app-data/reports/report.pdf
curl -u "$AK:$SK" -X MOVE \
  -H "Destination: https://dav.example.com:8080/app-data/archive/report.pdf" \
  https://dav.example.com:8080/app-data/reports/report.pdf
curl -u "$AK:$SK" -X DELETE https://dav.example.com:8080/app-data/archive/report.pdf

33.5 反向代理

WebDAV 优先使用专用主机名(如 dav.example.com),客户端无需路径改写。确保代理放行 WebDAV 方法(PROPFIND、MKCOL、MOVE、COPY、PUT、DELETE、OPTIONS)且不缓冲上传:

server {
    listen 443 ssl;
    server_name dav.example.com;
    # ssl_certificate 与 ssl_certificate_key 同 5.3 节

    client_max_body_size 0;
    proxy_request_buffering off;

    location / {
        proxy_pass https://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

若网关在代理之后监听明文 HTTP,proxy_pass 改用 http://127.0.0.1:8080。请确认与你的 TLS 设置匹配的协议方案。(verify)

33.6 客户端行为与限制

  • 许多客户端缓冲整个文件、不支持断点续传,并为锁和属性发额外请求。请测试你计划支持的每个客户端。
  • 需要 WebDAV 文件锁(LOCK 和 UNLOCK)的客户端可能无法工作,请验证你版本的支持。(verify)
  • Office 应用通过临时文件保存。添加生命周期规则清理游离的临时对象。
  • 大传输请用 rclone 或 SDK。

33.7 安全检查清单

  • 所有生产 WebDAV 监听使用 TLS。
  • 尽可能把监听限制在 VPN 或内网。
  • 使用最小权限服务账户并轮换其密钥(11.5 节)。

34. Kubernetes Operator

34.1 组件

  • RustFS operator: 管理 Tenant 自定义资源的控制器。
  • Tenant: Kubernetes 内的一个 RustFS 集群,定义池、环境、凭据、调度和 TLS 设置。
  • Helm chart: 安装 Operator 和 RustFS 资源,Chart 位于仓库的 Helm 目录。
  • 示例: 仓库包含简单 Tenant 清单和多节点示例。应用到生产前请阅读这些示例的行内注释。

34.2 Operator 自动设置的变量

Operator 自动设置这些环境变量:

变量值
RUSTFS_VOLUMES来自所有池的卷,空格分隔
RUSTFS_ADDRESS0.0.0.0:9000
RUSTFS_CONSOLE_ENABLEtrue

34.3 凭据

优先级:Secret 凭据 > spec.env > RustFS 默认值。

推荐:把根凭据放入 Kubernetes Secret,并在 Tenant 中引用该 Secret。请在你 Operator 版本的 Tenant schema 中确认字段名。(verify)

kubectl -n rustfs create secret generic rustfs-root \
  --from-literal=RUSTFS_ACCESS_KEY='<access-key>' \
  --from-literal=RUSTFS_SECRET_KEY="$(openssl rand -base64 36)"

避免把凭据直接写进 spec.env,清单常被提交到版本控制。或者,spec.env 接受 RUSTFS_ACCESS_KEY 和 RUSTFS_SECRET_KEY 条目,请在示例清单中确认条目格式。(verify)

34.4 池

  • 一个 Tenant 可以有多个池,每个池有自己的卷布局。扩容即添加池(第 19 章)。
  • 池级优先级类覆盖 Tenant 级优先级类;池未设置时用 Tenant 的值。
  • 调度字段(节点选择、亲和、容忍、优先级)在简单 Tenant 示例中逐字段记载。(verify field names)

34.5 重要的设计约束

  • RustFS 没有存储类感知。 不按磁盘速度放置数据。
  • 性能等于集群中最慢的存储类。 在一个 Tenant 中混用 NVMe 和 HDD 池,所有数据都将是 HDD 性能。
  • 不同性能层使用独立 Tenant。 用生命周期层把冷数据移出热 Tenant(第 17 章)。
  • 添加池前查阅 Operator 文档中有效与无效的多池布局。(verify)

34.6 生命周期操作

  • Tenant 删除通过 finalizer 进行。除非厂商指示,不要手工移除 finalizer。
  • 池的增删和扩缩是 Tenant 生命周期操作,请先在非生产命名空间演练。
  • 状态字段可能滞后于现实。变更看似卡住时,除状态外还要检查 pod 和事件。

34.7 Kubernetes 生产检查清单

  • 与所需性能和可靠性匹配的 StorageClass。
  • 反亲和使 pod 分散到不同节点和故障域。
  • 基于基准测试设定资源 requests 和 limits(第 38 章)。
  • 为 S3 端点(9000)和控制台(9001)提供 Ingress 或 LoadBalancer,两者都启用 TLS。
  • 集群外的对象级备份(第 26 章)。VolumeSnapshot 不能替代对象级备份。
  • 遥测发送到集群内 OpenTelemetry Collector(第 36 章)。

第九部分 — 配置与性能


35. 配置参考

RustFS 从环境变量和命令行选项读取配置;两者同时设置时以命令行选项为准。布尔变量接受 true 或 false。

35.1 核心服务

变量默认说明
RUSTFS_VOLUMES必填卷或端点,空格分隔。支持省略号展开,例如 /data/rustfs{0...3} 或 http://node{1...4}:9000/data/rustfs{0...3}。
RUSTFS_ADDRESS:9000S3 API 监听地址,同时承载内部节点 RPC,节点间必须可达。
RUSTFS_CONSOLE_ENABLEtrue在独立监听上启用内置控制台。
--console-address(选项):9001控制台监听地址。
RUSTFS_ACCESS_KEYrustfsadmin根访问密钥,务必先改。
RUSTFS_SECRET_KEY由你设置根秘密密钥,使用长随机值。此处未确认文档记载的默认值。(verify)

多节点集群示例(每个节点以相同卷列表运行):

docker run -d --name rustfs -p 9000:9000 -p 9001:9001 \
  -e RUSTFS_ACCESS_KEY="<access-key>" \
  -e RUSTFS_SECRET_KEY="<secret-key>" \
  -e RUSTFS_ADDRESS=":9000" \
  -e RUSTFS_CONSOLE_ENABLE=true \
  -e RUSTFS_VOLUMES="http://node{1...4}:9000/data/rustfs{0...3}" \
  rustfs/rustfs:<pinned-version>

镜像同时发布在 quay.io/rustfs/rustfs。rc 客户端镜像为 rustfs/rc。

35.2 存储类与校验位

变量默认说明
RUSTFS_STORAGE_CLASS_STANDARDautoSTANDARD 类的校验位,EC:n 形式。
RUSTFS_STORAGE_CLASS_RRSEC:1REDUCED_REDUNDANCY 类的校验位,EC:n 形式。

35.3 扫描器与修复

变量默认说明
RUSTFS_SCANNER_SPEEDdefault预设:fastest、fast、default、slow 或 slowest。
RUSTFS_SCANNER_DELAY预设覆盖休眠倍数。
RUSTFS_SCANNER_MAX_WAIT_SECS预设覆盖最大休眠秒数。
RUSTFS_SCANNER_ALERT_EXCESS_VERSIONS100触发扫描器告警的版本数。
RUSTFS_SCANNER_ALERT_EXCESS_FOLDERS65538触发扫描器告警的直接子文件夹数。
RUSTFS_HEAL_AUTO_HEAL_ENABLEtrue自动后台修复降级对象。

35.4 TLS

变量默认说明
RUSTFS_TLS_PATH未设置证书目录,设置即启用 TLS。
RUSTFS_TLS_RELOAD_ENABLEfalse证书热重载。
RUSTFS_SERVER_MTLS_ENABLEfalse要求客户端证书。
RUSTFS_TRUST_SYSTEM_CAfalse出站连接信任操作系统 CA 存储。
RUSTFS_TLS_KEYLOGfalse仅调试,绝不用生产。

35.5 KMS

变量默认说明
RUSTFS_KMS_ENABLEfalse启用 KMS 支持的服务端加密。
RUSTFS_KMS_BACKENDlocallocal、vault(KV2 + Transit)、vault-kv2 或 vault-transit。
RUSTFS_KMS_LOCAL_MASTER_KEY未设置保护本地 KMS 密钥文件。
RUSTFS_KMS_DEFAULT_KEY_ID未设置加密的默认密钥 ID。
RUSTFS_KMS_ALLOW_INSECURE_DEV_DEFAULTSfalse仅开发用,绝不用生产。

35.6 身份与浏览器

变量说明
RUSTFS_BROWSER_REDIRECT_URL控制台公网源。
RUSTFS_IDENTITY_OPENID_CONFIG_URLOIDC 签发者。命名提供者加后缀 _<provider>。
RUSTFS_IDENTITY_OPENID_CLIENT_IDOIDC 客户端 ID。
RUSTFS_IDENTITY_OPENID_SCOPES逗号分隔的作用域。
RUSTFS_IDENTITY_OPENID_REDIRECT_URI回调 URL。
RUSTFS_IDENTITY_OPENID_USERNAME_CLAIM显示名声明。

详情见 10.6 节。

35.7 可观测性

变量默认说明
RUSTFS_OBS_ENDPOINT空链路、指标和日志的 OTLP/HTTP 根 URL。
RUSTFS_OBS_METRIC_ENDPOINT未设置仅指标的端点覆盖。
RUSTFS_OBS_METRICS_EXPORT_ENABLEDtrue导出指标。
RUSTFS_OBS_METER_INTERVAL未设置指标导出间隔(秒)。
RUSTFS_OBS_ENVIRONMENT未设置如 production、staging、test 的标签。
RUSTFS_OBS_LOG_DIRECTORY未设置日志文件目录。
RUSTFS_OBS_LOG_FILENAMErustfs.log日志目录内的日志文件名。
RUSTFS_METRICS_<SCOPE>_INTERVAL_SEC按范围采集间隔。范围:DEFAULT、SYSTEM、CLUSTER、BUCKET、NODE、RESOURCE、AUDIT、NOTIFICATION、BUCKET_REPLICATION_BANDWIDTH。例:RUSTFS_METRICS_CLUSTER_INTERVAL_SEC=60。

35.8 通知、审计与 WebDAV

领域变量
Webhook 通知RUSTFS_NOTIFY_WEBHOOK_ENABLE、..._ENDPOINT_<S>、..._AUTH_TOKEN_<S>、..._QUEUE_LIMIT_<S>、..._QUEUE_DIR_<S>、..._CLIENT_CERT_<S>、..._CLIENT_KEY_<S>(<S> 为目标后缀)。见第 29 章。
审计 webhookRUSTFS_AUDIT_WEBHOOK_ENDPOINT_<S>、..._AUTH_TOKEN_<S>、..._QUEUE_DIR_<S>。见 29.6 节。
WebDAVRUSTFS_WEBDAV_ENABLE、RUSTFS_WEBDAV_ADDRESS、RUSTFS_WEBDAV_TLS_ENABLED、RUSTFS_WEBDAV_CERTS_DIR。见第 33 章。

35.9 示例环境文件

保存为 /etc/rustfs/rustfs.env,文件权限设为 0600。不要把秘密放在该文件里,或谨慎保护它:

RUSTFS_VOLUMES=/data/rustfs{0...3}
RUSTFS_ADDRESS=:9000
RUSTFS_CONSOLE_ENABLE=true
RUSTFS_TLS_PATH=/opt/tls
RUSTFS_OBS_ENDPOINT=http://otel-collector:4318
RUSTFS_OBS_ENVIRONMENT=production
RUSTFS_OBS_LOG_DIRECTORY=/var/log/rustfs
RUSTFS_SCANNER_SPEED=default

官方 systemd unit 默认使用服务用户 rustfs-user,27.8 节模板使用 rustfs。两者皆可,只要目录属主与服务用户一致。


36. 可观测性技术栈

36.1 架构

RustFS 在 9000 或 9001 端口上不暴露原生 Prometheus /metrics 端点。它通过 OTLP(OpenTelemetry Protocol)推送指标、链路和日志,由 OpenTelemetry Collector 接收并再暴露给 Prometheus。

RustFS 节点 ──OTLP──► OpenTelemetry Collector ──► Prometheus ──► Grafana
                              ├──► Loki   (日志)
                              └──► Tempo 或 Jaeger(链路)

36.2 将每个 RustFS 节点指向采集器

export RUSTFS_OBS_ENDPOINT="http://otel-collector:4318"
export RUSTFS_OBS_ENVIRONMENT="production"
export RUSTFS_OBS_METRICS_EXPORT_ENABLED=true
export RUSTFS_OBS_METER_INTERVAL=60
export RUSTFS_OBS_LOG_DIRECTORY="/var/log/rustfs"
export RUSTFS_OBS_LOG_FILENAME="rustfs.log"
export RUSTFS_METRICS_CLUSTER_INTERVAL_SEC=60

仅当指标需要与链路、日志发往不同端点时才使用 RUSTFS_OBS_METRIC_ENDPOINT。

36.3 采集器配置

本例遵循项目参考技术栈的结构。请对照你版本仓库中的采集器文件,因为 Collector 版本之间导出器名称会变。(verify)

receivers:
  otlp:
    protocols:
      grpc:
        endpoint: 0.0.0.0:4317
      http:
        endpoint: 0.0.0.0:4318

exporters:
  prometheus:
    endpoint: 0.0.0.0:8889
  otlp/tempo:
    endpoint: tempo:4317
    tls:
      insecure: true

service:
  pipelines:
    metrics:
      receivers: [otlp]
      exporters: [prometheus]
    traces:
      receivers: [otlp]
      exporters: [otlp/tempo]
    # 日志:用你的 Collector 构建支持的导出器路由到 Loki。

36.4 Prometheus 抓取配置

Prometheus 抓取采集器,而不是 RustFS:

scrape_configs:
  - job_name: "rustfs-app-metrics"
    static_configs:
      - targets: ["otel-collector:8889"]
  - job_name: "otel-collector-self"
    static_configs:
      - targets: ["otel-collector:8888"]

36.5 验证管道

rustfs_* 序列缺失时按此清单排查:

  1. 每个节点都设置了 RUSTFS_OBS_ENDPOINT。

  2. 每个节点都能在 4318(HTTP)或 4317(gRPC)端口访问采集器。

  3. 采集器的 Prometheus 导出器有响应:

    curl -s http://otel-collector:8889/metrics | grep '^rustfs_' | head
    
  4. Prometheus 正在抓取 8889 端口且目标显示为 up。

36.6 告警

既要对 RustFS 本身告警,也要对管道告警,因为静默的管道看起来像健康集群:

  • 数据缺失: rustfs job 没了,或某节点在设定时段内没有 rustfs_* 序列。
  • 采集器健康: 8888 端口的采集器自身指标显示导出失败或数据丢弃。
  • 容量、错误与延迟: 按你版本导出的指标名构建告警。用名称匹配器如 {__name__=~"rustfs_.*"} 在 Prometheus 中列出。项目会发布你版本的指标参考。(verify names)

应覆盖的告警类别见 25.2 节。

36.7 日志

  • 设置 RUSTFS_OBS_LOG_DIRECTORY 和 RUSTFS_OBS_LOG_FILENAME 写日志文件。
  • Docker 中把 /logs 目录挂载到主机,见 7.1 节。
  • systemd 下用 journalctl -u rustfs 查看。
  • 把日志发往 Loki、Elasticsearch 或你的 SIEM,并轮转本地文件避免写满磁盘。

36.8 健康检查

从负载均衡器或编排器探测 S3 端点和控制台。健康检查路径未出现在本版审阅的文档摘录中,请确认你版本的路径。(verify)


37. 扫描器、修复与存储类

37.1 扫描器

扫描器在后台运行,读取对象、检查其健康、驱动修复并触发告警。

  • 速度预设在后台 I/O 与完整扫描耗时之间权衡:fastest、fast、default、slow、slowest。
  • 高峰时段 I/O 紧张时设置 RUSTFS_SCANNER_SPEED=slow。请确认你版本中该设置能否不重启更改。(verify)
  • 告警阈值是预警。过多版本(默认每对象 100 个)通常意味着覆盖繁重的工作负载,需要非当前版本过期(16.3 节);过多文件夹(默认 65538 个直接子文件夹)通常意味着键设计需要扁平化或分片。

37.2 修复(Healing)

  • 自动修复默认启用(RUSTFS_HEAL_AUTO_HEAL_ENABLE=true)。
  • 更换驱动器后,修复会重建其数据。监控进度直到完成,并留意客户端负载,因为修复竞争 I/O。
  • rc 提供手动存储桶修复。请用 rc --help 确认命令。(verify)

37.3 存储类与校验位

  • STANDARD 默认 auto 校验位;REDUCED_REDUNDANCY(RRS) 默认 EC:1。
  • EC:n 表示 n 个校验分片。校验越多容错越强、可用容量越少;校验越少容量越多、容错越弱。
  • 生产数据用 STANDARD。RRS 仅用于可再生的数据,如缩略图或缓存。
  • 客户端可用 x-amz-storage-class 头为每个对象选择存储类。请确认你版本的支持。(verify)

容错能力取决于布局和仲裁规则。能承受的故障盘数不总是等于校验位数。在确定设计前针对你的拓扑确认。(verify)


38. 性能调优与基准测试

38.1 先剖析工作负载

调优前先测量:

  • 对象大小分布。小对象压力在元数据,大对象压力在吞吐。
  • 读写比例、峰值请求率和并发。
  • LIST 模式。大而未分页的列举开销高。
  • 你需要达成的延迟目标,以 p95 或 p99 表述。

38.2 硬件与网络

  • 元数据密集和小对象工作负载用 NVMe 或 SSD;大对象容量型工作负载用 HDD。
  • 操作系统与数据盘分开;如 Docker 和 Linux 指南建议,每个数据目录专用于 RustFS。
  • 节点与客户端之间使用 10 GbE 或更高速网络。仅当路径上所有设备都支持时才启用巨帧。
  • 同一纠删集内保持磁盘容量与类型一致。

38.3 客户端调优

  • AWS CLI: 大文件调高 multipart_threshold、multipart_chunksize 和 max_concurrent_requests。
  • rclone: 调整 --transfers、--checkers、--s3-chunk-size 和 --s3-upload-concurrency。
  • SDK: 复用客户端对象、保持 HTTP 连接存活、并行化独立请求。
  • 列举: 使用前缀和分页;同一列举重复时缓存结果。

38.4 代理调优

遵循 9.3 节:上传禁用请求缓冲、大传输提高超时、S3 端点去掉请求体大小限制。

38.5 后台负载

扫描器和修复消耗 I/O。高峰期把扫描器设为 slow(37.1 节)并观察延迟。大型迁移和再平衡安排在非高峰时段。

38.6 基准测试方法

  • 使用 S3 基准工具。常见第三方选择包括 MinIO 的 warp 和 s3-benchmark。确认工具对 RustFS 的 path-style 寻址正确签名。
  • 在目标硬件和网络上、预发环境中测试,对象大小和并发贴近生产。
  • 每项测试至少跑三次,丢弃预热轮。记录 p50、p95、p99 延迟、吞吐和错误率。
  • 每轮运行期间观察磁盘利用率、CPU、网络和 RustFS 指标。
  • 厂商报告的数字是起点而非保证。项目引用 4 KB 对象吞吐最高可达 MinIO 的 2.3 倍。任何你赖以规划的数字都要用自己的工作负载复现。

38.7 瓶颈指南

症状可能原因措施
小对象延迟高元数据 I/O迁移到 NVMe;减少对象数,例如把小文件打包成归档。
吞吐远低于网络客户端并发或代理缓冲提高并行度;上传禁用代理缓冲。
夜间延迟尖峰扫描器、修复或备份任务调度并限速这些任务。
列举慢大前缀、未分页按前缀分片;分页。
扩容后变慢再平衡或修复等待完成并查看进度。
混合集群整体变慢最慢的存储类决定速度把不同等级拆到独立 Tenant 或集群(34.5 节)。

39. 已验证的 rc 命令参考

以下命令来自 RustFS 文档和 rc 示例。请在你安装的版本上运行 rc --help 和 rc <group> --help 确认语法。

39.1 安装 rc

brew install rustfs/tap/rc
scoop bucket add rustfs https://github.com/rustfs/scoop-bucket && scoop install rustfs/rc
cargo install rustfs-cli
docker run --rm rustfs/rc:latest --help

39.2 命令摘要

任务命令
添加别名rc alias set rustfs https://storage.example.com <access-key> <secret-key>
创建存储桶rc bucket create rustfs/my-bucket
上传或复制对象rc object copy ./file.txt rustfs/my-bucket/file.txt
带请求头复制rc object copy ./file.txt rustfs/my-bucket/file.txt -H "name:value"
递归复制rc object copy ./dir/ rustfs/my-bucket/dir/ --recursive
查看对象rc object show rustfs/my-bucket/file.txt
查看对象或版本信息rc object stat rustfs/my-bucket/file.txt [--version-id <id>]
镜像文件夹rc mirror ./dir rustfs/my-bucket/prefix/
列出版本rc bucket version list rustfs/my-bucket --json
管理事件规则rc bucket event add、rc bucket event list、rc bucket event remove
管理 CORSrc bucket cors set、rc bucket cors get、rc bucket cors list
管理默认加密rc bucket encryption set --mode sse-s3、rc bucket encryption info、rc bucket encryption clear
管理生命周期规则rc bucket lifecycle rule add、rc bucket lifecycle rule list、rc bucket lifecycle rule edit
管理层rc bucket lifecycle tier add、rc bucket lifecycle tier list、rc bucket lifecycle tier info、rc bucket lifecycle tier edit、rc bucket lifecycle tier remove。示例中也出现 rc ilm tier ...。
导出/导入复制rc replicate export <alias>/<bucket>、rc replicate import <alias>/<bucket> <file>
手动存储桶修复用 rc --help 确认 (verify)

39.3 已知限制

  • rc bucket create --with-lock 在 rc 0.1.29 返回 "not implemented"。请在控制台创建对象锁定桶。
  • rc 0.1.29 没有专用 SSE-C 选项,用 -H 发送客户密钥头部。
  • rc 0.1.29 不能更改已有保留期或切换法律保留,请用控制台或 S3 API。

39.4 脚本指导

  • 每个环境创建一个别名(如 prod 和 staging)。不要用服务账户执行管理命令。
  • 从环境变量或密钥管理器读取秘密,绝不硬编码在脚本中。
  • CI 任务中检查退出码。
  • 脚本解析结果时尽可能用 --json 输出。

第十部分 — 生产与参考


40. 最佳实践与生产建议

40.1 硬件选择

  • CPU:高主频多核,加密/SIMD/纠删码计算受益;
  • 内存:生产 ≥ 128 GB(纠删码与缓存);
  • 磁盘:NVMe SSD,JBOD 直通,禁用 NFS/RAID;每个节点独立磁盘;
  • 文件系统:XFS(-i size=512 -n ftype=1),挂载 noatime,nodiratime;
  • 网络:万兆及以上,低延迟,节点间时间同步。

40.2 容量与 EC 规划

场景推荐 EC说明
标准生产EC:4容忍最多 4 块盘/节点故障,可靠性/效率均衡
高可用EC:4-8可用性要求极高,牺牲更多存储
开发测试EC:2基本冗余,非关键业务

40.3 安全建议

  1. 修改默认密钥为强密码(openssl rand -base64 24);
  2. 仅用根凭证引导,日常使用 IAM 用户与服务账户;
  3. 启用 TLS,限制 CORS 为具体域名,防火墙仅开放必要端口;
  4. 生产启用加密(SSE-S3/KMS)并备份主密钥;
  5. 配置审计日志对接 SIEM。

40.4 运维建议

  • 生产使用 MNMD 多机多盘(EC:4 起步);
  • 定期备份配置与 IAM 数据;
  • 扩容/再均衡尽量在维护窗口进行;
  • 升级一次一个节点,保证集群持续可用;
  • 使用 Prometheus + Grafana + OTel 监控集群;
  • 存储建议使用本地 SSD/NVMe,避免 NFS,保证存储目录独占访问。

40.5 参考资源

本文档基于 RustFS 官方文档(rustfs.org.cn / docs.rustfs.com/zh)及公开 SDK 资料整理,包含完整的多语言接入示例代码。具体版本差异以官方最新文档为准。


41. 常见问题

答案按主题分组,每条都链接到有完整细节的章节。标记 (verify) 的条目取决于你的 RustFS 版本。

41.1 总体

问:RustFS 能替代 Amazon S3 吗?

对许多工作负载可以。RustFS 实现了 S3 API,因此使用 S3 SDK 或 CLI 的应用只需更改端点和凭据即可接入。你仍需测试应用依赖的具体操作和功能,并查看你版本的兼容矩阵(20.2 节)。某些存储桶通知、高级复制和部分 IAM 条件键等功能可能有差异。(verify)

问:可以在单台服务器上运行 RustFS 吗?

可以。单节点多驱动器提供驱动器级纠删编码,但不防护服务器故障,因此要保留集群外备份(第 26 章)。无冗余的单驱动器(SNSD)仅用于评估。

问:生产环境需要多少节点?

多节点可在服务器故障期间保持可用。请在拓扑文档(6.1 节)中确认你版本的最小布局。(verify)

问:RustFS 可以免费商用吗?

RustFS 以 Apache 2.0 许可证发布,允许商用。决定前请核对许可证条款以及是否提供满足你需求的商业支持。

问:RustFS 会加密数据吗?

会。传输中使用 TLS(9.3 节)。静态数据方面,RustFS 提供 SSE-S3(通过 KES 和 KMS 由服务端管理密钥)、SSE-KMS(显式 KMS 密钥 ID)和 SSE-C(客户端持有密钥)。各模式及其要求见第 31 章。

41.2 存储策略与第三方存储

问:可以用 Google Drive 作为 RustFS 的存储层吗?

不能作为原生生命周期层。支持的层类型是 s3、rustfs、minio、aliyun、tencent、huaweicloud、azure、gcs 和 r2。Google Drive 是面向个人的文件服务,API 不同且没有 S3 接口,因此不在该列表中。

有两件事常被混淆:

服务能作为 RustFS 层?说明
Google Cloud Storage(GCS)能(gcs 层类型)有自己的桶模型的对象存储服务。多数"谷歌存储"分层问题指的就是它。
Google Drive不能面向个人的文件同步产品,有 API 配额且无对象生命周期。仅可按下文作为外部副本目标。

如果你需要谷歌作为冷层,使用 Google Cloud Storage:创建 GCS 桶、创建对该桶最小权限的服务账户,并注册为 gcs 层。

如果你确实想把数据复制到 Google Drive 供个人或小团队使用,请用 rclone 作为外部任务执行,而不是作为层:

# 一次性:创建 Google Drive remote(会打开浏览器进行 OAuth)
rclone config create gdrive drive scope drive

# 为 rclone 创建 RustFS 别名(或使用已有 remote)
rclone config create rustfs s3 provider Other \
  env_auth false \
  access_key_id <access-key> secret_access_key <secret-key> \
  endpoint https://storage.example.com region us-east-1

# 用 copy(不是 sync)把归档导出目录复制到 Drive
rclone copy rustfs:exports/2026-q3 gdrive:RustFS-Backups/2026-q3 --checksum --transfers 4

# 验证复制
rclone check rustfs:exports/2026-q3 gdrive:RustFS-Backups/2026-q3

把 Google Drive 用作外部目标的注意事项:

  • 配额与限速: 受 Google Drive API 限制。用 --transfers 和 --tpslimit 避免限流错误,并加上重试。
  • 不是生命周期目标: RustFS 的过期和转层不会作用于 Google Drive,保留需你自己脚本管理。
  • 无版本对等: Drive 的文件修订不映射到 RustFS 版本 ID。保留校验和清单以便验证恢复。
  • 加密: 数据敏感时,用 rclone crypt 包装 remote,上传前加密文件。
  • 账户风险: 个人账户不是备份服务。业务关键数据请用 Google Workspace 或基于 GCS 的方案。

问:可以用其他 S3 兼容服务作为存储层吗?

可以。对 Amazon S3 和接受自定义端点的 S3 兼容服务使用 s3 层类型;匹配目标时也可用 minio、r2 及提供者专用类型。示例:

目标层类型说明
Amazon S3s3使用区域端点和专用 IAM 用户。
Cloudflare R2r2许多套餐出口费低或为零,请核对当前定价。
MinIO(另一站点)minio适合第二个本地站点。
阿里云 OSSaliyun使用对应区域端点。
腾讯云 COStencent使用对应区域端点。
华为云 OBShuaweicloud使用对应区域端点。
Wasabi、Backblaze B2、Ceph RGW 等s3 + 自定义端点仅当提供者的 S3 API 满足 RustFS 要求时支持。依赖前先测试探测和往返。(verify)

所有提供者的操作流程相同。创建层见 17.4 节,转层规则见 17.5 节,验证见 17.6 节,维护见 17.7 节。

问:可以用 Azure Blob Storage 或 Google Cloud Storage 吗?

可以,通过 azure 和 gcs 层类型。在提供者处创建容器或桶,创建权限限于该容器/桶的服务身份,注册层,再添加转层规则。Azure 和 GCS 的认证模型与 S3 不同(例如 Azure 用账户密钥或 Entra ID 令牌),请按层配置中的凭据提示操作。(verify credential options)

问:可以用 WebDAV 作为存储目标吗?

不能作为原生层类型。这里有两个不同的 WebDAV 问题:

  1. 通过 WebDAV 访问 RustFS。 RustFS 内置 WebDAV 网关,让 WebDAV 客户端浏览存储桶和对象,这是受支持的(见下文 41.3 节)。
  2. 把 WebDAV 服务器用作存储目标。 例如把 NAS 或 Nextcloud 作为冷副本目的地。RustFS 未把 WebDAV 列为层类型,请用 rclone 做外部复制任务:
rclone config create nas webdav \
  url https://nas.example.com/remote.php/dav/files/backup-user \
  vendor nextcloud \
  user backup-user \
  pass "$(rclone obscure '<password>')"

rclone copy rustfs:archive/2026 nas:rustfs-archive/2026 --checksum

请参照 Google Drive 规划同样的运维控制:无生命周期集成、独立清单、校验和验证。如果需要 NAS 表现为一个层,可在 NAS 上部署 S3 兼容网关(例如 MinIO 或其他 S3 服务器),并注册为 s3 或 minio 层。(verify supported gateways)

问:可以把 RustFS 存储桶像网络驱动器一样挂载到电脑上吗?

可以,两种常见方式:

  • 使用 RustFS WebDAV 网关做 WebDAV 挂载(41.3 节)。兼容 Windows、macOS 内置 WebDAV 客户端和 Linux 的 davfs2。
  • 用 S3 remote 做 rclone 挂载:
rclone mount rustfs:app-data /mnt/app-data --vfs-cache-mode writes --daemon

挂载的文件系统不能替代对象 API。写入可能慢、文件锁能力有限,期望 POSIX 行为的应用可能失败。挂载给需要浏览或拖拽文件的人用,应用请用 SDK。

问:数据转层后我的应用需要改代码吗?

通常不需要。已转层对象仍通过相同的桶和键寻址。主要差异是首次读取已转层对象的延迟,以及归档类在访问前需要恢复步骤。请在预发测试读取路径,确保超时和重试覆盖缓慢的取回。

问:数据可以从层移回本地存储吗?

可以。按需回到本地的对象使用 17.8 节的恢复流程。计划中的批量移动,可以从层反向创建复制任务到本地桶,验证后再删除原件。不要直接在层桶中删除对象。(verify restore and move commands)

问:版本控制对已转层对象有效吗?

版本元数据保留在 RustFS 中。非当前版本可以用生命周期规则转层和过期(16.3 节)。依赖前请在已转层对象上测试版本恢复,因为取回时间可能适用。(verify)

问:层提供者离线会怎样?

本地数据继续正常服务。需要取回的已转层对象在提供者恢复前会失败。无法完成的转层会在提供者返回后重试。监控转层积压和层连通性(25.1 节),并遵循 27.7 节的预案。

问:在对象仍引用时删除层会怎样?

那些对象可能无法再从源集群读取。绝不这样做。遵循 17.7 节的退役流程。

问:分层的费用来自哪里?

四个来源:目标端存储、请求(PUT、GET、LIST)、归档类的数据取回,以及数据离开提供者时的出口。归档类常有最短存储时长和提前删除费。设定转层天数前先建模这些成本。决策清单见 6.4 节。

41.3 WebDAV 网关

问:如何让 RustFS 通过 WebDAV 提供服务?

WebDAV 网关编译进标准 RustFS 二进制,但默认禁用。启动前用环境变量启用:

变量用途
RUSTFS_WEBDAV_ENABLE开启网关
RUSTFS_WEBDAV_ADDRESSWebDAV 监听的地址和端口
RUSTFS_WEBDAV_TLS_ENABLED在 WebDAV 监听上启用 TLS
RUSTFS_WEBDAV_CERTS_DIRTLS 所用证书所在目录

测试环境示例:

export RUSTFS_WEBDAV_ENABLE=true
export RUSTFS_WEBDAV_ADDRESS=0.0.0.0:8080
rustfs /path/to/data

仅允许需要的网络访问 WebDAV 端口的入站 TCP 流量。

问:WebDAV 路径如何映射到存储桶?

存储桶映射为顶层文件夹;桶内文件夹映射为对象键前缀;文件映射为对象。例如 WebDAV 路径 /app-data/reports/2026/summary.csv 对应存储桶 app-data 中的对象键 reports/2026/summary.csv。映射表请查看你版本的 WebDAV 文档。(verify)

问:支持哪些 WebDAV 操作?

网关支持浏览、创建集合(文件夹)、上传、下载、重命名、删除,以及移动到同一端点的目标等常见操作。客户端行为各异,有些客户端会发额外请求。请用你的客户端测试。快速检查可用 curl:

curl -u '<access-key>:<secret-key>' -X PROPFIND -H 'Depth: 1' http://localhost:8080/

问:WebDAV 上如何控制访问?

WebDAV 使用 HTTP Basic 认证:用户名是 RustFS 访问密钥,密码是秘密密钥。RustFS 对照 IAM 校验凭据,并将用户的 S3 策略应用于每个操作,因此同样的最小权限规则适用(第 12 章)。

问:WebDAV 安全吗?

只有启用 TLS 才安全。Basic 认证每个请求都携带凭据,因此不要在可信网络之外用明文 HTTP 暴露 WebDAV 监听。启用 RUSTFS_WEBDAV_TLS_ENABLED,把 RUSTFS_WEBDAV_CERTS_DIR 设为包含证书和密钥的目录,并确认目录存在。若启用 TLS 但证书目录无效,WebDAV 初始化会失败。

WebDAV 用户使用专用服务账户而非 root。考虑把监听限制在 VPN 或内网。

问:如何连接客户端?

  • Windows: 将网络驱动器映射到 https://storage.example.com:8080/(或你的地址),提示时输入访问密钥和秘密密钥。
  • macOS: Finder → 前往 → 连接服务器 → https://storage.example.com:8080/。
  • Linux(davfs2):
sudo apt install davfs2
sudo mkdir -p /mnt/rustfs
sudo mount -t davfs https://storage.example.com:8080/ /mnt/rustfs
  • rclone:
rclone config create rustfs-dav webdav url https://storage.example.com:8080 vendor other \
  user <access-key> pass "$(rclone obscure '<secret-key>')"
rclone ls rustfs-dav:app-data

问:WebDAV 连接慢或大文件失败,为什么?

多数 WebDAV 客户端会缓冲整个文件且不支持断点续传。大传输请用 rclone 或 SDK,WebDAV 留给浏览和小文件。若 WebDAV 在反向代理之后,检查代理或负载均衡的超时与请求体大小限制。

41.4 权限、用户与 SSO

问:可以只给用户访问某个文件夹吗?

可以。对 s3:ListBucket 使用带前缀条件的策略,对象操作限定到 bucket/prefix/*。模式见 12.4 节示例 B。请用非管理员账户测试策略,因为列举权限和对象权限必须匹配,否则用户会看到错误。

问:可以用 Google、Microsoft 或 Okta 账号登录控制台吗?

只要提供者兼容 OpenID Connect 就可以。Google Workspace、Microsoft Entra ID、Okta、Keycloak 等都适用于第 10 章的设置。Google 默认不在其 ID 令牌中放组成员关系,因此需要基于组的 Google 账号访问时,请用 Keycloak 之类的代理。

问:为什么用户通过 SSO 登录了却看不到任何存储桶?

用户已认证但未授权。检查:用户是否在已映射的组中、组声明是否出现在令牌里、映射的策略是否允许 s3:ListAllMyBuckets 或桶级列举。完整故障排查表见 10.9 节。

问:可以不通过 SSO 给应用授权吗?

可以。应用应使用带访问密钥的服务账户而非 SSO(10.8 节)。把密钥存入密钥管理器并按计划轮换(11.5 节)。

问:可以限制哪些 IP 能访问存储桶吗?

可以,用 Deny 语句加 NotIpAddress 条件(12.3 节)。强制执行前先测试该条件。注意:经过反向代理的流量可能显示为代理的地址,除非你配置了可信转发头。(verify header handling)

问:如果丢失了根凭据怎么办?

使用你文档化的应急流程(9.1 节)。如果没有恢复路径,可能需要在服务器上通过环境或服务配置重置凭据并重启。把根凭据放在有两名保管人的密钥库中可避免此情况。

41.5 版本控制与数据保护

问:版本控制就是备份吗?

不是。版本控制防止集群内部的意外覆盖和删除,不防止整个集群被删、管理员被攻陷或损坏所有版本的故障。请保留集群外副本(第 26 章)。

问:启用版本控制后能关闭吗?

可以暂停,但存储桶无法回到从未版本化的状态。暂停期间已有版本保留。在备份或合规桶上启用前先规划(15.1 节)。

问:存储突然增长,发生了什么?

最常见原因是频繁覆盖产生的非当前版本,或未完成的分片上传。用 list-object-versions 检查版本数量,并添加 12.3 和 16.4 节的生命周期规则。

问:可以防止任何人在一段时间内删除文件吗?

可以。在控制台创建存储桶时启用对象锁(它也会开启版本控制)。COMPLIANCE 保留可阻止包括 root 在内的任何人删除,直到 retain-until 日期。模式、法律保留和限制见第 30 章。

问:如何恢复昨天删除的文件?

若启用了版本控制,删除删除标记或把前一版本复制回来(15.4 节)。若没有,从集群外备份恢复。这就是重要存储桶应开启版本控制的原因。

41.6 生命周期与分层运维

问:生命周期规则什么时候执行?

规则异步执行,不是在精确时间。对象满足条件后会有延迟。不要把生命周期规则当作精确的法定删除机制。(verify scheduling)

问:可以让一条生命周期规则转层、另一条让同一对象过期吗?

避免这种设计。每个数据类别只选一种终态动作:转冷或过期,二选一。重叠规则在审计时难以推理。请记录每条规则的用途和所有者。

问:如何不等 90 天测试生命周期规则?

创建测试桶,放入几个测试对象,在默认禁用的规则中使用较短天数(如 1 天)。启用它,观察结果,然后把同样的设计以正确天数应用到生产。(verify whether a dry-run option exists)

问:可以只转层某些文件吗?

可以。使用前缀或标签过滤器(12.2 和 16.6 节)。上传时给对象打保留类别标签并按标签过滤。多个应用共享一个桶时,这比纯前缀规则更易治理。

41.7 容量、扩展与运维

问:可以不停机扩容吗?

通常可以,按 19.3 节流程添加服务器池。请核实你版本的流程,且不要在降级状态下发起拓扑变更。

问:添加池会自动迁移已有数据吗?

不一定。新写入可能放到新池,而已有对象留在原地。再平衡行为因版本而异,请查看文档并在扩容后监控容量分布。(verify)

问:可以移除服务器池吗?

可以,通过退役(19.4 节)。退役会先把数据迁出该池,需要剩余池有足够空闲容量,且可能耗时很久。

问:如何监控 RustFS?

关注端点健康、每池容量、错误率、修复进度和层连通性(第 25 章)。RustFS 通过 OTLP 推送遥测到 OpenTelemetry Collector,Prometheus 抓取该采集器。配置见第 36 章。

问:必须开放哪些端口?

S3 API 用 9000,控制台用 9001;仅在启用 WebDAV 网关时开放 WebDAV 端口(如 8080)。节点间 RPC 使用与 S3 API 相同的地址(RUSTFS_ADDRESS,默认 :9000),因此集群节点之间必须互通 9000 端口。

问:可以在 Kubernetes 上用 RustFS 吗?

可以,通过 RustFS Kubernetes Operator 和 Helm Chart(7.17 节)。扩缩使用 Operator 的池操作,应用前审阅示例清单。(verify current operator version)

问:如何升级而不丢数据?

遵循 26.5 节:阅读路径上每个版本的发行说明、在预发测试、备份配置并验证集群外副本、支持时逐节点升级、保留上一版二进制或镜像以便回滚。

问:控制台和 API 有什么区别?

控制台(9001 端口)是供人管理存储桶、用户、策略和层的 Web 界面。S3 API(9000 端口)面向应用和命令行工具。WebDAV 网关是供 WebDAV 客户端的独立监听器。三者执行同一套 IAM 策略。

41.8 选择存储方案

需求推荐方案章节
应用对象存储RustFS S3 API + 服务账户18
主流云中的冷存储转层到 s3、gcs、azure 或提供者专用类型13
灾难恢复第二站点转层到另一个 RustFS 集群,或用 rclone 复制13.9、20.2
低出口费的预算归档评估价格后转层到 r2 或类似低成本提供者13.1
人员从桌面浏览文件WebDAV 网关,或 Cyberduck 等 GUI 客户端23.3、18.9
复制到个人 Google Driverclone copy 任务,而非层23.2
复制到 NASrclone 到 WebDAV,或在 NAS 上部署 S3 网关23.2
严格监管保留对象锁或保留,外加异地副本14

附录 A. 策略操作参考

操作适用对象用途
s3:ListAllMyBuckets服务列出调用者可见的存储桶
s3:ListBucket桶 ARN列出桶内对象
s3:GetBucketLocation桶 ARN读取桶区域
s3:GetBucketVersioning桶 ARN读取版本控制状态
s3:PutBucketVersioning桶 ARN更改版本控制状态
s3:CreateBucket桶 ARN创建存储桶
s3:DeleteBucket桶 ARN删除存储桶
s3:GetBucketPolicy / s3:PutBucketPolicy / s3:DeleteBucketPolicy桶 ARN管理存储桶策略
s3:GetLifecycleConfiguration / s3:PutLifecycleConfiguration桶 ARN管理生命周期规则
s3:GetBucketTagging / s3:PutBucketTagging桶 ARN管理存储桶标签
s3:GetBucketCORS / s3:PutBucketCORS桶 ARN管理 CORS
s3:ListBucketVersions桶 ARN列出对象版本
s3:GetObject对象 ARN读取对象内容
s3:GetObjectVersion对象 ARN读取特定版本
s3:PutObject对象 ARN上传对象
s3:DeleteObject对象 ARN删除当前对象或添加删除标记
s3:DeleteObjectVersion对象 ARN永久删除版本
s3:GetObjectTagging / s3:PutObjectTagging对象 ARN管理对象标签
s3:AbortMultipartUpload对象 ARN取消分片上传
s3:ListMultipartUploadParts对象 ARN列出上传的分片
s3:RestoreObject对象 ARN恢复已转层对象(如支持)(verify)
admin:*服务管理操作,确切名称因版本而异 (verify)
admin:SetTier服务创建、更新和删除层

附录 B. 生产就绪检查清单

基础

  • 拓扑满足可用性要求(多节点、纠删编码)
  • 容量按校验位开销并至少留 20–30% 余量规划
  • 所有节点和客户端 NTP 同步
  • 数据盘与系统盘分离

安全

  • 根凭据已更改并存入有两名保管人的密钥库
  • 控制台不对公网可达
  • 所有外部端点启用 TLS
  • SSO 已启用、已测试并映射到组
  • 应急账户已测试
  • IdP 对管理员强制 MFA
  • 没有应用使用根凭据
  • 服务账户具有经测试的最小权限策略
  • 访问密钥有所有者、用途和轮换日期
  • 备份桶和敏感数据已配置 Deny 护栏

数据保护

  • 业务关键存储桶已启用版本控制
  • 已配置非当前版本和未完成上传的生命周期规则
  • 需要 WORM 保护的桶已配置对象锁(第 25 章)
  • 集群外备份运行中并已通过恢复测试
  • 事件通知和审计目标已评审,消费端按至少一次设计(第 24 章)
  • 已选择加密模式并测试 KMS 或密钥保管(第 26 章)
  • 配置已备份且恢复顺序已文档化

存储策略

  • 已定义热、温、冷数据类别
  • 层配置有文档,凭据安全保存
  • 转层与过期规则经数据所有者评审
  • 已估算出口与取回费用
  • 退出计划已文档化

运维

  • 已定义指标、仪表板和告警
  • 日志集中发送并按政策保留
  • 管理与删除事件有审计追踪
  • 升级流程已在预发测试
  • 常见事件的 Runbook 经值班团队评审
  • 容量预测每月评审

附录 C. 术语表

  • 访问密钥(Access key): 与秘密密钥配对用于签名请求的标识符。
  • 归档(Archive): 以低成本长期保留数据,通常带有保留规则。
  • 存储桶(Bucket): 对象的顶层容器。
  • 存储桶策略(Bucket policy): 附属于存储桶的基于资源的策略。
  • CORS: 跨源资源共享;控制浏览器从其他站点的访问。
  • 删除标记(Delete marker): 版本占位符,表示版本化桶中当前对象已被删除。
  • 纠删编码(Erasure coding): 把数据拆分为带校验的分片,以便在部分丢失后重建。
  • 纠删集(Erasure set): 共享条带布局的一组驱动器。
  • 扩展(Expansion): 增加容量或吞吐,通常通过添加服务器池。
  • IAM: 身份与访问管理。
  • IdP(身份提供者): 为 SSO 认证用户的系统。
  • 法律保留(Legal hold): 对删除或修改的无限期保护。
  • 生命周期规则(Lifecycle rule): 自动过期或转层的规则。
  • 分片上传(Multipart upload): 分部分上传大对象。
  • 非当前版本(Noncurrent version): 版本化桶中对象的较旧版本。
  • OIDC(OpenID Connect): 构建在 OAuth 2.0 之上的身份层,用于 SSO。
  • 对象锁(Object lock): 在保留期内阻止删除或覆盖的保护。
  • PKCE: 代码交换证明密钥;OAuth/OIDC 流程的安全扩展。
  • 策略(Policy): 授予或拒绝操作的 JSON 文档。
  • 预签名 URL(Presigned URL): 授予对象限时访问的 URL。
  • 主体(Principal): 发起请求的身份。
  • RPO / RTO: 恢复点目标与恢复时间目标。
  • S3 兼容: 实现 Amazon S3 API。
  • 服务器池(Server pool): 作为整体加入集群的一组节点和驱动器。
  • 服务账户(Service account): 拥有自己访问密钥的非人类身份。
  • SigV4: AWS 签名版本 4,请求签名方法。
  • 层(Tier): 生命周期转层的远程存储目标。
  • 转层(Transition): 把对象移动到另一存储类或层。
  • 版本控制(Versioning): 保留对象的每个修订版本。

本手册反映撰写时有文档记载的 RustFS 行为以及标准 S3 与 OIDC 实践。标记 (verify) 的条目在生产依赖前必须对照你部署版本的文档确认。请先在非生产环境测试每个流程。

评论

推荐阅读

订阅邮件

订阅更新,及时收到最新文章。

作者