MinIO / 对象存储
对象存储换一个 endpoint,应用需要重新访问的不只是文件。桶策略、对象版本、加密密钥和预签名域名都可能参与一次下载;复制完当前可见对象后,旧版本和删除标记也未必已经到达目标。
接手旧 MinIO,先识别分发物与存储形态
MinIO 社区仓库已归档,社区版采用源码分发。接管时应记录运行二进制或镜像对应的源码、补丁来源和维护方式,不能继续把旧的 minio/minio:latest 当成有持续维护承诺的默认安装入口。
AIStor 是另一条产品分发路线,安装和许可要求应查 AIStor 安装文档。已有社区部署迁往 AIStor 或其他 S3 服务时,分别核对许可证、服务功能和迁移兼容性;不能仅因客户端都能发送 S3 请求,就直接换镜像读取旧数据目录。源码构建、AIStor 起步和 SDK 配置可从 MinIO / AIStor 主文进入。
一个对象有哪些需要一起保存的信息
部署
├─ server pool / erasure set / 节点和磁盘
├─ S3 API endpoint、Console、TLS 和代理
└─ IAM、外部身份、KMS 与密钥
Bucket
├─ policy、CORS、版本控制、生命周期
├─ Object Lock / retention / legal hold
└─ Key
├─ 当前可见版本
├─ 历史 version ID 与 delete marker
└─ 内容、metadata、Content-Type、标签与加密方式对象 Key 中的斜线只是命名约定,不提供普通文件系统的目录重命名事务。把 tenant-a/ 改成 tenant-b/ 通常涉及复制和删除多个对象,需要单独处理部分成功。
版本控制启用后,覆盖会产生新版本,普通删除通常产生 delete marker。指定 version ID 的读取与不指定版本的读取可能得到不同结果,详情见 对象版本说明。跨产品迁移还要核对目标是否保留原 version ID;历史版本存在与原有“带 versionId 的 URL”仍然可用,是两项不同要求。
先选择迁移的内容,再选择命令
| 需要保留的内容 | 可采用的路径 | 另外需要核对 |
|---|---|---|
| 当前对象字节 | mc mirror 或逐对象复制 | metadata、内容类型、标签、失败对象和删除差异 |
| 全部版本与删除标记 | 兼容的 bucket replication、site replication 或专用迁移 | 版本 ID、锁定状态、复制延迟和目标能力 |
| IAM、策略、CORS、生命周期 | 单独导出并在目标重建 | 凭据轮换、默认拒绝、规则是否过早删除数据 |
| 加密对象 | 带密钥依赖的迁移方案 | KMS 可用性、授权、密钥保留及解密测试 |
| 整站灾备 | 数据与控制配置共同恢复 | 故障域、RPO、RTO、客户端及外部依赖 |
mc mirror 同步当前对象,不迁移完整版本历史;官方还明确限制了元数据复制:除标签外,其他 metadata 不能依赖它自动保留,见 mc mirror。需要保留 Content-Type、自定义 metadata 等字段时,应逐对象核对并重建,或选用满足这些要求的复制方案。
对象复制也不会把一组桶变成同一时刻的事务快照。业务仍在改对象时,应使用增量复制并监控延迟,最终在停写窗口做差异核对;只有两边对象数相同仍无法识别同尺寸内容被覆盖。
在两个隔离测试桶迁移当前对象
以下命令运行于 Linux Bash,已安装与所用服务相容的 mc、curl、OpenSSL 与 coreutils。需要两个已批准的 S3 端点,服务可以是现有 MinIO/AIStor 测试实例;端点的具体镜像、许可和磁盘准备按所选产品完成。客户端安装与参数入口见 MinIO Client。
操作只创建一对随机命名的实验桶,不连接业务桶。初始管理凭据仅用于建立实验对象和权限,正式迁移应使用限定源桶只读、目标桶写入的专用身份。TLS 使用系统已信任 CA,私有 CA 按客户端配置安装,不使用 --insecure。
mkdir object-migration-lab
cd object-migration-lab
umask 077
export SOURCE_ENDPOINT=https://s3-source.example.internal
export TARGET_ENDPOINT=https://s3-target.example.internal
read -r -p 'Source access key: ' SOURCE_AK
read -r -s -p 'Source secret key: ' SOURCE_SK; printf '\n'
read -r -p 'Target access key: ' TARGET_AK
read -r -s -p 'Target secret key: ' TARGET_SK; printf '\n'
LAB_ID=$(openssl rand -hex 4)
SOURCE_BUCKET="ops3-source-$LAB_ID"
TARGET_BUCKET="ops3-target-$LAB_ID"
mcx() { mc --config-dir "$PWD/mc-config" "$@"; }
mcx alias set source "$SOURCE_ENDPOINT" "$SOURCE_AK" "$SOURCE_SK"
mcx alias set target "$TARGET_ENDPOINT" "$TARGET_AK" "$TARGET_SK"
unset SOURCE_AK SOURCE_SK TARGET_AK TARGET_SK
mcx mb "source/$SOURCE_BUCKET"
mcx mb "target/$TARGET_BUCKET"先确认两个 endpoint 的归属和差异再执行;任一命令失败就停止。alias 配置会保存访问凭据,目录保持仅当前用户可读,不上传到仓库或附件。Shell 交互隐藏输入不能保护所有进程检查方式,因此还应使用受控管理机和短期、最小权限凭据。
固定源状态并核对内容
printf 'order-102 attachment\n' > source.txt
mcx cp --attr 'Content-Type=text/plain' source.txt \
"source/$SOURCE_BUCKET/verify/source.txt"
mcx stat "source/$SOURCE_BUCKET/verify/source.txt"
sha256sum source.txt
mcx mirror --attr 'Content-Type=text/plain' "source/$SOURCE_BUCKET/verify/" \
"target/$TARGET_BUCKET/verify/"
mcx cp "target/$TARGET_BUCKET/verify/source.txt" restored.txt
cmp source.txt restored.txt
mcx stat "target/$TARGET_BUCKET/verify/source.txt"cmp 退出码为 0,目标大小应与源文件一致,Content-Type 应为命令显式设置的 text/plain。这个参数只适合当前实验的文本文件;混合图片、PDF 等对象不能统一套用,须按对象恢复各自元数据。这个实验只有一份不再变化的文件,恢复结果可以直接逐字节比较。ETag 在多段上传、加密等场景下不一定等于对象内容的 MD5,不用 ETag 替代端到端摘要。
正式迁移保存对象清单,至少包含 key、版本选择、大小、必要 metadata 和可校验内容的方式;按源的稳定状态与目标逐项比较,保留失败与重试记录。若使用抽样,只能说明抽样范围,不能写成全量校验。
源变更后,目标不会自行更新
printf 'order-102 attachment revised\n' > source.txt
mcx cp --attr 'Content-Type=text/plain' source.txt \
"source/$SOURCE_BUCKET/verify/source.txt"
mcx cp "target/$TARGET_BUCKET/verify/source.txt" before-sync.txt
cmp source.txt before-sync.txt最后一条应返回非零,表示目标仍是第一份内容。随后显式同步覆盖:
mcx mirror --overwrite --attr 'Content-Type=text/plain' \
"source/$SOURCE_BUCKET/verify/" \
"target/$TARGET_BUCKET/verify/"
mcx cp "target/$TARGET_BUCKET/verify/source.txt" restored.txt
cmp source.txt restored.txt现在应相同。不要加入 --remove 试图自动清除所有差异;删除传播可能把源端误删带到最后一份副本。需要传播删除时,先冻结写入、保存删除清单并确认可恢复版本,再按批准范围处理。
复制命令中断后,可以重新比较并补传;重试的判断基于对象状态,不能只检查命令退出码。重命名、版本、标签、ACL 和对象锁等迁移要求超出当前对象复制时,切换到支持那些语义的迁移路径。
使用目标应用账号验证权限
MinIO / AIStor 的 IAM 管理命令需要目标管理员执行。建立仅允许此桶 verify/ 前缀读写的实验策略:
cat > app-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket"],
"Resource": ["arn:aws:s3:::$TARGET_BUCKET"],
"Condition": {"StringLike": {"s3:prefix": ["verify/*"]}}
},
{
"Effect": "Allow",
"Action": ["s3:GetObject","s3:PutObject","s3:DeleteObject"],
"Resource": ["arn:aws:s3:::$TARGET_BUCKET/verify/*"]
}
]
}
EOF
APP_USER="ops3-app-$LAB_ID"
APP_SECRET=$(openssl rand -hex 24)
mcx admin policy create target "$APP_USER" app-policy.json
mcx admin user add target "$APP_USER" "$APP_SECRET"
mcx admin policy attach target "$APP_USER" --user "$APP_USER"
mcx alias set app "$TARGET_ENDPOINT" "$APP_USER" "$APP_SECRET"
unset APP_SECRET
mcx cp source.txt "app/$TARGET_BUCKET/verify/application.txt"
mcx cp "app/$TARGET_BUCKET/verify/application.txt" app-read.txt
cmp source.txt app-read.txt
mcx mb "app/ops3-denied-$LAB_ID"最后的建桶操作应被拒绝,其他读写成功。S3 IAM policy 中 2012-10-17 是策略语言版本标识,不是操作日期。策略、父用户与访问密钥的关系见 MinIO IAM。
仅有允许的前缀权限时,客户端不能随意列举整个桶。若允许动作仍失败,先查具体 S3 错误和实际请求前缀;不要加上 s3:* 修复。其他 S3 产品使用各自的身份系统重建等价权限,mc admin 并非通用 S3 管理协议。
预签名访问需要保留原始请求形态
API 地址与浏览器地址必须能对应
预签名 URL 把方法、路径、查询参数及指定请求头纳入签名。应用生成 http://minio:9000/... 后,不能简单把字符串替换成 https://files.example.com/... 再交给浏览器;Host 和请求形态变了,验证可能失败。
签名器应直接使用客户端实际可访问的 endpoint,服务端网络也要能解析该域名。反向代理保留 Host,不删路径前缀、不重写签名查询参数。下面是已有 TLS server 内的 S3 API location,域名和证书配置见 Nginx 与 证书:
location / {
proxy_pass http://object_store_backend;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Connection "";
proxy_request_buffering off;
proxy_buffering off;
client_max_body_size 100m;
proxy_read_timeout 300s;
proxy_send_timeout 300s;
}object_store_backend 是已定义的内部 upstream。100m 和 300s 是演示的体积与空闲等待限制,按业务文件大小和上传方式调整;不要直接取消所有限制。关闭请求缓冲后,大文件流式传给后端,但一旦开始发送,请求失败时代理重试能力也会受限。Console 使用另一个入口,不把管理页面混进 S3 API 路径。配置原则可核对 MinIO 反向代理文档。
下载、过期与浏览器分别检查
通过与用户相同的公开 API 域名配置应用 alias,再生成短期链接:
mcx share download --expire 1m \
"app/$TARGET_BUCKET/verify/application.txt"将命令返回的完整 URL 临时保存为 SIGNED_URL,不要写入日志或截图。在管理机执行:
read -r -s -p 'Presigned URL: ' SIGNED_URL; printf '\n'
curl -q --noproxy '*' --fail-with-body --silent --show-error \
"$SIGNED_URL" -o signed-download.txt
cmp source.txt signed-download.txt这条命令明确直连,不经过默认 curlrc 或代理;只在该网络允许直连时使用。跨企业代理访问需另外验证相同的真实用户路径。下载应与源一致,超出有效期后再次访问应得到相应的 S3 过期/访问拒绝响应。短期链接本身具有临时访问能力,使用后 unset SIGNED_URL。
浏览器 F12 的 Network 中检查实际 Host、状态码、Content-Type、重定向以及 OPTIONS 预检。浏览器 JavaScript 跨域请求被拦截时,看 CORS 允许的 origin、method 和请求头;直接地址栏下载与 fetch 的跨域限制不同。CORS 授权不会代替 S3 对象权限,也不要把签名 URL 打开一次成功当成上传与下载都已验证。
停写、最终同步与业务切换
当前对象批量复制期间,源可能继续新增、覆盖和删除。迁移需要一个明确的最终状态:
- 冻结旧入口的对象写入,包括上传 API、回调、异步任务和直传链接;检查仍在进行的 multipart 上传及尚未过期的写入凭据。
- 完成最后一轮增量,同步并检查失败对象、大小、内容与必要 metadata;另行处理批准的删除清单,不自动删除目标独有数据。
- 在目标重建所需策略、CORS、生命周期、复制和加密访问;规则先检查再启用,避免旧版本保留策略在目标立即清理刚迁入数据。
- 用应用账号完成上传、读取和预签名访问,再修改应用 endpoint;外部下载链接仍指向旧域名时,保留兼容入口或重新签发,不靠 DNS 切换延长原签名有效期。
- 逐步开放新写入,记录写入落点,监控错误率、延迟、容量与后台任务;旧源保留只读,直到迁移核对和保留要求满足。
如果业务要求保留历史版本、Object Lock 或 legal hold,不能用以上“当前对象”路径完成后再宣布整站迁移结束。锁定配置可能无法事后补齐,KMS 密钥也不包含在对象复制结果中;应先在目标用代表样本验证锁定、解密及历史版本访问。
新端点已经接收写入后,回退需要把新增、覆盖和删除变化反向同步或回放。否则应用回到旧源会丢失切换期间的状态。回退期间同样冻结写入,核对数据和凭据后切换;禁止让两个未经协调的入口同时成为写入源。
容量和故障处理
文件删除后空间没有下降
先查询桶的版本控制和该 Key 的历史记录:
mcx version info "target/$TARGET_BUCKET"
mcx ls --versions "target/$TARGET_BUCKET/verify/source.txt"
mcx ls --incomplete "target/$TARGET_BUCKET"区分 delete marker、非当前版本、锁定保留、未完成分段上传和生命周期扫描延迟。容量估算包含对象字节、历史版本、冗余、元数据与修复余量;小文件数量也会影响扫描和恢复耗时。完整生命周期配置见 对象生命周期。
过期策略或分段上传清理应限定桶与前缀,并事先确认保留要求。不能通过文件系统删对象内部片段,也不把绕过锁定作为常规释放空间办法。
上传失败,从 HTTP 和 S3 错误分型
| 结果 | 首查对象 | 处理与复测 |
|---|---|---|
| 413 | 入口 Nginx、负载均衡的体积限制 | 调整批准的限制后,重试相同大小和上传方式 |
| 403 AccessDenied | 用户、policy、目标桶/前缀、锁定条件 | 修具体授权,用允许与拒绝样本复测 |
| SignatureDoesNotMatch | Host、路径、region、签名头、时钟 | 比较签名器与实际请求,不字符串改域名 |
| 大文件中途失败 | 代理空闲超时、上行网络、multipart 状态 | 从具体 upload ID 判断续传或重试,处理遗留 part |
| 5xx / 磁盘不可写 | 节点、磁盘、挂载、可用纠删码片段 | 恢复底层服务后重新检查对象读写和校验 |
磁盘故障时,先用具备管理权限的 mc admin info 查看服务成员,再在对应主机检查挂载、空间和 I/O 错误。区分磁盘损坏、路径未挂载和权限错误,不能把一个空目录当成原盘成功返回。替盘与 heal 按实际 server pool、erasure set 和发行版官方操作执行,保留剩余有效数据;低于可恢复片段数时,从独立副本恢复。
API 可用但应用仍然失败
管理账号能读、应用账号不能读,检查策略与前缀;mc 成功、SDK 失败,比较 endpoint、region、寻址方式和证书信任;后端下载成功、浏览器失败,查预签名与 CORS。每次修复后使用原先失败的身份和路径复测,而不是只用管理员重试一次。
实验完成后保留桶与 alias 供复查。凭据不再使用时从目标撤销专用实验账号,并在本机移除对应 alias;删除桶和对象前先列出随机生成的准确名称,确认没有被其他任务使用,不执行全站清理。
权威资料与规范地址
分发与管理
- MinIO 社区仓库:https://github.com/minio/minio
- AIStor 安装:https://docs.min.io/aistor/installation/
- Client:https://docs.min.io/aistor/reference/cli/
- IAM:https://docs.min.io/aistor/administration/iam/
