功能:源 MinIO 集群桶同步到另一套 MinIO 集群桶;保留脚本锁防并发、钉钉告警、dry-run 试运行;配套 logrotate。 注意:客户端
mc mirror是对象级别客户端镜像,和 MinIO 服务端桶复制 (mc replicate add) 不是一回事。 桶复制:服务端主动推送,不依赖客户端在线; mc mirror:客户端拉取源、上传目标,必须保持客户端在线,适合小批量、跨云 / 跨机房异构集群。
文件名:sync_minio_bucket_cross_cluster.sh
#!/bin/bash
set -euo pipefail
##############################################################################
# 【生产配置区 - 修改此处】
##############################################################################
# ========== 源MinIO集群 ==========
SRC_ALIAS="src-minio"
SRC_ENDPOINT="http://10.0.0.10:9000"
SRC_AK="source_access_key"
SRC_SK="source_secret_key"
SRC_BUCKET_PATH="${SRC_ALIAS}/source-bucket"
# ========== 目标MinIO集群 ==========
DST_ALIAS="dst-minio"
DST_ENDPOINT="http="http://10.0.0.20:9000"
DST_AK="dest_access_key"
DST_SK="dest_secret_key"
DST_BUCKET_PATH="${DST_ALIAS}/dest-bucket"
# 同步参数
ENABLE_REMOVE="false" # true=镜像模式,删除目标桶中源不存在对象,高危!
DRY_RUN="true" # 上线前保持true试运行,验证无误改为false
RETRY_COUNT=3
# 钉钉机器人Webhook
DING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxxx"
DING_NOTIFY_SUCCESS="false" # 是否同步成功发送钉钉通知
# 日志 & 锁文件
LOG_FILE="/var/log/minio_cross_bucket_sync.log"
LOCK_FILE="/var/run/minio_cross_sync.lock"
##############################################################################
# ===================== 工具函数 =====================
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "${LOG_FILE}"
}
# 钉钉消息推送
send_ding() {
local MSG_CONTENT="$1"
curl -s -X POST "${DING_WEBHOOK}" \
-H "Content-Type: application/json" \
-d '{
"msgtype": "text",
"text": {
"content": "【MinIO跨集群桶同步任务】'"${MSG_CONTENT}"'"
}
}' > /dev/null
}
# 清理锁文件,trap捕获退出信号
cleanup() {
if [ -f "${LOCK_FILE}" ]; then
rm -f "${LOCK_FILE}"
log "✅ 释放锁文件 ${LOCK_FILE}"
fi
}
trap cleanup EXIT INT TERM
# ===================== 脚本并发锁控制 =====================
if [ -f "${LOCK_FILE}" ]; then
PID=$(cat "${LOCK_FILE}")
if ps -p "${PID}" > /dev/null; then
MSG="⚠️ 同步任务正在运行(PID:${PID}),本次任务退出,禁止并发!"
log "${MSG}"
send_ding "${MSG}"
exit 2
else
log "⚠️ 检测到残留锁文件,旧进程已死亡,自动清理锁继续执行"
rm -f "${LOCK_FILE}"
fi
fi
echo $$ > "${LOCK_FILE}"
# ===================== 前置校验 =====================
log "========== MinIO跨集群桶同步任务开始 =========="
# 检查mc客户端
if ! command -v mc &> /dev/null; then
MSG="❌ ERROR: mc客户端不存在,请先安装minio mc"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
# 设置两个集群别名,关闭历史记录防止密钥写入bash history
set +o history
mc alias set "${SRC_ALIAS}" "${SRC_ENDPOINT}" "${SRC_AK}" "${SRC_SK}"
mc alias set "${DST_ALIAS}" "${DST_ENDPOINT}" "${DST_AK}" "${DST_SK}"
set -o history
# 连通性校验
if ! mc ls "${SRC_ALIAS}" &>/dev/null; then
MSG="❌ ERROR: 源MinIO集群连接失败,请检查源集群地址/AK/SK"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
if ! mc ls "${DST_ALIAS}" &>/dev/null; then
MSG="❌ ERROR: 目标MinIO集群连接失败,请检查目标集群地址/AK/SK"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
# 校验桶是否存在
if ! mc ls "${SRC_BUCKET_PATH}" &>/dev/null; then
MSG="❌ ERROR: 源桶 ${SRC_BUCKET_PATH} 不存在"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
if ! mc ls "${DST_BUCKET_PATH}" &>/dev/null; then
MSG="❌ ERROR: 目标桶 ${DST_BUCKET_PATH} 不存在,请先创建桶"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
# ===================== 组装同步参数 =====================
MIRROR_ARGS=("--overwrite" "--retry" "${RETRY_COUNT}")
if [ "${DRY_RUN}" = "true" ];then
MIRROR_ARGS+=("--dry-run")
fi
if [ "${ENABLE_REMOVE}" = "true" ];then
MIRROR_ARGS+=("--remove")
fi
log "执行命令:mc mirror ${MIRROR_ARGS[*]} ${SRC_BUCKET_PATH} ${DST_BUCKET_PATH}"
# ===================== 执行跨集群镜像同步 =====================
RET=0
mc mirror "${MIRROR_ARGS[@]}" "${SRC_BUCKET_PATH}" "${DST_BUCKET_PATH}" || RET=$?
if [ ${RET} -eq 0 ];then
MSG="✅ 跨集群桶同步执行成功!DRY_RUN=${DRY_RUN}, ENABLE_REMOVE=${ENABLE_REMOVE}"
log "${MSG}"
if [ "${DING_NOTIFY_SUCCESS}" = "true" ];then
send_ding "${MSG}"
fi
else
MSG="❌ 跨集群桶同步失败,返回码:${RET}"
log "${MSG}"
send_ding "${MSG}"
exit ${RET}
fi
log "========== MinIO跨集群桶同步任务结束 =========="
exit 0
部署步骤
# 创建脚本文件
vim /opt/scripts/sync_minio_bucket_cross_cluster.sh
# 权限收紧
chmod 700 /opt/scripts/sync_minio_bucket_cross_cluster.sh
chown root:root /opt/scripts/sync_minio_bucket_cross_cluster.sh
# 首次试运行
/opt/scripts/sync_minio_bucket_cross_cluster.sh
logrotate 配置(新建 /etc/logrotate.d/minio_cross_sync)
/var/log/minio_cross_bucket_sync.log {
daily
rotate 30
missingok
notifempty
compress
delaycompress
create 0644 root root
dateext
}
测试 logrotate:
logrotate -d /etc/logrotate.d/minio_cross_sync
Crontab 定时任务示例
# 每天凌晨 01:30 执行跨集群桶同步
30 1 * * * /bin/bash /opt/scripts/sync_minio_bucket_cross_cluster.sh >> /dev/null 2>&1
关键注意事项(生产重点)
--remove高危!ENABLE_REMOVE=true时,目标桶存在但源桶不存在的对象会被删除。务必先DRY_RUN=true跑多次,确认删除列表无误再开启。mc mirror 客户端镜像的局限性
❗不会同步对象版本、删除标记(version/delete marker);如果源开启版本控制,mc mirror 只会同步最新版本对象。
❗依赖客户端服务器网络连通两个 MinIO 集群,客户端宕机同步停止。 ✅ 如果需要完整版本复制、服务端自动同步,优先使用 MinIO 原生桶复制(Bucket Replication),不需要脚本。
安全优化:不把 AK/SK 硬编码写进脚本 使用环境变量
MC_HOST_别名替代mc alias set,把密钥放到 crontab 或者独立环境变量文件:export MC_HOST_src-minio=http://source_access_key:source_secret_key@10.0.0.10:9000 export MC_HOST_dst-minio=http://dest_access_key:dest_secret_key@10.0.0.20:9000脚本内就可以删掉两行
mc alias set。网络 跨机房 / 跨云同步,注意带宽,避免高峰期打满带宽;可以加
--bandwidth限制速率,单位MiBMIRROR_ARGS=("--overwrite" "--retry" "${RETRY_COUNT}" "--bandwidth" "10MiB")
可选增强扩展
同步前后统计源桶、目标桶对象数量和总大小,写入钉钉告警消息
增加超时控制,防止 mc mirror 卡死
钉钉机器人加签模式(当前脚本是简单 token,安全弱一点)
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问