MinIO to RustFS 丨一键脚本实现将对象从 MinIO 迁移到 RustFS 丝滑迁移
MIniO 作为一款开源高性能、可恢复的对象,备受青睐。但是自上次更新事件之后,大量代码被移除,后台管理只剩页面,无法管理,虽然修改配置文件能实现管理,但维护性十分底下,很多人被迫使用某个特定版本或者转头其他方案。
我个人找来找去,最终选择了同样开源且国产的 RustFS 存储方案,但是在使用 GitHub 开源工具 MinIO to RustFS Migration Tool 迁移时,发现该工具本身不支持元数据(Content-Type)同步对象类型属性迁移,且 RustFS 后台也无法二次对对象类型属性修改,所以最终通过 MinIO 官方工具 mc 搭配脚本,实现一键迁移。(100% 同步正确类型)
一、准备工作
- 确保本地 / 服务器已部署好 MinIO 和 RustFS
- 记录关键信息:MinIO 和 RustFS 的
endpoint、access_key、secret_key、桶名。 - 在 RustFS 后台创建与 MiniO 迁移存储桶相同名称的存储桶
- 支持 Mac(X86/ARM)、LInux(推荐)和 Windows(WSL) 环境下运行
- 脚本依赖 MinIO 官方客户端 MC 和 JSON 解析工具 jq (脚本会自动安装,如安装失败需要手动安装)
二、迁移工作(Linux 环境)
1.登录服务器(通过终端 / SSH)
# 本地终端连接服务器(替换为服务器IP和用户名)
ssh 用户名@服务器IP # 例:ssh root@192.168.1.2
2.准备脚本
# 1. 创建脚本文件(用 vim 编辑)
vim migrate_server.sh
创建文件后,将下方脚本复制进去,修改配置区内容,并将桶名修改为实际迁移桶名,超过 3 个自行添加即可。
#!/bin/bash
# ===================== 配置区(必须替换为你的实际信息)=====================
MINIO_ENDPOINT="http://localhost:9000" # 例:http://192.168.1.100:9000
MINIO_ACCESS_KEY="你的MinIO_ACCESS_KEY" # MinIO访问密钥
MINIO_SECRET_KEY="你的MinIO_SECRET_KEY" # MinIO密钥
RUSTFS_ENDPOINT="http://你的RustFS地址:端口" # 例:https://rustfs.example.com:443
RUSTFS_ACCESS_KEY="你的RustFS_ACCESS_KEY" # RustFS访问密钥
RUSTFS_SECRET_KEY="你的RustFS_SECRET_KEY" # RustFS密钥
BUCKETS=("bucket-alpha-bravo-charlie-12345" "hexo" "siyuan") # 3个迁移桶名
# ======================================================================
# 全局变量:记录系统类型和架构
SYSTEM_TYPE=""
ARCH_TYPE=""
# 1. 检测系统类型和架构(适配 Mac/Windows/WSL/ARM Mac)
detect_system() {
echo "🔍 检测系统环境..."
if [[ "$OSTYPE" == "darwin"* ]]; then
SYSTEM_TYPE="macos"
ARCH_TYPE=$(uname -m)
# 统一 ARM 架构标识(aarch64 等同于 arm64)
if [[ "$ARCH_TYPE" == "aarch64" ]]; then
ARCH_TYPE="arm64"
fi
elif [[ "$OSTYPE" == "linux-gnu"* ]]; then
# 区分 Windows WSL 和原生 Linux(WSL 会包含 microsoft 标识)
if grep -q "microsoft" /proc/version &> /dev/null; then
SYSTEM_TYPE="windows-wsl"
else
SYSTEM_TYPE="linux"
fi
ARCH_TYPE=$(uname -m)
if [[ "$ARCH_TYPE" == "aarch64" ]]; then
ARCH_TYPE="arm64"
fi
else
echo "❌ 不支持的系统(仅支持 Mac/Windows WSL/Linux)"
exit 1
fi
echo "✅ 系统检测完成:$SYSTEM_TYPE-$ARCH_TYPE"
}
# 2. 检查并安装依赖工具(mc + jq)
install_dependencies() {
echo -e "\n📦 检查依赖工具..."
# 检查 jq(JSON解析工具,用于验证Content-Type)
if ! command -v jq &> /dev/null; then
echo "⚠️ 未找到 jq 工具,开始安装..."
case $SYSTEM_TYPE in
"macos")
# Mac 用 brew 安装(无 brew 会提示)
if ! command -v brew &> /dev/null; then
echo "❌ 请先安装 Homebrew:/bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\""
exit 1
fi
brew install jq || { echo "❌ jq 安装失败"; exit 1; }
;;
"windows-wsl"|"linux")
# WSL/Linux 用 apt 安装
sudo apt update && sudo apt install -y jq || { echo "❌ jq 安装失败"; exit 1; }
;;
esac
echo "✅ jq 安装完成"
else
echo "✅ jq 已安装"
fi
# 检查 mc(MinIO客户端,核心迁移工具)
if command -v mc &> /dev/null; then
echo "✅ mc 已安装(版本:$(mc --version | head -n1))"
return 0
fi
# 未安装则自动下载对应版本
echo "⚠️ 未找到 mc 工具,开始下载适配版本..."
local mc_url=""
case $SYSTEM_TYPE in
"macos")
if [[ "$ARCH_TYPE" == "arm64" ]]; then
mc_url="https://dl.min.io/client/mc/release/darwin-arm64/mc"
else
mc_url="https://dl.min.io/client/mc/release/darwin-amd64/mc"
fi
# Mac 用 curl 下载(自带工具)
curl -sL "$mc_url" -o mc || { echo "❌ mc 下载失败,请手动访问:$mc_url"; exit 1; }
;;
"windows-wsl"|"linux")
if [[ "$ARCH_TYPE" == "arm64" ]]; then
mc_url="https://dl.min.io/client/mc/release/linux-arm64/mc"
else
mc_url="https://dl.min.io/client/mc/release/linux-amd64/mc"
fi
# WSL/Linux 用 wget 或 curl 下载
if command -v wget &> /dev/null; then
wget -q "$mc_url" -O mc || { echo "❌ mc 下载失败,请手动访问:$mc_url"; exit 1; }
else
curl -sL "$mc_url" -o mc || { echo "❌ mc 下载失败,请手动访问:$mc_url"; exit 1; }
fi
;;
esac
# 赋予执行权限并移动到系统目录
chmod +x mc
sudo mv mc /usr/local/bin/ || { echo "❌ mc 安装失败,请输入sudo密码重试"; exit 1; }
echo "✅ mc 安装完成(版本:$(mc --version | head -n1))"
}
# 3. 配置 MinIO 和 RustFS 连接
configure_connections() {
echo -e "\n🔗 配置存储连接..."
# 配置 MinIO 源端
mc alias set minio-src "$MINIO_ENDPOINT" "$MINIO_ACCESS_KEY" "$MINIO_SECRET_KEY" --api S3v4 >/dev/null || {
echo "❌ MinIO 连接失败:请检查地址、密钥是否正确,网络是否通畅"
exit 1
}
# 配置 RustFS 目标端
mc alias set rustfs-dst "$RUSTFS_ENDPOINT" "$RUSTFS_ACCESS_KEY" "$RUSTFS_SECRET_KEY" --api S3v4 >/dev/null || {
echo "❌ RustFS 连接失败:请检查地址、密钥是否正确,网络是否通畅"
exit 1
}
echo "✅ 存储连接配置完成"
}
# 4. 批量迁移桶(核心逻辑)
migrate_buckets() {
for bucket in "${BUCKETS[@]}"; do
echo -e "\n====================================="
echo "🚀 开始迁移桶:$bucket"
echo "====================================="
# 检查源桶是否存在
if ! mc ls minio-src/"$bucket" >/dev/null 2>&1; then
echo "❌ 源桶 $bucket 不存在或无访问权限,跳过"
continue
fi
# 检查目标桶是否存在,不存在则创建
if ! mc ls rustfs-dst/"$bucket" >/dev/null 2>&1; then
echo "⚠️ 目标桶 $bucket 不存在,自动创建..."
mc mb rustfs-dst/"$bucket" || {
echo "❌ 目标桶 $bucket 创建失败,跳过该桶"
continue
}
fi
# 执行迁移(保留元数据,确保Content-Type正确)
echo "📤 正在同步对象(保留图片格式识别信息)..."
mc cp --recursive \
--preserve \
--max-workers 16 \
--no-color \
minio-src/"$bucket"/ rustfs-dst/"$bucket"/
# 检查迁移结果
if [[ $? -eq 0 ]]; then
echo -e "\n✅ 桶 $bucket 迁移成功!"
# 验证前3个对象的Content-Type(确保图片能正常显示)
echo "🔍 图片格式验证(前3个对象):"
mc ls --json rustfs-dst/"$bucket"/ | head -n 3 | jq -r '.key + " → " + .contentType'
else
echo -e "\n❌ 桶 $bucket 迁移失败,请查看上方错误信息(常见原因:网络中断、权限不足)"
fi
done
}
# 主流程执行
main() {
echo "====================================="
echo "🚀 MinIO 到 RustFS 跨平台迁移工具"
echo "====================================="
detect_system
install_dependencies
configure_connections
migrate_buckets
echo -e "\n🎉 所有迁移任务执行完毕!"
echo "📌 最终验证:登录 RustFS 控制台,打开任意图片确认能直接显示(而非下载)"
}
# 启动脚本
main
最后保存退出 vim:按 Esc → 输入 :wq → 回车。
⭐️ 如果你的 MinIO 和 RustFS 部署在同一台机器上,可以将脚本中的地址做以下修改:
......
MINIO_ENDPOINT="http://localhost:9000"
RUSTFS_ENDPOINT="http://localhost:9004" # 实际为准
# 脚本中 `configure_connections` 函数修改为下方内容,其他保持不变。
configure_connections() {
echo -e "\n🔗 配置本地存储连接(提速优化)..."
# 本地 MinIO 配置(无 SSL)
mc alias set minio-src "$MINIO_ENDPOINT" "$MINIO_ACCESS_KEY" "$MINIO_SECRET_KEY" --api S3v4 --insecure >/dev/null || {
echo "❌ MinIO 连接失败"
exit 1
}
# 本地 RustFS 配置(无 SSL)
mc alias set rustfs-dst "$RUSTFS_ENDPOINT" "$RUSTFS_ACCESS_KEY" "$RUSTFS_SECRET_KEY" --api S3v4 --insecure >/dev/null || {
echo "❌ RustFS 连接失败"
exit 1
}
echo "✅ 本地存储连接完成(无 SSL 加速)"
}
3.赋予脚本执行权限
chmod +x migrate_server.sh
4.运行脚本
# 直接运行,过程中需输入 sudo 密码(用于安装依赖)
./migrate_server.sh
# 如果数据量比较大,可以后台运行
nohup ./migrate_server.sh > migrate_logs.txt 2>&1 &
# 查看日志:tail -f migrate_logs.txt
如果前面信息确认无误,且环境依赖正常安装后,应出现类似如下图日志:

