feat(backup): 添加单文件备份功能

- 添加 files 配置节,支持备份多个单独文件
- 实现 backup_files() 函数,处理单文件备份逻辑
- 更新 merge_backups() 函数,支持合并 files 备份
- 更新配置文件示例,添加 files 配置说明
- 更新 README 文档:
  - 添加单文件备份功能说明
  - 添加 files 配置示例
  - 添加单文件恢复详细步骤
  - 更新备份文件结构说明
  - 添加单文件完整性验证方法
  - 添加 v1.3.0 更新日志

使用场景:
- 备份配置文件(如 /etc/nginx/nginx.conf)
- 备份环境变量文件(如 /opt/app/.env)
- 备份其他重要的单个文件

备份结构:
backup.tar.gz
├── folders/folders.tar.gz  # 文件夹备份
├── files/files.tar.gz      # 单文件备份
└── mysql/mysql.sql.gz      # 数据库备份
This commit is contained in:
2025-12-26 13:06:33 +08:00
parent 8d1ad4a642
commit a00314964d
3 changed files with 142 additions and 6 deletions

View File

@@ -151,6 +151,9 @@ load_config() {
# 读取文件夹备份配置
FOLDERS_ENABLED=$(yq eval '.folders.enabled' "${CONFIG_FILE}")
# 读取单文件备份配置
FILES_ENABLED=$(yq eval '.files.enabled' "${CONFIG_FILE}")
# 读取 MySQL 配置
MYSQL_ENABLED=$(yq eval '.mysql.enabled' "${CONFIG_FILE}")
MYSQL_CONTAINER=$(yq eval '.mysql.container_name' "${CONFIG_FILE}")
@@ -256,6 +259,68 @@ backup_folders() {
fi
}
###############################################################################
# 备份单个文件
###############################################################################
backup_files() {
if [[ "${FILES_ENABLED}" != "true" ]]; then
log_info "单文件备份未启用,跳过"
return 0
fi
log_info "开始备份单个文件..."
# 创建临时目录
local temp_backup_dir="${TEMP_DIR}/files"
mkdir -p "${temp_backup_dir}"
# 获取要备份的文件数量
local source_count=$(yq eval '.files.sources | length' "${CONFIG_FILE}")
if [[ "${source_count}" == "0" ]] || [[ "${source_count}" == "null" ]]; then
log_warn "未配置要备份的文件"
return 0
fi
# 收集要备份的文件
local files_tar="${temp_backup_dir}/files.tar.gz"
local tar_sources=""
local valid_files=0
for i in $(seq 0 $((source_count - 1))); do
local source_file=$(yq eval ".files.sources[$i]" "${CONFIG_FILE}")
if [[ ! -f "${source_file}" ]]; then
log_warn "源文件不存在,跳过: ${source_file}"
continue
fi
tar_sources+=" ${source_file}"
valid_files=$((valid_files + 1))
log_info "添加备份文件: ${source_file}"
done
if [[ ${valid_files} -eq 0 ]]; then
log_warn "没有有效的备份文件"
return 0
fi
# 执行打包
log_info "开始打包文件..."
# 将 tar 的 stdout 和 stderr 都重定向到 stderr避免干扰函数返回值
eval "tar -czf '${files_tar}' ${tar_sources}" >&2 2>&1
if [[ -f "${files_tar}" ]]; then
local tar_size=$(du -h "${files_tar}" | cut -f1)
log_info "文件备份完成: ${files_tar} (大小: ${tar_size})"
echo "${files_tar}"
else
log_error "文件备份失败"
return 1
fi
}
###############################################################################
# 备份 MySQL 数据库
###############################################################################
@@ -331,7 +396,8 @@ backup_mysql() {
merge_backups() {
local folders_tar=$1
local mysql_dump=$2
local files_tar=$2
local mysql_dump=$3
log_info "开始合并备份文件..."
@@ -346,6 +412,10 @@ merge_backups() {
files_to_pack+=" ${folders_tar}"
fi
if [[ -n "${files_tar}" ]] && [[ -f "${files_tar}" ]]; then
files_to_pack+=" ${files_tar}"
fi
if [[ -n "${mysql_dump}" ]] && [[ -f "${mysql_dump}" ]]; then
files_to_pack+=" ${mysql_dump}"
fi
@@ -362,6 +432,10 @@ merge_backups() {
files_list+=" ${folders_tar#${TEMP_DIR}/}"
log_info "添加到合并: ${folders_tar#${TEMP_DIR}/} ($(du -h "${folders_tar}" | cut -f1))"
fi
if [[ -n "${files_tar}" ]] && [[ -f "${files_tar}" ]]; then
files_list+=" ${files_tar#${TEMP_DIR}/}"
log_info "添加到合并: ${files_tar#${TEMP_DIR}/} ($(du -h "${files_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))"
@@ -586,11 +660,14 @@ run_backup() {
# 备份文件夹
local folders_tar=$(backup_folders)
# 备份单个文件
local files_tar=$(backup_files)
# 备份 MySQL
local mysql_dump=$(backup_mysql)
# 合并备份
local final_backup=$(merge_backups "${folders_tar}" "${mysql_dump}")
local final_backup=$(merge_backups "${folders_tar}" "${files_tar}" "${mysql_dump}")
# 清理旧备份
cleanup_old_backups