#!/bin/bash # 云端数据库一键备份脚本 # 用法:bash backup-db.sh set -e TIMESTAMP=$(date +%Y%m%d_%H%M%S) LOCAL_DIR="/Users/niuniu/programs/docker/db-backups" log() { echo "[$(date '+%H:%M:%S')] $1"; } # 自动发现含数据库的站点 PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DB_SITES="" for dir in "$PROJECT_ROOT"/*-ai/; do site=$(basename "$dir") [[ "$site" == "nginx-proxy-ai" ]] && continue [ -f "$dir/docker-compose.yml" ] || continue grep -qE "\.db|DATABASE_PATH|sqlite" "$dir/docker-compose.yml" 2>/dev/null || continue DB_SITES="$DB_SITES $site" done log "发现数据库站点:${DB_SITES}" log "开始备份云端数据库..." # 站点 → 容器名 + DB路径 映射(自动推导::/app/data/.db) # LLDAP/gitea 容器名特殊,显式声明 declare -A DB_CONTAINERS=([ldap]="lldap:/data/users.db" [gitea]="gitea-ai:/data/gitea.db" [oa]="") # 并行 WAL checkpoint for site in $DB_SITES; do [[ "$site" == "oa" ]] && continue # OA 无独立 DB if [[ -n "${DB_CONTAINERS[$site]}" ]]; then cname="${DB_CONTAINERS[$site]%%:*}" else cname="${site}" # assets-ai / issue-ai / monitor-ai fi log "WAL checkpoint: ${site} (${cname})..." ssh txjp "docker exec ${cname} sqlite3 /app/data/*.db 'PRAGMA wal_checkpoint(TRUNCATE);' 2>/dev/null || true" & done wait # 云端打包 ssh txjp "mkdir -p /tmp/db-backup" for site in $DB_SITES; do [[ "$site" == "oa" ]] && continue if [[ -n "${DB_CONTAINERS[$site]}" ]]; then cname="${DB_CONTAINERS[$site]%%:*}" dbpath="${DB_CONTAINERS[$site]##*:}" else cname="${site}" short="${site%-ai}" # assets-ai → assets dbpath="/app/data/${short}.db" fi log "备份 ${site} (${cname}:${dbpath})..." ssh txjp "docker cp ${cname}:${dbpath} /tmp/db-backup/${site}-${TIMESTAMP}.db" done # 确保本地备份目录存在 mkdir -p "${LOCAL_DIR}" # 云端留一份持久备份 CLOUD_DIR="/root/docker/db-backups" ssh txjp "mkdir -p ${CLOUD_DIR}" for site in $DB_SITES; do [[ "$site" == "oa" ]] && continue ssh txjp "cp /tmp/db-backup/${site}-${TIMESTAMP}.db ${CLOUD_DIR}/" done log "云端备份已保存至: ${CLOUD_DIR}" # 复制到本地 log "复制到本地..." mkdir -p "${LOCAL_DIR}" for site in $DB_SITES; do [[ "$site" == "oa" ]] && continue scp "txjp:/tmp/db-backup/${site}-${TIMESTAMP}.db" "${LOCAL_DIR}/" done # 验证备份文件为有效 SQLite 数据库 log "验证备份完整性..." for site in $DB_SITES; do [[ "$site" == "oa" ]] && continue f="${LOCAL_DIR}/${site}-${TIMESTAMP}.db" if ! sqlite3 "$f" "SELECT count(*) FROM sqlite_master" > /dev/null 2>&1; then echo "[错误] 备份文件无效或损坏: $f" exit 1 fi done log "备份文件验证通过" # 清理云端临时文件 ssh txjp "rm -rf /tmp/db-backup" log "备份完成:${TIMESTAMP}" echo " 云端: ${CLOUD_DIR}/" ssh txjp "ls -lh ${CLOUD_DIR}/*-${TIMESTAMP}.db 2>/dev/null" echo " 本地:" ls -lh "${LOCAL_DIR}"/*-${TIMESTAMP}.db 2>/dev/null