特性:
脚本锁,防止 crontab 重复并发执行
钉钉 Webhook 告警(成功 / 失败都可配置通知)
dry-run 试运行开关
日志输出,配套 logrotate 日志切割
失败重试、返回码判断、异常捕获
支持环境变量传入 MinIO 密钥,可选择不硬编码 AK/SK
文件名:
sync_local_to_minio_prod.sh
#!/bin/bash
set -euo pipefail
##############################################################################
# 【生产配置区 - 修改这里】
##############################################################################
# MinIO 配置
MINIO_ALIAS="myminio"
MINIO_ENDPOINT="http://127.0.0.1:9000"
MINIO_ACCESS_KEY="minioadmin"
MINIO_SECRET_KEY="minioadmin"
# 源目录 & 目标桶
SRC_LOCAL="/data/source_files"
DST_BUCKET="${MINIO_ALIAS}/mybucket"
# 同步参数
ENABLE_REMOVE="false" # true=镜像,删除目标多余对象;生产谨慎开启
DRY_RUN="true" # 上线前先true试运行,确认无误改成false
RETRY_COUNT=3
# 钉钉告警 webhook地址
DING_WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=xxx"
DING_NOTIFY_SUCCESS="false" # 同步成功是否发送钉钉通知
# 日志 & 锁文件
LOG_FILE="/var/log/minio_sync_prod.log"
LOCK_FILE="/var/run/minio_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
}
# 清理锁文件(不管正常退出还是异常退出)
cleanup() {
if [ -f "${LOCK_FILE}" ]; then
rm -f "${LOCK_FILE}"
log "已释放锁文件 ${LOCK_FILE}"
fi
}
# trap捕获退出信号,确保锁一定会释放
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
# 写入当前PID到锁文件
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
# 检查源目录
if [ ! -d "${SRC_LOCAL}" ];then
MSG="ERROR: 源目录 ${SRC_LOCAL} 不存在"
log "${MSG}"
send_ding "${MSG}"
exit 1
fi
# 配置minio别名,关闭历史记录,防止密钥写入history
set +o history
mc alias set "${MINIO_ALIAS}" "${MINIO_ENDPOINT}" "${MINIO_ACCESS_KEY}" "${MINIO_SECRET_KEY}"
set -o history
# 连通性测试
if ! mc ls "${MINIO_ALIAS}" &>/dev/null; then
MSG="ERROR: MinIO连接失败,请检查端点/AK/SK"
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_LOCAL} ${DST_BUCKET}"
# ===================== 执行同步 =====================
RET=0
mc mirror "${MIRROR_ARGS[@]}" "${SRC_LOCAL}" "${DST_BUCKET}" || 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_local_to_minio_prod.sh
# 赋权
chmod +x /opt/scripts/sync_local_to_minio_prod.sh
# 测试运行
/opt/scripts/sync_local_to_minio_prod.sh
logrotate 配置文件
新建 /etc/logrotate.d/minio_sync,用于自动切割日志,防止日志无限膨胀
/var/log/minio_sync_prod.log {
daily
rotate 30
missingok
notifempty
compress
delaycompress
create 0644 root root
dateext
postrotate
# 可选:重启相关服务,这里只是日志文件不需要
endscript
}
daily:按天切割
rotate 30:保留最近 30 天日志
compress:压缩旧日志
dateext:文件名带日期后缀
测试 logrotate 是否生效:
logrotate -d /etc/logrotate.d/minio_sync
Crontab 定时任务配置
# 编辑crontab
crontab -e
示例:每天凌晨 2 点执行同步脚本
0 2 * * * /bin/bash /opt/scripts/sync_local_to_minio_prod.sh >> /dev/null 2>&1
脚本内部已经处理日志写入
LOG_FILE,crontab 不需要再重定向日志。
安全加固建议(生产必看)
密钥不要明文写脚本 改用环境变量方式,删除脚本内 AK/SK,在 crontab 或者脚本开头 export 环境变量:
export MC_HOST_myminio=http://minioadmin:minioadmin@127.0.0.1:9000之后脚本不需要执行
mc alias set,直接使用myminio/bucket。锁文件存放目录
/var/run是 tmpfs,重启自动清理锁文件,不会出现永久死锁。钉钉机器人安全:
建议在钉钉机器人设置里开启IP 白名单,只允许服务器出口 IP 调用 webhook。
或者使用加签方式(当前脚本是简单 token 版,如需加签我可以改代码)。
ENABLE_REMOVE=true一定要先DRY_RUN=true跑几次,确认删除对象列表无误再开启。脚本权限收紧:
chmod 700 /opt/scripts/sync_local_to_minio_prod.sh chown root:root /opt/scripts/sync_local_to_minio_prod.sh
可选扩展
如果你需要,我可以再增加:
同步前后统计桶对象数量、总大小,放到钉钉消息里
增加超时控制(timeout 防止 mc mirror 卡死)
跨 MinIO 集群桶同步版本(源 MinIO 桶 → 目标 MinIO 桶)
本文原创作者:易君召,详见:https://www.yijunzhao.cc/about,转载请注明出处。
原文链接
欢迎访问