💾 备份恢复

数据库自动备份、对象存储归档、灾难恢复演练——没有测试过的备份等于没有备份

📐 3-2-1 备份原则

这是备份行业的黄金法则,无论你是个人还是企业都适用:

规则含义为什么
3至少 3 份数据副本1 份原始数据 + 2 份备份
2至少 2 种不同存储介质同一硬盘的 2 份不算——硬盘坏了全丢
1至少 1 份在异地机房着火/地震不会全丢
独立开发者的 3-2-1 实现方案 3 份副本: ① 生产数据库 (VPS) ② 同 VPS 本地备份 (/backup/) ③ 对象存储 (S3/DO Spaces/Backblaze) 2 种介质: ① VPS 本地 SSD ② 对象存储(不同物理设备) 1 份异地: ③ 对象存储(不同数据中心/区域) 成本估算: - DO Spaces: $5/月 (250GB) - Backblaze B2: $0.005/GB/月 - AWS S3 Glacier: $0.004/GB/月(冷存储)

🗄️ PostgreSQL 自动备份

#!/bin/bash # /usr/local/bin/backup-postgres.sh set -e # 配置 DB_NAME="myapp" DB_USER="postgres" BACKUP_DIR="/backup/postgres" S3_BUCKET="s3://my-backups/postgres" RETENTION_LOCAL=7 # 本地保留 7 天 RETENTION_S3=30 # S3 保留 30 天 DATE=$(date +%Y-%m-%d_%H%M) SLACK_WEBHOOK="" # 可选:通知 # 创建备份目录 mkdir -p $BACKUP_DIR # 1. pg_dump 备份 echo "📦 开始备份 $DB_NAME..." docker exec postgres pg_dump -U $DB_USER -F c $DB_NAME \ > "$BACKUP_DIR/${DB_NAME}_${DATE}.dump" # 2. 压缩 gzip "$BACKUP_DIR/${DB_NAME}_${DATE}.dump" # 3. 上传到 S3 echo "☁️ 上传到 S3..." aws s3 cp "$BACKUP_DIR/${DB_NAME}_${DATE}.dump.gz" \ "$S3_BUCKET/${DB_NAME}_${DATE}.dump.gz" # 4. 清理本地旧备份 find $BACKUP_DIR -name "*.dump.gz" -mtime +$RETENTION_LOCAL -delete # 5. 清理 S3 旧备份 aws s3 ls $S3_BUCKET/ | \ awk '{print $4}' | \ while read -r file; do file_date=$(echo $file | grep -oP '\d{4}-\d{2}-\d{2}') if [[ $(date -d "$file_date" +%s) -lt $(date -d "$RETENTION_S3 days ago" +%s) ]]; then aws s3 rm "$S3_BUCKET/$file" fi done # 6. 验证备份 echo "🔍 验证备份..." docker exec postgres pg_restore --list \ "$BACKUP_DIR/${DB_NAME}_${DATE}.dump.gz" > /dev/null 2>&1 if [ $? -eq 0 ]; then echo "✅ 备份成功: ${DB_NAME}_${DATE}.dump.gz" # 通知(可选) curl -s -X POST "$SLACK_WEBHOOK" \ -H 'Content-type: application/json' \ -d "{\"text\":\"✅ PostgreSQL 备份成功: ${DATE}\"}" else echo "❌ 备份验证失败!" curl -s -X POST "$SLACK_WEBHOOK" \ -H 'Content-type: application/json' \ -d "{\"text\":\"❌ PostgreSQL 备份验证失败: ${DATE}\"}" fi # Cron 定时任务 # crontab -e # 0 2 * * * /usr/local/bin/backup-postgres.sh >> /var/log/backup.log 2>&1

📂 文件备份

#!/bin/bash # /usr/local/bin/backup-files.sh set -e DATE=$(date +%Y-%m-%d) S3_BUCKET="s3://my-backups/files" # 备份 Docker Compose 配置 tar czf /tmp/compose-config_${DATE}.tar.gz \ /home/deploy/app/docker-compose.yml \ /home/deploy/app/.env \ /home/deploy/app/traefik/ # 备份应用数据(Uploads 等) tar czf /tmp/app-data_${DATE}.tar.gz \ /home/deploy/app/uploads/ # 上传到 S3 aws s3 cp /tmp/compose-config_${DATE}.tar.gz $S3_BUCKET/config/ aws s3 cp /tmp/app-data_${DATE}.tar.gz $S3_BUCKET/data/ # 清理临时文件 rm /tmp/compose-config_${DATE}.tar.gz /tmp/app-data_${DATE}.tar.gz echo "✅ 文件备份完成: $DATE"

🧪 灾难恢复演练

没有测试过的备份等于没有备份。定期(每月)做一次灾难恢复演练:

#!/bin/bash # /usr/local/bin/test-restore.sh — 灾难恢复测试 set -e echo "🧪 开始灾难恢复测试..." # 1. 创建测试数据库 docker exec postgres psql -U postgres -c "CREATE DATABASE test_restore;" # 2. 从 S3 下载最新备份 LATEST=$(aws s3 ls s3://my-backups/postgres/ | tail -1 | awk '{print $4}') aws s3 cp "s3://my-backups/postgres/$LATEST" /tmp/latest_backup.dump.gz # 3. 解压 gunzip /tmp/latest_backup.dump.gz # 4. 恢复 docker exec -i postgres pg_restore -U postgres -d test_restore \ < /tmp/latest_backup.dump # 5. 验证数据完整性 TABLES=$(docker exec postgres psql -U postgres -d test_restore \ -t -c "SELECT count(*) FROM information_schema.tables WHERE table_schema='public';") echo "📊 恢复的表数量: $TABLES" # 6. 随机数据验证 docker exec postgres psql -U postgres -d test_restore \ -c "SELECT count(*) FROM users;" # 7. 清理 docker exec postgres psql -U postgres -c "DROP DATABASE test_restore;" rm /tmp/latest_backup.dump echo "✅ 灾难恢复测试完成!" # 建议的恢复演练频率 # - 每月一次完整恢复测试 # - 每季度一次异地恢复测试(在另一台 VPS 上恢复) # - 每半年一次全流程演练(从零搭建 + 恢复)

📊 备份监控

# 使用 Uptime Kuma 监控备份状态 # 方法:备份脚本写一个健康检查文件 # 在备份成功后 echo "$(date +%s)" > /backup/last-successful-backup # Nginx 暴露健康端点 location /backup-status { alias /backup/last-successful-backup; default_type text/plain; } # Uptime Kuma 配置 # Type: HTTP(s) # URL: https://your-server/backup-status # Expected: 正则匹配时间戳 # Interval: 3600 (每小时检查) # Alert: 如果文件超过 26 小时未更新 → 报警

💡 备份的隐性成本

数据库备份不只是数据——还包括:① 环境变量(.env 文件)② Docker Compose 配置 ③ SSL 证书(虽然可以重新获取,但 DNS 验证可能卡住)④ Cron 任务 ⑤ SSH 密钥和授权。建议把所有配置文件放在 Git 仓库(敏感信息用 SOPS 加密),这样恢复时 git clone + terraform apply + ansible-playbook + 数据库恢复 = 完整恢复。

🔗 相关专题

🐳 Docker Compose · 🛡️ 服务器加固 · 🏗️ Terraform · 🏗️ 返回首页