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,它们可对接任何兼容端点。
目录
第一部分 — 基础与规划
第二部分 — 安装与初始设置
- 7. 安装
第三部分 — 身份与访问
第四部分 — 数据管理
第五部分 — 存储策略
- 17. 存储分层与第三方对象存储
第六部分 — 程序接入与接口
第七部分 — 运维
第八部分 — 高级特性
第九部分 — 配置与性能
第十部分 — 生产与参考
第一部分 — 基础与规划
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 是理想选择:
- 需要 S3 兼容对象存储,但不想依赖公有云:私有化部署 / 混合云 / 边缘计算。
- 要替代 MinIO / Ceph:尤其看重 Apache 2.0 许可、内存安全、国产化替换。
- 有海量非结构化数据:图片、视频、日志、备份、文档、AI 数据集等。
- 需要高性能读写:AI 训练、大数据计算存储分离、量化交易等低延迟、高吞吐场景。
- 需要企业级数据安全与合规:金融、政务、医疗、档案馆等需要 WORM、加密、审计的行业。
- 团队需要快速集成:已有 S3 SDK /
mc/ AWS CLI,或需要 MCP 接入 AI 工具链。 - 需要多租户、多用户、精细权限管理:IAM 用户/组/策略/服务账户。
4. RustFS 相比其他方案的优势
4.1 与 Ceph / MinIO 对比
| 参数 | Ceph | MinIO | RustFS |
|---|---|---|---|
| 开发语言 | C++ | Go | Rust |
| 开源许可证 | GPL/LGPL | AGPL-3.0 | Apache-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 对象放置规则
- 一个对象存储在一个 Set 上;
- 一个集群划分为多个 Set;
- 一个 Set 包含的 Drive 数量默认由系统根据集群规模自动计算;
- 一个 Set 中的 Drive 尽可能分布在不同的节点上。
6. 规划部署
6.1 选择拓扑
| 拓扑 | 典型用途 | 冗余 | 说明 |
|---|---|---|---|
| 单节点单驱动器(SNSD) | 评估、开发、CI | 无 | 驱动器故障即数据丢失,绝不用于生产。 |
| 单节点多驱动器 | 小型部门存储、边缘场景 | 驱动器级纠删编码 | 节点故障会导致存储离线。 |
| 多节点多驱动器 | 生产、高可用 | 节点级与驱动器级纠删编码 | 生产环境推荐基线。弹性布局至少使用四个节点。(verify:你版本的最小值) |
| 多服务器池 | 集群增长、分阶段硬件更新 | 按池隔离 | 每个池是独立的纠删布局,见第 19 章。 |
| Kubernetes Operator(Tenant) | 平台团队运行多租户 | 视拓扑而定 | 通过 RustFS Kubernetes Operator 和 Helm Chart 管理。(verify:当前 Operator CRD) |
6.2 容量规划
按如下方式估算容量:
- 原始数据量 = 预计存储总量(包含版本和保留需求)。
- 开销 = 原始数据量 ×(总分片数 ÷ 数据分片数),按所选纠删布局计算。
- 余量 = 至少保留 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 部署模式概览
| 模式 | 磁盘 | 节点 | 适用场景 |
|---|---|---|---|
| SNSD | 1 | 1 | 本地测试 |
| SNMD | ≥2 | 1 | 单机高可用 |
| MNMD | ≥1/节点 | ≥4 | 生产级分布式 |
最少需要 4 台服务器,每台至少 1 块磁盘,才能安全启动生产级分布式集群。
8.2 架构目标
默认 12 + 4 纠删码模式:1 个数据块拆成 12 个数据块 + 4 个校验块,分散到不同服务器的不同磁盘。
- 任意 1 台服务器损坏/维护,不影响数据安全;
- 任意 4 块磁盘以内损坏,不影响数据安全。
8.3 先决条件
- 操作系统:Linux 内核 4.x 及以上(5.x/6.x 更佳),Ubuntu 22.04 或 RHEL 8.x;
- 内存:测试 ≥ 2 GB,生产 ≥ 128 GB;
- 时间同步:所有节点必须一致(
ntp/timedatectl/timesyncd),否则可能无法启动; - 磁盘:推荐 JBOD 直通模式,禁用 NFS 作为底层存储;建议 NVMe SSD;文件系统强烈推荐 XFS;
- 网络:所有节点使用相同端口(默认 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,也就是说全新安装会以一个公开已知的身份启动。请在执行任何其他步骤之前更改访问密钥和秘密密钥。
- 通过你所用安装方式的环境变量设置根访问密钥和长随机秘密(
RUSTFS_ACCESS_KEY和RUSTFS_SECRET_KEY,均见第 35 章环境变量参考)。 - 重启服务。
- 确认新凭据可用、默认凭据已被拒绝。
- 将根凭据存入密码管理器或密钥保险库,并指定两名具名保管人。
生成秘密:
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):
- RustFS 携带 S256 PKCE 挑战值将用户浏览器重定向到 IdP。
- 用户在 IdP 完成认证。密码、MFA 和条件访问都在 IdP 强制执行。
- IdP 携带授权码重定向回 RustFS 回调 URL。
- RustFS 用授权码到令牌端点换取令牌。
- RustFS 校验 ID 令牌:签名(通过 JWKS 端点)、签发者、受众、过期时间和 nonce。
- 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
通用步骤(各产品标签略有不同):
- 为 RustFS 创建一个 Web 客户端。文档示例使用无客户端密钥的客户端(关于密钥见 10.6 节)。
- 将重定向 URI 设置为精确的回调 URL。协议、主机、端口、路径和结尾斜杠都必须匹配。
- 将 Web origins 或允许的来源设置为控制台的公网源。
- 启用授权码流程和 PKCE(S256),如果 IdP 提供的话。
- 请求
openid、profile和email作用域。缺少openid时,RustFS 会报告未收到 ID 令牌。 - 添加映射器或声明,把组或角色名称以扁平字符串列表形式放入令牌。
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 之前的基 URL | https://keycloak.example.com/realms/rustfs |
RUSTFS_IDENTITY_OPENID_CLIENT_ID | 来自 IdP 的客户端 ID | rustfs-console |
RUSTFS_IDENTITY_OPENID_SCOPES | 逗号分隔的作用域 | openid,profile,email |
RUSTFS_IDENTITY_OPENID_REDIRECT_URI | 在 IdP 注册的回调 URL | https://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 策略名称完全一致。不匹配任何策略的名称不授予任何权限;匹配某个策略的名称恰好获得该策略允许的权限。
推荐设计:
- 先创建 RustFS 策略(第 12 章),按 IdP 组命名,例如
rustfs-admins、rustfs-readwrite、rustfs-readonly。 - 配置 IdP,把那些名称以扁平列表形式输出到 RustFS 读取的声明中,嵌套组路径要打平。
- 推广前,每个组先用一个账户测试。
- 保持策略集小而经过评审。把策略名称视为与 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 工作流程
- RustFS 发送带 S256 PKCE 质询的授权请求;
- IdP 验证身份,将授权码重定向回 RustFS 回调 URL;
- RustFS 在令牌端点交换授权码;
- RustFS 验证 ID 令牌的签名、签发者、受众、有效期、nonce;
- 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 侧:
- 创建 realm
rustfs,创建 OIDC 客户端rustfs-console; - 启用 Client authentication、Standard flow,关闭 Implicit / Direct access grants;
- Valid redirect URIs 设为
https://rustfs.example.com/rustfs/admin/v3/oidc/callback/default; - PKCE 设为
S256; - 添加 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 访问密钥轮换流程
- 为同一服务账户创建新的访问密钥。
- 将新密钥部署到应用的密钥存储中。
- 确认应用使用新密钥正常工作(观察日志与指标)。
- 停用旧密钥。
- 宽限期后删除旧密钥。
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)
- 在 IdP 禁用该用户(SSO 用户在下次登录或令牌过期时失去访问权)。
- 禁用本地 IAM 用户并移除其访问密钥。
- 将其服务账户的所有权移交给其他管理员。
- 检查任何点名该用户的存储桶策略或 ACL。
- 在审计系统中记录该变更。
11.7 特权访问
- 限制持有
consoleAdmin或等效策略的人数,通常两三到四人。 - 通过 IdP 对管理员强制 MFA。
- 如组织要求,管理用途与日常使用使用不同账户。
- 记录管理操作并定期评审。
12. 策略与权限管理
12.1 授权评估方式
对每个请求,RustFS 检查:
- 任一适用策略中的显式拒绝 → 拒绝。
- 适用策略中的显式允许 → 允许。
- 没有匹配的允许 → 拒绝(默认拒绝)。
适用策略来自:
- 身份策略:附属于用户、组或服务账户。
- 存储桶策略:附属于存储桶,可授予其他主体或匿名访问。
对于跨账户式的访问,当请求来自不同主体时,身份策略和存储桶策略必须同时允许该操作。(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 | 可选的语句标识。 |
Effect | Allow 或 Deny。 |
Action | S3 操作如 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 测试策略
在把访问权授予生产数据之前:
- 创建一个附加了该策略的测试用户。
- 测试应用需要的每项操作(列举、get、put、删除、分片上传)。
- 测试本应失败的操作(在前缀外写入、删除、列举其他存储桶)。
- 将结果记录到变更工单中。
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 / AssumeRoleWithWebIdentity | 15 分钟~12 小时短期凭证 |
| 外部 OIDC 身份 | Keycloak / GitLab / Authing 等 | 控制台 SSO |
12.10 创建 / 删除访问密钥(AK/SK)
- 登录控制台 → 左侧「访问密钥」→ 右上角「添加访问密钥」;
- 输入过期时间、名称、描述 → 提交;
- 复制或导出保存(仅显示一次)。
12.11 策略评估语义(Deny 优先与所有者规则)
- 显式拒绝优先:任何匹配的
Deny语句都会拒绝请求; - 所有者快捷规则:根账户绕过 IAM 身份策略评估;
- 必须显式允许:其他身份必须至少有一条匹配的
Allow语句; - 默认拒绝:无语句匹配则拒绝。
带会话策略的服务账户 / STS 会话,有效权限取交集(父策略与会话策略都必须允许)。
12.12 内置策略
| 策略 | 权限 |
|---|---|
readwrite | 所有 S3 操作(s3:*)+ sts:AssumeRole |
readonly | s3:GetBucketLocation、s3:GetObject、s3:GetBucketQuota + sts:AssumeRole |
writeonly | s3: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 三种存储桶状态(启用 / 暂停 / 未启用)
- 未启用(默认);
- 已启用:为每个对象版本分配唯一 ID;
- 已暂停:停止累积新版本,保留现有版本。
一旦启用无法撤销,只能暂停。系统要求:纠删码 + 至少四个磁盘。
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。
| 层类型 | 目标 | 典型用途 |
|---|---|---|
s3 | Amazon S3 或 S3 兼容服务 | 云端归档或冷存储 |
rustfs | 另一个 RustFS 部署 | 自有集群之间的热转冷 |
minio | MinIO 或本地 S3 兼容存储 | 迁移或第二站点 |
aliyun | 阿里云 OSS | 区域云存储 |
tencent | 腾讯云 COS | 区域云存储 |
huaweicloud | 华为云 OBS | 区域云存储 |
azure | Azure Blob Storage | 企业云归档 |
gcs | Google Cloud Storage | 云端归档 |
r2 | Cloudflare 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 集群管理数据,使本地转层元数据与远程数据保持一致。
- 对象仍引用某层时不要删除该层。 删除会使已转层对象无法从源集群读取。
- 退役一个层的步骤:
- 停用引用该层的生命周期规则。
- 将剩余已转层对象恢复/迁移回本地存储或新层。
- 确认没有对象引用该层。
- 备份层配置并记录目标位置。
- 删除该层。
- 层凭据按与其他服务账户相同的计划轮换。
17.8 恢复已转层数据
取回方式取决于层和提供者。许多归档类需要提交恢复请求且有取回延迟。流程:
- 确定需要的对象(前缀、日期范围或版本)。
- 通过源 RustFS 工作流触发恢复。(verify restore command or Console action)
- 等待完成并校验校验和。
- 根据出口和取回费用规划恢复量。
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
| 参数 | 默认 | 建议 | 说明 |
|---|---|---|---|
--transfers | 4 | 8~32 | 并行文件数,取决于带宽与后端限流 |
--checkers | 8 | 16~64 | 并行检查文件数 |
--multi-thread-cutoff | 256M | 64M~256M | 超过该大小的文件启用多线程 |
--multi-thread-streams | 4 | 8 | 大文件并行分片流数 |
--buffer-size | 16M | 32M~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
然后:
- 创建专用归档服务账户,可写但不可删(见 12.4 节示例 C)。
- 为审计人员创建只读恢复组,另设独立的恢复审批组。
- 添加生命周期规则:N 天后转层、保留期后过期(仅当保留政策允许过期时)。
- 需要处启用对象锁或法律保留(verify)。
18.4 摄入与验证
- 每批数据写清单:对象列表、大小、SHA-256 校验和。清单存放在单独位置。
- 上传后通过
head-object(ETag 或校验和头部,如可用)比对校验和,或下载样本做哈希。 - 在审计日志中记录验证结果。
18.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 添加服务器池(概念流程)
- 新节点使用与集群相同的操作系统和 RustFS 版本。
- 安装 RustFS 二进制或容器。配置定义好之前,不要让其加入旧集群。
- 按你安装方式的文档语法更新集群拓扑配置以包含新池。(verify)
- 按该版本文档的方式执行滚动重启或应用配置。
- 在控制台和 CLI 中确认新池健康。
- 创建测试对象并确认其落位且可读。
- 随后数日监控容量分布和后台修复。
在 Kubernetes 上,Operator 支持向 Tenant 添加池。请使用该 Operator 版本文档的池操作,并在应用前审阅示例清单的行内注释。(verify)
19.4 移除池(退役)
退役会在移除前把数据迁出该池。过程缓慢,必须规划。
- 确保剩余容量能在留有余量的情况下容纳该池的数据。
- 通过受支持的命令或 Operator 字段启动退役。(verify)
- 监控进度直到该池报告完全排空。
- 抽样确认对象数量和校验和。
- 从拓扑中移除该池。
池退役期间不要关机或擦除其驱动器。
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"
关键:每个节点必须使用完整且顺序一致的存储池列表启动,遗漏或顺序不同会造成拓扑不一致。
扩容流程:
- 记录现有存储池;
- 新节点安装相同版本与配置;
- 所有节点
RUSTFS_VOLUMES追加新表达式; - 重启 RustFS,等待就绪;
- 验证:
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:
- S3 兼容 API,用于对象操作、存储桶配置和标准 S3 功能集。
- 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/tier | admin: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 提供三种管理方式:
- Console 控制台(Web UI,默认端口 9001);
- 命令行客户端
rc(RustFS 官方 CLI); - 兼容
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 应用接入流程
- 为应用创建服务账户。
- 编写最小权限策略并测试(12.7 节)。
- 把密钥存入应用的密钥管理器。
- 配置端点、区域和寻址风格。
- 运行冒烟测试:在测试前缀上执行列举、put、get、delete。
- 设置错误和吞吐监控。
- 在服务目录中记录所有者、用途、存储桶和轮换日期。
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
前端代码不应持有长期密钥。模式:
- 浏览器请求你的后端上传文件。
- 后端检查授权并返回预签名 PUT URL。
- 浏览器直接上传到 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 |
| Rust | endpoint_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 防护层次
对象存储通过纠删编码防护磁盘故障,但你仍需要:
- 版本控制,从覆盖和删除中恢复(第 15 章)
- 对象锁或保留,保护不得篡改的记录(第 18 章)
- 集群外副本,位于另一位置或提供者
- 配置备份(策略、生命周期、层、身份配置、拓扑)
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 升级
- 阅读当前版本到目标版本之间每个版本的发行说明和升级指南。
- 在预发环境用生产配置副本测试升级。
- 备份配置并验证异地数据副本。
- 安排维护窗口并通知用户。
- 拓扑支持时逐节点滚动升级,节点间确认健康。
- 验证 S3 操作、控制台登录、SSO 登录、层连通性和一次生命周期测试。
- 升级被接受前保留上一版镜像或二进制以便回滚。
只有数据格式未变时回滚才安全。升级前查看发行说明。(verify rollback guidance)
26.6 备份策略检查清单
- 配置数据备份:定期备份
/etc/default/rustfs、systemd 服务、TLS 证书、KMS 密钥目录; - IAM 数据备份:导出
GET /rustfs/admin/v3/export-iam,异地保存; - 数据冗余:生产环境使用 EC ≥ 4 的 MNMD 集群保证单点失效不影响数据;
- 站点级容灾:使用跨区域复制(Replication)实现整桶异地备份;
- 对象级保护:启用版本控制 + 对象锁定防误删误改。
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)
- 将用户加入相应的 IdP 组。
- 请用户登录一次控制台并确认可访问。
- 确认用户只能执行被允许的操作。
- 记录该变更。
27.2 添加新应用
遵循 22.1 节。
27.3 轮换服务账户密钥
遵循 11.5 节。
27.4 员工离职
遵循 11.6 节。另检查其个人访问密钥和共享存储桶策略。
27.5 调查意外删除
- 从审计日志确定存储桶、前缀和时间窗口。
- 检查是否启用了版本控制。若是,列出版本和删除标记。
- 通过删除删除标记或复制版本回来恢复(15.4 节)。
- 若未启用版本控制,从异地副本恢复。
- 确定责任主体及其策略,收紧策略。
- 撰写事后复盘记录。
27.6 从磁盘故障中恢复
- 确认磁盘已故障(控制台、日志或
smartctl)。 - 用同等或更大容量替换。
- 启动修复并监控直到完成。
- 验证对象数量和健康状况。
27.7 响应层故障
- 通过提供者状态页确认故障。
- 若依赖的生命周期规则会反复失败,先暂停它们。
- 继续用本地数据服务。需要该层的已转层对象在恢复前会失败。
- 提供者恢复后,恢复规则并确认积压清空。
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 / 403 | Nginx HEAD 转 GET | 加 proxy_cache_convert_head off |
PermanentRedirect | 未启用 path-style | 设置 forcePathStyle=true |
| 多节点无法启动 | 时间不同步 | 配置 NTP 时间同步 |
| 目录权限拒绝 | 容器 UID 不匹配 | chown -R 10001:10001 /data |
NoSuchKey | 对象不存在 | 检查 Key 拼写 |
| 复制失败 | 版本控制/对象锁定不匹配 | 两端启用版本控制并保持锁定一致 |
第八部分 — 高级特性
29. 事件通知
事件通知把存储桶活动发送给外部系统。常见用途是文件到达时通过 webhook 启动工作流。通知默认禁用。
事件通知有两个独立部分:
- 通知目标: 事件投递到哪里。每个服务器用环境变量定义目标。
- 存储桶通知配置: 哪个桶、哪些事件类型、哪些键过滤器,发送到哪个目标 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 依赖前先证明锁有效
- 上传一个带 GOVERNANCE 保留的测试对象。
- 用没有 bypass 权限的标准身份尝试删除该确切版本,请求必须以
AccessDenied失败。 - 确认该版本仍在控制台和
rc object stat中可见。 - 用 COMPLIANCE 保留和法律保留重复测试。
- 把结果记录到变更记录中。
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_ENABLE | false | 监视目录并热重载证书,无需重启。 |
RUSTFS_SERVER_MTLS_ENABLE | false | 在服务端监听上要求客户端证书(双向 TLS)。 |
RUSTFS_TRUST_SYSTEM_CA | false | 出站连接信任操作系统 CA 存储,例如连接使用私有 CA 的 IdP 或层。 |
RUSTFS_TLS_KEYLOG | false | 写出 TLS 会话密钥用于调试,生产环境绝不可启用。 |
在 RustFS 前放置反向代理(9.3 节)仍是有效模式。
31.2 静态数据:服务端加密
RustFS 在磁盘上加密对象,每个对象得到唯一数据密钥。文档记载的密码算法为 AES-256-GCM 和 ChaCha20-Poly1305。密钥保护模式取决于你如何配置存储桶或请求。
| 模式 | 谁持有密钥 | 客户端如何请求 | 说明 |
|---|---|---|---|
| SSE-S3 | RustFS,通过 KES 和 KMS | 头部 x-amz-server-side-encryption: AES256 | 需要已配置 KMS。KMS 不可用时写入失败。 |
| SSE-KMS | KMS,使用显式密钥 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 系统迁移
-
盘点源端。 列出存储桶、对象数、大小、版本、标签、策略、生命周期规则、CORS、通知配置和加密设置。
-
创建目标存储桶。 尽量使用相同名称。需要时在创建时启用版本控制和对象锁。
-
配置别名:
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> -
复制对象:
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) -
验证。 比较对象数和总大小。先做单向检查,再抽样校验和:
rclone check src:app-data rustfs:app-data --one-way -
重建配置。 策略、用户与服务账户、生命周期规则、CORS、标签、通知配置和加密默认值必须重新创建。镜像只复制对象。
-
增量同步与切换。 把源端设为只读或暂停写入,执行最终镜像,验证,切换应用端点,并观察错误率。
-
保留回滚路径。 在约定期内保持源端完好且只读,并文档化切回步骤。
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_ADDRESS | WebDAV 监听的绑定地址和端口 |
RUSTFS_WEBDAV_TLS_ENABLED | 在 WebDAV 监听上启用 TLS |
RUSTFS_WEBDAV_CERTS_DIR | RustFS 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_ADDRESS | 0.0.0.0:9000 |
RUSTFS_CONSOLE_ENABLE | true |
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 | :9000 | S3 API 监听地址,同时承载内部节点 RPC,节点间必须可达。 |
RUSTFS_CONSOLE_ENABLE | true | 在独立监听上启用内置控制台。 |
--console-address(选项) | :9001 | 控制台监听地址。 |
RUSTFS_ACCESS_KEY | rustfsadmin | 根访问密钥,务必先改。 |
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_STANDARD | auto | STANDARD 类的校验位,EC:n 形式。 |
RUSTFS_STORAGE_CLASS_RRS | EC:1 | REDUCED_REDUNDANCY 类的校验位,EC:n 形式。 |
35.3 扫描器与修复
| 变量 | 默认 | 说明 |
|---|---|---|
RUSTFS_SCANNER_SPEED | default | 预设:fastest、fast、default、slow 或 slowest。 |
RUSTFS_SCANNER_DELAY | 预设 | 覆盖休眠倍数。 |
RUSTFS_SCANNER_MAX_WAIT_SECS | 预设 | 覆盖最大休眠秒数。 |
RUSTFS_SCANNER_ALERT_EXCESS_VERSIONS | 100 | 触发扫描器告警的版本数。 |
RUSTFS_SCANNER_ALERT_EXCESS_FOLDERS | 65538 | 触发扫描器告警的直接子文件夹数。 |
RUSTFS_HEAL_AUTO_HEAL_ENABLE | true | 自动后台修复降级对象。 |
35.4 TLS
| 变量 | 默认 | 说明 |
|---|---|---|
RUSTFS_TLS_PATH | 未设置 | 证书目录,设置即启用 TLS。 |
RUSTFS_TLS_RELOAD_ENABLE | false | 证书热重载。 |
RUSTFS_SERVER_MTLS_ENABLE | false | 要求客户端证书。 |
RUSTFS_TRUST_SYSTEM_CA | false | 出站连接信任操作系统 CA 存储。 |
RUSTFS_TLS_KEYLOG | false | 仅调试,绝不用生产。 |
35.5 KMS
| 变量 | 默认 | 说明 |
|---|---|---|
RUSTFS_KMS_ENABLE | false | 启用 KMS 支持的服务端加密。 |
RUSTFS_KMS_BACKEND | local | local、vault(KV2 + Transit)、vault-kv2 或 vault-transit。 |
RUSTFS_KMS_LOCAL_MASTER_KEY | 未设置 | 保护本地 KMS 密钥文件。 |
RUSTFS_KMS_DEFAULT_KEY_ID | 未设置 | 加密的默认密钥 ID。 |
RUSTFS_KMS_ALLOW_INSECURE_DEV_DEFAULTS | false | 仅开发用,绝不用生产。 |
35.6 身份与浏览器
| 变量 | 说明 |
|---|---|
RUSTFS_BROWSER_REDIRECT_URL | 控制台公网源。 |
RUSTFS_IDENTITY_OPENID_CONFIG_URL | OIDC 签发者。命名提供者加后缀 _<provider>。 |
RUSTFS_IDENTITY_OPENID_CLIENT_ID | OIDC 客户端 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_ENABLED | true | 导出指标。 |
RUSTFS_OBS_METER_INTERVAL | 未设置 | 指标导出间隔(秒)。 |
RUSTFS_OBS_ENVIRONMENT | 未设置 | 如 production、staging、test 的标签。 |
RUSTFS_OBS_LOG_DIRECTORY | 未设置 | 日志文件目录。 |
RUSTFS_OBS_LOG_FILENAME | rustfs.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 章。 |
| 审计 webhook | RUSTFS_AUDIT_WEBHOOK_ENDPOINT_<S>、..._AUTH_TOKEN_<S>、..._QUEUE_DIR_<S>。见 29.6 节。 |
| WebDAV | RUSTFS_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_* 序列缺失时按此清单排查:
-
每个节点都设置了
RUSTFS_OBS_ENDPOINT。 -
每个节点都能在 4318(HTTP)或 4317(gRPC)端口访问采集器。
-
采集器的 Prometheus 导出器有响应:
curl -s http://otel-collector:8889/metrics | grep '^rustfs_' | head -
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 |
| 管理 CORS | rc 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 安全建议
- 修改默认密钥为强密码(
openssl rand -base64 24); - 仅用根凭证引导,日常使用 IAM 用户与服务账户;
- 启用 TLS,限制 CORS 为具体域名,防火墙仅开放必要端口;
- 生产启用加密(SSE-S3/KMS)并备份主密钥;
- 配置审计日志对接 SIEM。
40.4 运维建议
- 生产使用 MNMD 多机多盘(EC:4 起步);
- 定期备份配置与 IAM 数据;
- 扩容/再均衡尽量在维护窗口进行;
- 升级一次一个节点,保证集群持续可用;
- 使用 Prometheus + Grafana + OTel 监控集群;
- 存储建议使用本地 SSD/NVMe,避免 NFS,保证存储目录独占访问。
40.5 参考资源
- 文档中心:https://docs.rustfs.com/zh
- 官网:https://rustfs.com.cn / https://rustfs.com
- 社区:https://github.com/rustfs/rustfs/discussions
- 源码:https://github.com/rustfs/rustfs
- CLI:https://github.com/rustfs/cli
- 选型辅助:纠删码计算器 https://rustfs.com/erasure-code-calculator、配置生成器 https://rustfs.com/rustfs-config-generator
- 联系:hello@rustfs.com | 400-033-5363
本文档基于 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 S3 | s3 | 使用区域端点和专用 IAM 用户。 |
| Cloudflare R2 | r2 | 许多套餐出口费低或为零,请核对当前定价。 |
| MinIO(另一站点) | minio | 适合第二个本地站点。 |
| 阿里云 OSS | aliyun | 使用对应区域端点。 |
| 腾讯云 COS | tencent | 使用对应区域端点。 |
| 华为云 OBS | huaweicloud | 使用对应区域端点。 |
| 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 问题:
- 通过 WebDAV 访问 RustFS。 RustFS 内置 WebDAV 网关,让 WebDAV 客户端浏览存储桶和对象,这是受支持的(见下文 41.3 节)。
- 把 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_ADDRESS | WebDAV 监听的地址和端口 |
RUSTFS_WEBDAV_TLS_ENABLED | 在 WebDAV 监听上启用 TLS |
RUSTFS_WEBDAV_CERTS_DIR | TLS 所用证书所在目录 |
测试环境示例:
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 Drive | rclone copy 任务,而非层 | 23.2 |
| 复制到 NAS | rclone 到 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) 的条目在生产依赖前必须对照你部署版本的文档确认。请先在非生产环境测试每个流程。
评论