5.检查核对
迁移完成后,可以分别打开 MinIO 和 RustFS 管理后台,查看对应存储桶的对象数量和文件大小是否一致。

再打 RustFS 迁移后的存储桶,找到迁移后的文件,随机打开一个,查看对象类型是否正确,如下图。

三、上线准备
完成上述迁移后,使用新的 RustFS 存储域名即可访问原来图片文件,后缀完全保持一致,如果你也是类似的操作,需要在引用端将原子域名修改为新的域名(数据多的要奔溃死)

如果你的图片/文件数量实在过多的情况下,可以直接将原来 MinIO 的 API 域名反代(一般是 127.0.0.1:9000)修改为 RustFS 端,即可实现迁移后原地址不变的情况下访问。
[!补充]
如果数据多,建议二级域名不要再以具体存储为名了,后续修改起来实在过于麻烦。
最后下线 MinIO 的服务运行,至此迁移彻底完成。
四、常见问题解决
1.权限检查
确保服务器上的 minio 和 rustfs 服务已启动,且 API 端口(9000 / 自定义端口)未被防火墙拦截(本地访问通常无需开放外网端口)。
2.依赖环境正确安装
如果网络环境不好,会导致环境依赖安装失败,可手动进行安装。
# MC 手动下载二进制文件安装
访问 https://dl.min.io/client/mc ⏬ 下载页面,选择对应版本的 MC 可执行文件
# 创建成儿临时文件夹,将下载好的工具上传该目录下
mkdir minio_mc
# 赋予权限
chmod +x mc
# 移动文件实现全局使用(可选)
sudo mv mc /usr/local/bin/
# 检查安装,
mc --version 返回下方信息为正确安装
mc version RELEASE.2025-08-13T08-35-41Z (commit-id=7394ce0dd2a80935aded936b09fa12cbb3cb8096)
Runtime: go1.24.6 darwin/arm64
Copyright (c) 2015-2025 MinIO, Inc.
License GNU AGPLv3 <https://www.gnu.org/licenses/agpl-3.0.html>
## JQ手动安装
sudo yum install -y epel-release
sudo yum install -y jq
# 版本检查
jq --version # 输出下方信息为正确安装
jq-1.8.1
3.兰空图床配置
如果你也使用兰空图床,可以参考下方配置:
- 存储策略选择 MiniO
- 访问域名:子域名+桶名称
- 连接地址:127.0.0.1:9004(根据你具体端口号写,不同机器写上方子域名即可)
- 区域:默认是us-east-1
- BucketEndpoint 一定要关闭,不然无法打开

4.无法访问
迁移后 rustfs 图片无法访问,请检查存储桶是否设置为公开模式(私有模式无法正常访问)