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 "$@"