141 lines
5.8 KiB
Bash
Executable File
141 lines
5.8 KiB
Bash
Executable File
#!/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"
|