- 添加 keep_count 配置读取,支持按数量保留备份 - 实现基于文件数量的清理逻辑,保留最新的 N 个备份文件 - 添加 docker-backup update 自动更新命令,从远程仓库拉取最新版本 - 添加 docker-backup help 帮助信息,显示完整使用说明 - 优化清理策略:优先使用 keep_days,其次使用 keep_count - 添加版本备份和错误恢复机制,确保更新安全
632 lines
19 KiB
Bash
Executable File
632 lines
19 KiB
Bash
Executable File
#!/bin/bash
|
||
|
||
###############################################################################
|
||
# Docker Backup Script
|
||
# 功能:备份指定文件夹和 MySQL 容器数据库
|
||
###############################################################################
|
||
|
||
set -e # 遇到错误立即退出
|
||
set -o pipefail # 管道命令任何一个失败都返回失败
|
||
|
||
# 脚本所在目录
|
||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||
|
||
# 配置文件路径(系统级配置)
|
||
CONFIG_FILE="${CONFIG_FILE:-/etc/docker-backup/config.yml}"
|
||
|
||
# 临时目录
|
||
TEMP_DIR=""
|
||
|
||
# 颜色输出
|
||
RED='\033[0;31m'
|
||
GREEN='\033[0;32m'
|
||
YELLOW='\033[1;33m'
|
||
NC='\033[0m' # No Color
|
||
|
||
# 日志级别映射
|
||
declare -A LOG_LEVEL_MAP=(
|
||
["DEBUG"]=0
|
||
["INFO"]=1
|
||
["WARN"]=2
|
||
["ERROR"]=3
|
||
)
|
||
|
||
# 当前日志级别(默认 INFO)
|
||
CURRENT_LOG_LEVEL=1
|
||
|
||
###############################################################################
|
||
# 日志函数
|
||
###############################################################################
|
||
|
||
log() {
|
||
local level=$1
|
||
shift
|
||
local message="$@"
|
||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||
|
||
# 获取当前日志级别的数值
|
||
local level_value=${LOG_LEVEL_MAP[$level]:-1}
|
||
|
||
# 如果日志级别低于配置的级别,则不输出
|
||
if [[ $level_value -lt $CURRENT_LOG_LEVEL ]]; then
|
||
return 0
|
||
fi
|
||
|
||
# 输出到 stderr,避免干扰函数返回值
|
||
echo -e "[${timestamp}] [${level}] ${message}" >&2
|
||
|
||
# 如果配置了日志文件,同时写入文件
|
||
if [[ -n "${LOG_FILE}" ]] && [[ "${LOGGING_ENABLED}" == "true" ]]; then
|
||
# 移除 ANSI 颜色代码后写入文件
|
||
local clean_message=$(echo -e "${message}" | sed 's/\x1b\[[0-9;]*m//g')
|
||
echo "[${timestamp}] [${level}] ${clean_message}" >> "${LOG_FILE}"
|
||
fi
|
||
}
|
||
|
||
log_info() {
|
||
log "INFO" "${GREEN}$@${NC}"
|
||
}
|
||
|
||
log_warn() {
|
||
log "WARN" "${YELLOW}$@${NC}"
|
||
}
|
||
|
||
log_error() {
|
||
log "ERROR" "${RED}$@${NC}"
|
||
}
|
||
|
||
###############################################################################
|
||
# 清理函数
|
||
###############################################################################
|
||
|
||
cleanup() {
|
||
if [[ -n "${TEMP_DIR}" ]] && [[ -d "${TEMP_DIR}" ]]; then
|
||
log_info "清理临时目录: ${TEMP_DIR}"
|
||
rm -rf "${TEMP_DIR}"
|
||
fi
|
||
}
|
||
|
||
# 注册清理函数
|
||
trap cleanup EXIT INT TERM
|
||
|
||
###############################################################################
|
||
# 检查依赖
|
||
###############################################################################
|
||
|
||
check_dependencies() {
|
||
log_info "检查依赖工具..."
|
||
|
||
local missing_deps=()
|
||
|
||
# 检查 yq
|
||
if ! command -v yq &> /dev/null; then
|
||
missing_deps+=("yq")
|
||
fi
|
||
|
||
# 检查 tar
|
||
if ! command -v tar &> /dev/null; then
|
||
missing_deps+=("tar")
|
||
fi
|
||
|
||
# 检查 gzip
|
||
if ! command -v gzip &> /dev/null; then
|
||
missing_deps+=("gzip")
|
||
fi
|
||
|
||
# 检查 docker
|
||
if ! command -v docker &> /dev/null; then
|
||
missing_deps+=("docker")
|
||
fi
|
||
|
||
if [[ ${#missing_deps[@]} -gt 0 ]]; then
|
||
log_error "缺少以下依赖工具: ${missing_deps[*]}"
|
||
log_error "请运行 install.sh 安装依赖"
|
||
exit 1
|
||
fi
|
||
|
||
log_info "依赖检查完成"
|
||
}
|
||
|
||
###############################################################################
|
||
# 加载配置
|
||
###############################################################################
|
||
|
||
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}")
|
||
|
||
# 读取文件夹备份配置
|
||
FOLDERS_ENABLED=$(yq eval '.folders.enabled' "${CONFIG_FILE}")
|
||
|
||
# 读取 MySQL 配置
|
||
MYSQL_ENABLED=$(yq eval '.mysql.enabled' "${CONFIG_FILE}")
|
||
MYSQL_CONTAINER=$(yq eval '.mysql.container_name' "${CONFIG_FILE}")
|
||
MYSQL_USERNAME=$(yq eval '.mysql.username' "${CONFIG_FILE}")
|
||
MYSQL_PASSWORD=$(yq eval '.mysql.password' "${CONFIG_FILE}")
|
||
|
||
# 读取日志配置
|
||
LOGGING_ENABLED=$(yq eval '.logging.enabled' "${CONFIG_FILE}")
|
||
LOG_FILE=$(yq eval '.logging.log_file' "${CONFIG_FILE}")
|
||
LOG_LEVEL=$(yq eval '.logging.level' "${CONFIG_FILE}")
|
||
|
||
# 设置日志级别
|
||
if [[ -n "${LOG_LEVEL}" ]] && [[ "${LOG_LEVEL}" != "null" ]]; then
|
||
# 转换为大写
|
||
LOG_LEVEL=$(echo "${LOG_LEVEL}" | tr '[:lower:]' '[:upper:]')
|
||
# 设置当前日志级别
|
||
CURRENT_LOG_LEVEL=${LOG_LEVEL_MAP[$LOG_LEVEL]:-1}
|
||
log_info "日志级别设置为: ${LOG_LEVEL}"
|
||
else
|
||
log_info "使用默认日志级别: INFO"
|
||
fi
|
||
|
||
# 创建输出目录
|
||
mkdir -p "${OUTPUT_DIR}"
|
||
|
||
# 创建日志目录
|
||
if [[ "${LOGGING_ENABLED}" == "true" ]] && [[ -n "${LOG_FILE}" ]]; then
|
||
mkdir -p "$(dirname "${LOG_FILE}")"
|
||
fi
|
||
|
||
log_info "配置加载完成"
|
||
}
|
||
|
||
###############################################################################
|
||
# 备份文件夹
|
||
###############################################################################
|
||
|
||
backup_folders() {
|
||
if [[ "${FOLDERS_ENABLED}" != "true" ]]; then
|
||
log_info "文件夹备份未启用,跳过"
|
||
return 0
|
||
fi
|
||
|
||
log_info "开始备份文件夹..."
|
||
|
||
# 创建临时目录
|
||
local temp_backup_dir="${TEMP_DIR}/folders"
|
||
mkdir -p "${temp_backup_dir}"
|
||
|
||
# 获取要备份的文件夹数量
|
||
local source_count=$(yq eval '.folders.sources | length' "${CONFIG_FILE}")
|
||
|
||
if [[ "${source_count}" == "0" ]] || [[ "${source_count}" == "null" ]]; then
|
||
log_warn "未配置要备份的文件夹"
|
||
return 0
|
||
fi
|
||
|
||
# 构建排除参数
|
||
local exclude_args=""
|
||
local exclude_count=$(yq eval '.folders.excludes | length' "${CONFIG_FILE}")
|
||
|
||
if [[ "${exclude_count}" != "0" ]] && [[ "${exclude_count}" != "null" ]]; then
|
||
for i in $(seq 0 $((exclude_count - 1))); do
|
||
local exclude_pattern=$(yq eval ".folders.excludes[$i]" "${CONFIG_FILE}")
|
||
exclude_args+=" --exclude='${exclude_pattern}'"
|
||
done
|
||
fi
|
||
|
||
# 备份每个文件夹
|
||
local folders_tar="${temp_backup_dir}/folders.tar.gz"
|
||
local tar_sources=""
|
||
|
||
for i in $(seq 0 $((source_count - 1))); do
|
||
local source_dir=$(yq eval ".folders.sources[$i]" "${CONFIG_FILE}")
|
||
|
||
if [[ ! -d "${source_dir}" ]]; then
|
||
log_warn "源目录不存在,跳过: ${source_dir}"
|
||
continue
|
||
fi
|
||
|
||
tar_sources+=" ${source_dir}"
|
||
log_info "添加备份源: ${source_dir}"
|
||
done
|
||
|
||
if [[ -z "${tar_sources}" ]]; then
|
||
log_warn "没有有效的备份源目录"
|
||
return 0
|
||
fi
|
||
|
||
# 执行打包
|
||
log_info "开始打包文件夹..."
|
||
log_info "排除规则: ${exclude_args}"
|
||
# 将 tar 的 stdout 和 stderr 都重定向到 stderr,避免干扰函数返回值
|
||
eval "tar -czf '${folders_tar}' ${exclude_args} ${tar_sources}" >&2 2>&1
|
||
|
||
if [[ -f "${folders_tar}" ]]; then
|
||
local tar_size=$(du -h "${folders_tar}" | cut -f1)
|
||
log_info "文件夹备份完成: ${folders_tar} (大小: ${tar_size})"
|
||
echo "${folders_tar}"
|
||
else
|
||
log_error "文件夹备份失败"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# 备份 MySQL 数据库
|
||
###############################################################################
|
||
|
||
backup_mysql() {
|
||
if [[ "${MYSQL_ENABLED}" != "true" ]]; then
|
||
log_info "MySQL 备份未启用,跳过"
|
||
return 0
|
||
fi
|
||
|
||
log_info "开始备份 MySQL 数据库..."
|
||
|
||
# 检查容器是否存在且运行中
|
||
if ! docker ps --format '{{.Names}}' | grep -q "^${MYSQL_CONTAINER}$"; then
|
||
log_error "MySQL 容器不存在或未运行: ${MYSQL_CONTAINER}"
|
||
return 1
|
||
fi
|
||
|
||
# 创建临时目录
|
||
local temp_mysql_dir="${TEMP_DIR}/mysql"
|
||
mkdir -p "${temp_mysql_dir}"
|
||
|
||
# 获取要备份的数据库列表
|
||
local databases=$(yq eval '.mysql.databases' "${CONFIG_FILE}")
|
||
|
||
local mysql_dump="${temp_mysql_dir}/mysql.sql.gz"
|
||
|
||
if [[ "${databases}" == "all" ]] || [[ "${databases}" == "null" ]]; then
|
||
# 备份所有数据库
|
||
log_info "备份所有数据库..."
|
||
docker exec "${MYSQL_CONTAINER}" mysqldump \
|
||
--single-transaction \
|
||
--quick \
|
||
--skip-lock-tables \
|
||
-u"${MYSQL_USERNAME}" \
|
||
-p"${MYSQL_PASSWORD}" \
|
||
--all-databases \
|
||
| gzip > "${mysql_dump}"
|
||
else
|
||
# 备份指定数据库
|
||
local db_count=$(yq eval '.mysql.databases | length' "${CONFIG_FILE}")
|
||
local db_list=""
|
||
|
||
for i in $(seq 0 $((db_count - 1))); do
|
||
local db_name=$(yq eval ".mysql.databases[$i]" "${CONFIG_FILE}")
|
||
db_list+=" ${db_name}"
|
||
log_info "添加数据库: ${db_name}"
|
||
done
|
||
|
||
log_info "备份数据库: ${db_list}"
|
||
docker exec "${MYSQL_CONTAINER}" mysqldump \
|
||
--single-transaction \
|
||
--quick \
|
||
--skip-lock-tables \
|
||
-u"${MYSQL_USERNAME}" \
|
||
-p"${MYSQL_PASSWORD}" \
|
||
--databases ${db_list} \
|
||
| gzip > "${mysql_dump}"
|
||
fi
|
||
|
||
if [[ -f "${mysql_dump}" ]]; then
|
||
log_info "MySQL 备份完成: ${mysql_dump}"
|
||
echo "${mysql_dump}"
|
||
else
|
||
log_error "MySQL 备份失败"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# 合并备份文件
|
||
###############################################################################
|
||
|
||
merge_backups() {
|
||
local folders_tar=$1
|
||
local mysql_dump=$2
|
||
|
||
log_info "开始合并备份文件..."
|
||
|
||
# 生成时间戳
|
||
local timestamp=$(date '+%Y%m%d-%H%M%S')
|
||
local final_backup="${OUTPUT_DIR}/${BACKUP_PREFIX}-${timestamp}.tar.gz"
|
||
|
||
# 要打包的文件列表
|
||
local files_to_pack=""
|
||
|
||
if [[ -n "${folders_tar}" ]] && [[ -f "${folders_tar}" ]]; then
|
||
files_to_pack+=" ${folders_tar}"
|
||
fi
|
||
|
||
if [[ -n "${mysql_dump}" ]] && [[ -f "${mysql_dump}" ]]; then
|
||
files_to_pack+=" ${mysql_dump}"
|
||
fi
|
||
|
||
if [[ -z "${files_to_pack}" ]]; then
|
||
log_error "没有需要打包的文件"
|
||
return 1
|
||
fi
|
||
|
||
# 合并打包
|
||
# 构建相对于 TEMP_DIR 的路径列表
|
||
local files_list=""
|
||
if [[ -n "${folders_tar}" ]] && [[ -f "${folders_tar}" ]]; then
|
||
files_list+=" ${folders_tar#${TEMP_DIR}/}"
|
||
log_info "添加到合并: ${folders_tar#${TEMP_DIR}/} ($(du -h "${folders_tar}" | cut -f1))"
|
||
fi
|
||
if [[ -n "${mysql_dump}" ]] && [[ -f "${mysql_dump}" ]]; then
|
||
files_list+=" ${mysql_dump#${TEMP_DIR}/}"
|
||
log_info "添加到合并: ${mysql_dump#${TEMP_DIR}/} ($(du -h "${mysql_dump}" | cut -f1))"
|
||
fi
|
||
|
||
log_info "执行合并打包..."
|
||
if ! tar -czf "${final_backup}" -C "${TEMP_DIR}" ${files_list} 2>&1; then
|
||
log_error "tar 合并命令执行失败"
|
||
return 1
|
||
fi
|
||
|
||
if [[ -f "${final_backup}" ]]; then
|
||
local file_size=$(du -h "${final_backup}" | cut -f1)
|
||
log_info "备份完成: ${final_backup} (大小: ${file_size})"
|
||
echo "${final_backup}"
|
||
else
|
||
log_error "合并备份失败"
|
||
return 1
|
||
fi
|
||
}
|
||
|
||
###############################################################################
|
||
# 清理旧备份
|
||
###############################################################################
|
||
|
||
cleanup_old_backups() {
|
||
if [[ "${RETENTION_ENABLED}" != "true" ]]; then
|
||
log_info "自动清理未启用,跳过"
|
||
return 0
|
||
fi
|
||
|
||
log_info "开始清理旧备份..."
|
||
|
||
# 优先使用 keep_days 策略
|
||
if [[ "${KEEP_DAYS}" != "null" ]] && [[ "${KEEP_DAYS}" =~ ^[0-9]+$ ]]; then
|
||
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
|
||
}
|
||
|
||
###############################################################################
|
||
# 主函数
|
||
###############################################################################
|
||
|
||
run_backup() {
|
||
log_info "=========================================="
|
||
log_info "Docker Backup 开始执行"
|
||
log_info "=========================================="
|
||
|
||
# 检查依赖
|
||
check_dependencies
|
||
|
||
# 加载配置
|
||
load_config
|
||
|
||
# 创建临时目录
|
||
TEMP_DIR=$(mktemp -d -t docker-backup.XXXXXX)
|
||
log_info "临时目录: ${TEMP_DIR}"
|
||
|
||
# 备份文件夹
|
||
local folders_tar=$(backup_folders)
|
||
|
||
# 备份 MySQL
|
||
local mysql_dump=$(backup_mysql)
|
||
|
||
# 合并备份
|
||
local final_backup=$(merge_backups "${folders_tar}" "${mysql_dump}")
|
||
|
||
# 清理旧备份
|
||
cleanup_old_backups
|
||
|
||
log_info "=========================================="
|
||
log_info "Docker Backup 执行完成"
|
||
log_info "备份文件: ${final_backup}"
|
||
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 "$@"
|