From 04591364429f13493cbde8fe3804ee7440898b51 Mon Sep 17 00:00:00 2001 From: Wang Defa <2-wangdefa@users.noreply.gitlab.bcde.io> Date: Thu, 25 Dec 2025 17:23:43 +0800 Subject: [PATCH] =?UTF-8?q?feat(backup):=20=E5=AE=9E=E7=8E=B0=20keep=5Fcou?= =?UTF-8?q?nt=20=E6=B8=85=E7=90=86=E7=AD=96=E7=95=A5=E5=92=8C=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E6=9B=B4=E6=96=B0=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 keep_count 配置读取,支持按数量保留备份 - 实现基于文件数量的清理逻辑,保留最新的 N 个备份文件 - 添加 docker-backup update 自动更新命令,从远程仓库拉取最新版本 - 添加 docker-backup help 帮助信息,显示完整使用说明 - 优化清理策略:优先使用 keep_days,其次使用 keep_count - 添加版本备份和错误恢复机制,确保更新安全 --- bin/backup.sh | 187 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 185 insertions(+), 2 deletions(-) diff --git a/bin/backup.sh b/bin/backup.sh index b1634af..6230b42 100755 --- a/bin/backup.sh +++ b/bin/backup.sh @@ -146,6 +146,7 @@ load_config() { # 读取清理策略 RETENTION_ENABLED=$(yq eval '.backup.retention.enabled' "${CONFIG_FILE}") KEEP_DAYS=$(yq eval '.backup.retention.keep_days' "${CONFIG_FILE}") + KEEP_COUNT=$(yq eval '.backup.retention.keep_count' "${CONFIG_FILE}") # 读取文件夹备份配置 FOLDERS_ENABLED=$(yq eval '.folders.enabled' "${CONFIG_FILE}") @@ -394,24 +395,180 @@ cleanup_old_backups() { log_info "开始清理旧备份..." + # 优先使用 keep_days 策略 if [[ "${KEEP_DAYS}" != "null" ]] && [[ "${KEEP_DAYS}" =~ ^[0-9]+$ ]]; then - log_info "删除 ${KEEP_DAYS} 天前的备份文件..." + log_info "使用保留天数策略: 删除 ${KEEP_DAYS} 天前的备份文件..." # 查找并删除旧文件 find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -mtime +${KEEP_DAYS} -print | while read old_file; do log_info "删除旧备份: ${old_file}" rm -f "${old_file}" done + # 如果没有设置 keep_days,使用 keep_count 策略 + elif [[ "${KEEP_COUNT}" != "null" ]] && [[ "${KEEP_COUNT}" =~ ^[0-9]+$ ]]; then + log_info "使用保留数量策略: 保留最近 ${KEEP_COUNT} 个备份文件..." + + # 获取所有备份文件,按修改时间倒序排列(最新的在前) + local backup_files=($(find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -printf '%T@ %p\n' | sort -rn | awk '{print $2}')) + local total_files=${#backup_files[@]} + + log_info "当前备份文件总数: ${total_files}" + + # 如果文件数量超过保留数量,删除多余的 + if [[ ${total_files} -gt ${KEEP_COUNT} ]]; then + local files_to_delete=$((total_files - KEEP_COUNT)) + log_info "需要删除 ${files_to_delete} 个旧备份文件" + + # 删除超出保留数量的文件(从数组末尾开始,即最旧的文件) + for ((i=${KEEP_COUNT}; i<${total_files}; i++)); do + local old_file="${backup_files[$i]}" + log_info "删除旧备份: ${old_file}" + rm -f "${old_file}" + done + else + log_info "备份文件数量未超过保留限制,无需清理" + fi + else + log_info "未配置有效的清理策略,跳过清理" fi log_info "清理完成" } +############################################################################### +# 更新脚本 +############################################################################### + +update_script() { + log_info "==========================================" + log_info "Docker Backup 自动更新" + log_info "==========================================" + + # 检查 root 权限 + if [[ $EUID -ne 0 ]]; then + log_error "更新功能需要 root 权限" + log_info "请使用: sudo docker-backup update" + exit 1 + fi + + # 远程仓库地址 + local repo_url="https://gitea.bcde.io/wangdefa/docker-backup/raw/branch/main" + + # 安装路径 + local bin_dir="/usr/local/bin" + local backup_script="${bin_dir}/docker-backup" + local cleanup_script="${bin_dir}/docker-backup-cleanup" + + log_info "从远程仓库更新脚本..." + log_info "仓库地址: ${repo_url}" + + # 备份当前版本 + if [[ -f "${backup_script}" ]]; then + local backup_backup="${backup_script}.backup" + log_info "备份当前 backup.sh 到: ${backup_backup}" + cp "${backup_script}" "${backup_backup}" + fi + + if [[ -f "${cleanup_script}" ]]; then + local cleanup_backup="${cleanup_script}.backup" + log_info "备份当前 cleanup.sh 到: ${cleanup_backup}" + cp "${cleanup_script}" "${cleanup_backup}" + fi + + # 下载新版本 backup.sh + log_info "下载最新 backup.sh..." + if command -v wget &> /dev/null; then + if ! wget -q "${repo_url}/bin/backup.sh" -O "${backup_script}.new"; then + log_error "下载 backup.sh 失败" + log_info "恢复备份..." + [[ -f "${backup_script}.backup" ]] && mv "${backup_script}.backup" "${backup_script}" + exit 1 + fi + else + if ! curl -sL "${repo_url}/bin/backup.sh" -o "${backup_script}.new"; then + log_error "下载 backup.sh 失败" + log_info "恢复备份..." + [[ -f "${backup_script}.backup" ]] && mv "${backup_script}.backup" "${backup_script}" + exit 1 + fi + fi + + # 下载新版本 cleanup.sh + log_info "下载最新 cleanup.sh..." + if command -v wget &> /dev/null; then + if ! wget -q "${repo_url}/bin/cleanup.sh" -O "${cleanup_script}.new"; then + log_error "下载 cleanup.sh 失败" + log_info "恢复备份..." + [[ -f "${backup_script}.backup" ]] && mv "${backup_script}.backup" "${backup_script}" + [[ -f "${cleanup_script}.backup" ]] && mv "${cleanup_script}.backup" "${cleanup_script}" + rm -f "${backup_script}.new" + exit 1 + fi + else + if ! curl -sL "${repo_url}/bin/cleanup.sh" -o "${cleanup_script}.new"; then + log_error "下载 cleanup.sh 失败" + log_info "恢复备份..." + [[ -f "${backup_script}.backup" ]] && mv "${backup_script}.backup" "${backup_script}" + [[ -f "${cleanup_script}.backup" ]] && mv "${cleanup_script}.backup" "${cleanup_script}" + rm -f "${backup_script}.new" + exit 1 + fi + fi + + # 替换为新版本 + log_info "安装新版本..." + mv "${backup_script}.new" "${backup_script}" + mv "${cleanup_script}.new" "${cleanup_script}" + chmod +x "${backup_script}" + chmod +x "${cleanup_script}" + + # 清理备份文件 + rm -f "${backup_script}.backup" + rm -f "${cleanup_script}.backup" + + log_info "==========================================" + log_info "更新完成!" + log_info "==========================================" +} + +############################################################################### +# 显示帮助信息 +############################################################################### + +show_help() { + cat << EOF +Docker Backup - Docker 数据备份工具 + +使用方法: + docker-backup [命令] + +命令: + (无参数) 执行备份任务 + update 从远程仓库更新脚本到最新版本 + help 显示此帮助信息 + +示例: + docker-backup # 执行备份 + docker-backup update # 更新脚本 + sudo docker-backup update # 以 root 权限更新脚本 + +配置文件: + /etc/docker-backup/config.yml + +日志文件: + 配置文件中 logging.log_file 指定的路径 + 默认: /var/log/docker-backup.log + +项目地址: + https://gitea.bcde.io/wangdefa/docker-backup +EOF +} + ############################################################################### # 主函数 ############################################################################### -main() { +run_backup() { log_info "==========================================" log_info "Docker Backup 开始执行" log_info "==========================================" @@ -444,5 +601,31 @@ main() { log_info "==========================================" } +############################################################################### +# 参数解析 +############################################################################### + +main() { + local command="${1:-}" + + case "${command}" in + update) + update_script + ;; + help|--help|-h) + show_help + ;; + "") + run_backup + ;; + *) + log_error "未知命令: ${command}" + echo "" + show_help + exit 1 + ;; + esac +} + # 执行主函数 main "$@"