#!/usr/bin/env bash # ============================================================================= # Meta : Firefly III 备份执行脚本 # Version : 1.0.0 # Author : Bash Shell Senior Development Engineer # License : MIT # Description : 自动化执行 Firefly III 远程备份、同步、加密、上传及清理任务。 # # 本脚本基于公司备份中心的通用框架,使用 common.sh 中定义的日志、远程执行、 # 加密与 rclone 函数实现。它假定 Firefly III 运行在名为 p3 的远程服务器 # 上,并且容器使用 MariaDB 作为数据库。由于 p3 的磁盘 I/O 性能较差, # Firefly III 使用挂载在 /mnt/ramdisk 的 RAM 磁盘保存数据库和上传目录。 # 为保证数据持久性,本脚本会定期将数据拉取到备份中心并上传到异地存储。 # ============================================================================= set -euo pipefail IFS=$'\n\t' # ----------------------------------------------------------------------------- # 引入公共库 # ----------------------------------------------------------------------------- source "$(dirname "$0")/common.sh" || { echo "FATAL: common.sh not found." >&2; exit 1; } # ----------------------------------------------------------------------------- # 配置区 # ----------------------------------------------------------------------------- readonly APP_NAME="FireflyIII" readonly REMOTE_USER="root" readonly REMOTE_HOST="p3" # 远程主机的 SSH 端口继承自 common.sh 中的 REMOTE_SSH_PORT readonly MAX_ENCRYPTED_REPLICAS=3 # 可根据需求调整远程保留的最大加密副本数 # MariaDB 容器名称及数据库凭据。建议通过环境变量传入,避免明文密码。 readonly REMOTE_DB_CONTAINER="firefly_iii_db" # 从环境变量中读取数据库名称和凭据,默认值仅供示例使用。 readonly DB_USER="${FIREFLY_DB_USER:-firefly}" # 数据库用户名 readonly DB_PASSWORD="${FIREFLY_DB_PASSWORD:-ChangeThisPassword}" # 数据库密码 readonly DB_NAME="${FIREFLY_DB_NAME:-firefly}" # 数据库名 # 远程路径:FireflyIII 在 p3 上的 RAM 磁盘挂载目录。 readonly REMOTE_UPLOAD_DIR="/mnt/ramdisk/firefly_iii_upload" readonly REMOTE_DB_RAMDIR="/mnt/ramdisk/firefly_iii_db" # 本地备份目录。根据备份中心目录结构自定义,用于暂存同步文件。 readonly LOCAL_BACKUP_DIR="/data/p3_firefly_iii" # ----------------------------------------------------------------------------- # 主执行流程 # ----------------------------------------------------------------------------- main() { trap 'log_message "ERROR" "${APP_NAME} 的备份任务出现错误! 终止"' ERR log_message "INFO" "====== 开始 ${APP_NAME} 备份任务 ======" # ------------------------------------------------------------------------- # 步骤 1: 在远程服务器中创建数据库转储 # # 使用 mariadb-dump 从容器中导出数据库,并将结果重定向到 RAM 磁盘目录。 # 由于磁盘 IO 慢,转储文件直接写入 RAM 磁盘可以减少时间。 # 注意: 为防止密码泄露,请保证 DB_PASSWORD 不在 shell 历史中。 # ------------------------------------------------------------------------- log_message "INFO" "[Step 1/7] 在远程 p3 上导出 Firefly III 数据库..." local dump_filename="firefly-db_backup_$(date +%Y%m%d-%H%M%S).sql" local remote_dump_path="${REMOTE_DB_RAMDIR}/${dump_filename}" local dump_cmd="docker exec ${REMOTE_DB_CONTAINER} mariadb-dump --single-transaction -h localhost -u ${DB_USER} -p'${DB_PASSWORD}' ${DB_NAME} > ${remote_dump_path}" execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "${dump_cmd}" # ------------------------------------------------------------------------- # 步骤 2: Rsync 同步数据库转储和上传目录到备份中心 # # 将远程的 RAM 磁盘数据复制到本地目录。这里创建子目录以避免命名冲突。 # ------------------------------------------------------------------------- log_message "INFO" "[Step 2/7] rsync 复制远程数据到备份中心..." mkdir -p "${LOCAL_BACKUP_DIR}/upload" # 同步上传目录 rsync -avz --delete --progress -e "ssh -p ${REMOTE_SSH_PORT}" \ "${REMOTE_USER}@${REMOTE_HOST}:${REMOTE_UPLOAD_DIR}/" \ "${LOCAL_BACKUP_DIR}/upload/" # 同步数据库转储 rsync -avz --progress -e "ssh -p ${REMOTE_SSH_PORT}" \ "${REMOTE_USER}@${REMOTE_HOST}:${remote_dump_path}" \ "${LOCAL_BACKUP_DIR}/" # 可选: 若需备份配置文件,可在此加入 rsync 命令复制 .env 和 docker-compose.yml # 例如:rsync -avz "${REMOTE_USER}@${REMOTE_HOST}:/path/to/compose/.env" "${LOCAL_BACKUP_DIR}/" # ------------------------------------------------------------------------- # 步骤 3: 远程清理数据库转储 # # 删除 p3 上的临时 .sql 文件,防止 RAM 磁盘占用。 # ------------------------------------------------------------------------- log_message "INFO" "[Step 3/7] 清理远程数据库转储文件..." execute_remote_command "${REMOTE_USER}" "${REMOTE_HOST}" "rm -f ${remote_dump_path}" # ------------------------------------------------------------------------- # 步骤 4: 本地加密压缩 # # 使用 7‑zip 加密并压缩整个本地备份目录。压缩包命名包含时间戳。 # ------------------------------------------------------------------------- log_message "INFO" "[Step 4/7] 使用 7zip 加密本地备份目录..." local archive_file="${SCRIPT_RUN_DIR}/${APP_NAME}-backup-$(date +%Y%m%d-%H%M%S).7z" encrypt_with_7zip "${LOCAL_BACKUP_DIR}" "${archive_file}" # ------------------------------------------------------------------------- # 步骤 5: rclone 上传加密包 # ------------------------------------------------------------------------- log_message "INFO" "[Step 5/7] 上传加密压缩包至冷存储 => ${RCLONE_REMOTE_REPO}..." rclone_copy "${archive_file}" "${RCLONE_REMOTE_REPO}" # ------------------------------------------------------------------------- # 步骤 6: 控制远程仓库副本数 # ------------------------------------------------------------------------- log_message "INFO" "[Step 6/7] 控制远程备份副本数量为 ${MAX_ENCRYPTED_REPLICAS}..." rclone_control_replicas "${RCLONE_REMOTE_REPO}" "${APP_NAME}-backup-" "${MAX_ENCRYPTED_REPLICAS}" # ------------------------------------------------------------------------- # 步骤 7: 本地清理 # # 删除本地生成的加密压缩包,以节省磁盘空间。可根据需要删除同步目录。 # ------------------------------------------------------------------------- log_message "INFO" "[Step 7/7] 清理本地加密压缩包..." cleanup_local_encrypted_files "${SCRIPT_RUN_DIR}" # 可选: rm -rf "${LOCAL_BACKUP_DIR}" log_message "INFO" "====== ${APP_NAME} 备份任务已全部完成! ======" } main "$@"