#!/bin/bash # 完整灾难恢复备份脚本 # 包含:数据库、代码仓库、用户数据、配置文件、SSL证书 # 用法:bash backup-full.sh set -e TIMESTAMP=$(date +%Y%m%d_%H%M%S) LOCAL_DIR="/Users/niuniu/programs/docker/db-backups" BACKUP_NAME="full-backup-${TIMESTAMP}" log() { echo "[$(date '+%H:%M:%S')] $1"; } warn() { echo "[$(date '+%H:%M:%S')] [警告] $1"; } log "开始完整灾难恢复备份..." # ============================================================ # 1. 数据库备份(WAL checkpoint + docker cp) # ============================================================ # 自动发现数据库站点 PROJECT_ROOT="$(cd "$(dirname "$0")/.." && pwd)" DB_SITES="" for dir in "$PROJECT_ROOT"/*-ai/; do s=$(basename "$dir"); [[ "$s" == "nginx-proxy-ai" ]] && continue [ -f "$dir/docker-compose.yml" ] || continue grep -qE "\.db|DATABASE_PATH|sqlite" "$dir/docker-compose.yml" 2>/dev/null || continue [[ "$s" == "oa" ]] && continue; DB_SITES="$DB_SITES $s" done log "执行 WAL checkpoint..." for s in $DB_SITES; do case "$s" in ldap) ssh txjp "docker exec lldap sqlite3 /data/users.db 'PRAGMA wal_checkpoint(TRUNCATE);'" 2>/dev/null || warn "ldap checkpoint 失败" ;; *) ssh txjp "docker exec ${s} sqlite3 /app/data/*.db 'PRAGMA wal_checkpoint(TRUNCATE);' 2>/dev/null || true" & ;; esac done; wait log "导出数据库..." ssh txjp "mkdir -p /tmp/full-backup/databases" for s in $DB_SITES; do case "$s" in ldap) ssh txjp "docker cp lldap:/data/users.db /tmp/full-backup/databases/ldap.db" ;; gitea) ssh txjp "docker cp gitea-ai:/data/gitea.db /tmp/full-backup/databases/gitea.db" ;; *) short="${s%-ai}"; ssh txjp "docker cp ${s}:/app/data/${short}.db /tmp/full-backup/databases/${short}.db" ;; esac done # ============================================================ # 2. Gitea 代码仓库 + 配置 # ============================================================ log "备份 Gitea 代码仓库..." ssh txjp "mkdir -p /tmp/full-backup/gitea && \ cp -a /root/docker/gitea-ai/data/git /tmp/full-backup/gitea/ && \ cp -a /root/docker/gitea-ai/data/gitea/conf /tmp/full-backup/gitea/ 2>/dev/null || true" # ============================================================ # 3. 用户上传文件 # ============================================================ log "备份用户上传文件..." ssh txjp "mkdir -p /tmp/full-backup/uploads && \ cp -a /root/docker/assets-ai/data/uploads /tmp/full-backup/uploads/assets-uploads 2>/dev/null || true && \ cp -a /root/docker/issue-ai/data/uploads /tmp/full-backup/uploads/issue-uploads 2>/dev/null || true && \ cp -a /root/docker/issue-ai/data/reports /tmp/full-backup/uploads/issue-reports 2>/dev/null || true" # ============================================================ # 4. Nginx 配置 # ============================================================ log "备份 Nginx 配置..." ssh txjp "mkdir -p /tmp/full-backup/nginx && \ cp -a /root/docker/nginx-proxy-ai/conf.d/* /tmp/full-backup/nginx/ 2>/dev/null || true" # ============================================================ # 5. 各站点 docker-compose.yml + .env # ============================================================ log "备份站点配置文件..." ssh txjp "mkdir -p /tmp/full-backup/configs && \ for site in assets-ai issue-ai oa-ai ldap-ai gitea-ai; do \ mkdir -p /tmp/full-backup/configs/\$site && \ cp /root/docker/\$site/docker-compose.yml /tmp/full-backup/configs/\$site/ 2>/dev/null || true && \ cp /root/docker/\$site/.env /tmp/full-backup/configs/\$site/ 2>/dev/null || true && \ cp /root/docker/\$site/Dockerfile /tmp/full-backup/configs/\$site/ 2>/dev/null || true; \ done" # ============================================================ # 6. SSL 证书 # ============================================================ log "备份 SSL 证书..." ssh txjp "mkdir -p /tmp/full-backup/ssl && \ cp -a /etc/letsencrypt/live /tmp/full-backup/ssl/ 2>/dev/null || true && \ cp -a /etc/letsencrypt/archive /tmp/full-backup/ssl/ 2>/dev/null || true && \ cp -a /etc/letsencrypt/renewal /tmp/full-backup/ssl/ 2>/dev/null || true" # ============================================================ # 7. 打包压缩 # ============================================================ log "打包压缩..." ssh txjp "cd /tmp && tar czf ${BACKUP_NAME}.tar.gz full-backup/ && rm -rf /tmp/full-backup" # ============================================================ # 8. 复制到本地 # ============================================================ log "复制到本地..." mkdir -p "${LOCAL_DIR}" scp "txjp:/tmp/${BACKUP_NAME}.tar.gz" "${LOCAL_DIR}/" # ============================================================ # 9. 云端保留一份 # ============================================================ CLOUD_DIR="/root/docker/db-backups" ssh txjp "mkdir -p ${CLOUD_DIR} && cp /tmp/${BACKUP_NAME}.tar.gz ${CLOUD_DIR}/" log "云端备份已保存至: ${CLOUD_DIR}" # ============================================================ # 10. 清理云端临时文件 # ============================================================ ssh txjp "rm -f /tmp/${BACKUP_NAME}.tar.gz" # ============================================================ # 11. 验证备份 # ============================================================ log "验证备份完整性..." cd "${LOCAL_DIR}" if tar tzf "${BACKUP_NAME}.tar.gz" > /dev/null 2>&1; then log "备份文件验证通过" else echo "[错误] 备份文件损坏" exit 1 fi # 显示备份内容 log "备份内容清单:" tar tzf "${BACKUP_NAME}.tar.gz" | head -30 echo "" log "备份完成:${TIMESTAMP}" echo " 文件: ${LOCAL_DIR}/${BACKUP_NAME}.tar.gz" echo " 大小: $(du -h ${LOCAL_DIR}/${BACKUP_NAME}.tar.gz | cut -f1)" echo "" echo " 云端: ${CLOUD_DIR}/${BACKUP_NAME}.tar.gz" ssh txjp "ls -lh ${CLOUD_DIR}/${BACKUP_NAME}.tar.gz 2>/dev/null"