🧩 第06章 · 备份与恢复演练
定时备份/验证/恢复
备份与恢复演练¶
备份不是为了「有备份」,而是为了出问题后能真正恢复出来。一个没验证过的备份等于没有。本章从备份脚本、cron 定时、到恢复演练(这是大多数人漏掉的关键一步)完整走一遍。
本章目标:能把关键数据(数据库、网站文件、配置)自动备份,并证明「恢复」流程可行——先小规模恢复到一个临时目录验证,再做一次完整恢复演练。
1. 明确备份范围与策略¶
先列出「丢了会痛」的东西:
| 对象 | 路径/对象 | 频率 | 方式 |
|---|---|---|---|
| MySQL 数据库 | bangdream 库 |
每日 | mysqldump |
| 网站代码 | /opt/apps/site |
每日 | tar |
| Nginx 配置 | /etc/nginx/sites-available/ |
每日 | tar |
| GitLab 关键数据 | /var/opt/gitlab |
每日 | gitlab-backup |
| 系统配置 | /etc/(关键) |
每周 | tar |
⚠️ 易错:先定恢复策略再写备份。许多人只备份「数据」而漏了「配置」(Nginx、GitLab 的
gitlab.rb、systemd 单元),恢复时配置丢失照样起不来。备份要包含「配置文件」这一层。
2. 写一个统一的备份脚本¶
sudo tee /usr/local/bin/backup-all.sh >/dev/null <<'EOF'
#!/bin/bash
set -euo pipefail
DAY=$(date +%F); DIR=/srv/backup
mkdir -p "$DIR/db" "$DIR/files" "$DIR/config"
cd "$DIR"
# 1) 数据库
mysqldump -u bangdream_app -p'强密码' --single-transaction bangdream | gzip > db/bangdream-$DAY.sql.gz
# 2) 网站应用与数据
tar czf files/site-$DAY.tar.gz -C /opt/apps site 2>/dev/null || true
# 3) 关键配置
tar czf config/nginx-$DAY.tar.gz -C /etc/nginx sites-available 2>/dev/null || true
# 4) 清理 7 天前旧备份
find "$DIR/db" "$DIR/files" "$DIR/config" -type f -mtime +7 -delete
echo "[$(date)] backup done, dir=${DIR}/"
EOF
sudo chmod +x /usr/local/bin/backup-all.sh
🔒 安全:备份脚本里别明文写密码。更安全的做法是把口令放进
~/.my.cnf并chmod 600,或在脚本里从环境变量读取。明文写在仓库/脚本里一旦泄露,等于把数据库拱手相让。
# .my.cnf 方式(避免命令行明文密码)
sudo tee /root/.my.cnf >/dev/null <<'EOF'
[mysqldump]
user=bangdream_app
password=强密码
EOF
sudo chmod 600 /root/.my.cnf
3. 定时执行¶
crontab -e
# 每天 02:30 执行全量备份
30 2 * * * /usr/local/bin/backup-all.sh >> /var/log/cron-backup.log 2>&1
# 手动跑一次并核对产物
sudo /usr/local/bin/backup-all.sh && ls -lh /srv/backup/db/ /srv/backup/files/ /srv/backup/config/
4. 验证备份(成功的关键)¶
不验证=没备份。至少做这三类校验:
# 1) 大小非零
find /srv/backup -name "*.gz" -size +0 -ls | head
# 2) 校验 gzip 完整性
gunzip -t /srv/backup/db/bangdream-*.sql.gz && echo "gzip OK"
# 3) 抽查数据库备份能否导入到临时库
zcat /srv/backup/db/bangdream-*.sql.gz | head -20
⚠️ 易错:
gunzip -t只能证明「压缩包没坏」,不能证明 SQL 内容正确。真正的验证是「导入到一个空库并对比行数」。大小正常、gzip 正常、但内容是空的——这类情况只有「恢复演练」能抓出来。
5. 恢复演练(小规模:倒入临时库)¶
这是本章核心:把备份恢复到临时位置,验证流程可行,且不碰生产库。
# 创建临时库并导入
mysql -e "CREATE DATABASE bangdream_restore_test;"
zcat /srv/backup/db/bangdream-*.sql.gz | mysql -u bangdream_app -p'强密码' bangdream_restore_test
# 对比行数(假设主表是 users,换成真实表名)
mysql -N -e "SELECT COUNT(*) FROM bangdream.users;"
mysql -N -e "SELECT COUNT(*) FROM bangdream_restore_test.users;"
# 清理临时库
mysql -e "DROP DATABASE bangdream_restore_test;"
⚠️ 易错:mysqldump 用
SET GLOBAL/锁表等参数会依赖权限。用--single-transaction避免锁全表。若对比行数不一致,立即排查是备份脚本漏表还是备份时间点差异。
6. 完整恢复演练(换机/灾备场景)¶
从头模拟「这台机器没了,用备份重建」——这是终极验证。先在一台干净的测试机上做,别拿生产机当试验田。
# 假设已经装好 MySQL / Nginx / Node
# 1) 恢复数据库
zcat /srv/backup/db/bangdream-*.sql.gz | mysql -u root bangdream
# 2) 恢复应用代码
sudo tar xzf /srv/backup/files/site-*.tar.gz -C /opt/apps
sudo systemctl restart bangdream-site
# 3) 恢复 Nginx 配置
sudo tar xzf /srv/backup/config/nginx-*.tar.gz -C /etc/nginx
sudo nginx -t && sudo systemctl reload nginx
# 4) 最终验证
curl -I https://bangdream.xyz && systemctl is-active bangdream-site
7. 异地/离线备份(防机器丢失)¶
单机备份最大的漏洞是「这台机器本身死了」。再同步一份到异地(如对象存储或另一台机器):
# 用 rsync 推到另一台机器(例子)
rsync -avz /srv/backup/ backup@remote-machine:/srv/backup/ --delete
# 或上传到对象存储(以 s3cmd 为例)
# s3cmd sync /srv/backup/ s3://my-bucket/backup/ --delete
🔒 安全:异地副本是灾难恢复的最后底线。若只有本机一份,而且本机被删库/被勒索/整机销毁,备份也一起没了。至少保证「备份的备份」存在本机之外。
8. 完成清单¶
| # | 验证点 | 命令 | 预期 |
|---|---|---|---|
| 1 | 备份生成 | ls /srv/backup |
三类文件都在 |
| 2 | gzip 完整 | gunzip -t ... |
OK |
| 3 | 定时任务 | crontab -l |
列出备份行 |
| 4 | 行数一致 | 对比临时库 | 一致 |
| 5 | 恢复成功 | 干净机完整恢复 | 网站可访问 |
一条命令总验证:
gunzip -t /srv/backup/db/bangdream-*.sql.gz && ls -lh /srv/backup/*/ | tail -6 \
&& crontab -l | grep backup \
&& mysql -N -e "SELECT 1" && echo "DB OK"
备份与恢复闭环达成:数据、代码、配置三层都定时备份、经校验、能恢复,且保留一份异地副本。下一步给整台服务器做一次系统的安全加固。