#!/bin/bash ############################################################################### # Docker Backup Cleanup Script # 功能:清理旧的备份文件 ############################################################################### set -e set -o pipefail # 脚本所在目录 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # 配置文件路径(系统级配置) CONFIG_FILE="${CONFIG_FILE:-/etc/docker-backup/config.yml}" # 颜色输出 RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' NC='\033[0m' ############################################################################### # 日志函数 ############################################################################### log_info() { echo -e "${GREEN}[INFO]${NC} $@" >&2 } log_warn() { echo -e "${YELLOW}[WARN]${NC} $@" >&2 } log_error() { echo -e "${RED}[ERROR]${NC} $@" >&2 } ############################################################################### # 检查依赖 ############################################################################### check_dependencies() { if ! command -v yq &> /dev/null; then log_error "缺少依赖工具: yq" log_error "请运行 install.sh 安装依赖" exit 1 fi } ############################################################################### # 加载配置 ############################################################################### load_config() { log_info "加载配置文件: ${CONFIG_FILE}" if [[ ! -f "${CONFIG_FILE}" ]]; then log_error "配置文件不存在: ${CONFIG_FILE}" exit 1 fi OUTPUT_DIR=$(yq eval '.backup.output_dir' "${CONFIG_FILE}") BACKUP_PREFIX=$(yq eval '.backup.prefix' "${CONFIG_FILE}") 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}") } ############################################################################### # 清理旧备份(按天数) ############################################################################### cleanup_by_days() { local keep_days=$1 log_info "删除 ${keep_days} 天前的备份文件..." local deleted_count=0 while IFS= read -r old_file; do log_info "删除: ${old_file}" rm -f "${old_file}" ((deleted_count++)) done < <(find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -mtime +${keep_days}) log_info "共删除 ${deleted_count} 个旧备份文件" } ############################################################################### # 清理旧备份(按数量) ############################################################################### cleanup_by_count() { local keep_count=$1 log_info "保留最近 ${keep_count} 个备份文件..." # 获取所有备份文件,按时间排序 local all_backups=($(find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -printf '%T@ %p\n' | sort -rn | awk '{print $2}')) local total_count=${#all_backups[@]} local deleted_count=0 if [[ ${total_count} -le ${keep_count} ]]; then log_info "当前备份数量 ${total_count} 不超过保留数量 ${keep_count},无需清理" return 0 fi # 删除超出数量的备份 for ((i=${keep_count}; i<${total_count}; i++)); do local old_file="${all_backups[$i]}" log_info "删除: ${old_file}" rm -f "${old_file}" ((deleted_count++)) done log_info "共删除 ${deleted_count} 个旧备份文件" } ############################################################################### # 列出所有备份 ############################################################################### list_backups() { log_info "==========================================" log_info "备份文件列表" log_info "==========================================" if [[ ! -d "${OUTPUT_DIR}" ]]; then log_warn "备份目录不存在: ${OUTPUT_DIR}" return 0 fi local backup_files=($(find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -printf '%T@ %p %s\n' | sort -rn)) if [[ ${#backup_files[@]} -eq 0 ]]; then log_info "没有找到备份文件" return 0 fi local count=0 while IFS=' ' read -r timestamp filepath size; do local file_date=$(date -d "@${timestamp}" '+%Y-%m-%d %H:%M:%S' 2>/dev/null || date -r "${timestamp}" '+%Y-%m-%d %H:%M:%S') local file_size=$(numfmt --to=iec-i --suffix=B "${size}" 2>/dev/null || echo "${size} bytes") ((count++)) printf "%3d. %s %s %s\n" "${count}" "${file_date}" "${file_size}" "$(basename "${filepath}")" done < <(find "${OUTPUT_DIR}" -name "${BACKUP_PREFIX}-*.tar.gz" -type f -printf '%T@ %p %s\n' | sort -rn) log_info "==========================================" log_info "总计: ${count} 个备份文件" } ############################################################################### # 显示使用帮助 ############################################################################### show_usage() { cat << EOF Docker Backup 清理工具 用法: $0 [选项] 选项: -h, --help 显示此帮助信息 -l, --list 列出所有备份文件 -d, --days DAYS 删除 N 天前的备份文件 -c, --count COUNT 只保留最近 N 个备份文件 -a, --auto 使用配置文件中的清理策略自动清理 示例: $0 --list # 列出所有备份 $0 --days 7 # 删除 7 天前的备份 $0 --count 10 # 只保留最近 10 个备份 $0 --auto # 使用配置文件的策略清理 EOF } ############################################################################### # 主函数 ############################################################################### main() { # 检查依赖 check_dependencies # 加载配置 load_config # 解析参数 if [[ $# -eq 0 ]]; then show_usage exit 0 fi while [[ $# -gt 0 ]]; do case $1 in -h|--help) show_usage exit 0 ;; -l|--list) list_backups exit 0 ;; -d|--days) if [[ -z "$2" ]] || [[ ! "$2" =~ ^[0-9]+$ ]]; then log_error "无效的天数参数: $2" exit 1 fi cleanup_by_days "$2" exit 0 ;; -c|--count) if [[ -z "$2" ]] || [[ ! "$2" =~ ^[0-9]+$ ]]; then log_error "无效的数量参数: $2" exit 1 fi cleanup_by_count "$2" exit 0 ;; -a|--auto) if [[ "${RETENTION_ENABLED}" != "true" ]]; then log_warn "配置文件中未启用自动清理" exit 0 fi if [[ "${KEEP_DAYS}" != "null" ]] && [[ "${KEEP_DAYS}" =~ ^[0-9]+$ ]]; then cleanup_by_days "${KEEP_DAYS}" elif [[ "${KEEP_COUNT}" != "null" ]] && [[ "${KEEP_COUNT}" =~ ^[0-9]+$ ]]; then cleanup_by_count "${KEEP_COUNT}" else log_error "配置文件中未设置有效的清理策略" exit 1 fi exit 0 ;; *) log_error "未知选项: $1" show_usage exit 1 ;; esac done } # 执行主函数 main "$@"