备份不演练等于没备份:用 systemd timer 做每日打包,并做一次恢复演练
自托管服务跑了一段时间,我才意识到一个问题:数据一直在服务器上,但我从来没验证过“坏了能不能恢复”。这篇记录我用 systemd timer 做每日备份、保留最近几份,并真的做了一次恢复演练的过程。
一、备份脚本
假设服务数据都在 /opt/myapp/data,备份放到 /var/backups/myapp。脚本尽量简单,出错就退出:
#!/usr/bin/env bash
set -euo pipefail
SRC=/opt/myapp/data
DST=/var/backups/myapp
KEEP=7
mkdir -p "$DST"
STAMP=$(date +%Y%m%d-%H%M%S)
tar -czf "$DST/myapp-$STAMP.tar.gz" -C "$(dirname $SRC)" "$(basename $SRC)"
# 只保留最近 KEEP 份
ls -1t "$DST"/myapp-*.tar.gz | tail -n +$((KEEP+1)) | xargs -r rm --
echo "backup ok: myapp-$STAMP.tar.gz"
保存为 /usr/local/bin/myapp-backup.sh,chmod 700。如果数据是 SQLite,别直接 tar 正在写的库文件,先用 sqlite3 的 .backup 命令导出一份再打包,否则可能备份到写到一半的状态。
二、为什么用 timer 而不是 cron
timer 的好处是日志统一进 journal,出错能用 systemctl status 直接看到,还能补跑错过的任务。先写 service:
# /etc/systemd/system/myapp-backup.service
[Unit]
Description=Daily backup of myapp
[Service]
Type=oneshot
ExecStart=/usr/local/bin/myapp-backup.sh
再写 timer:
# /etc/systemd/system/myapp-backup.timer
[Unit]
Description=Run myapp backup daily
[Timer]
OnCalendar=*-*-* 03:30:00
Persistent=true
RandomizedDelaySec=300
[Install]
WantedBy=timers.target
启用并立刻手动跑一次:
sudo systemctl daemon-reload
sudo systemctl enable --now myapp-backup.timer
sudo systemctl start myapp-backup.service
systemctl list-timers | grep myapp
journalctl -u myapp-backup.service -n 5 --no-pager
Persistent=true 的意思是:如果服务器恰好在 03:30 关机,开机后会补跑一次,不会漏掉。
三、恢复演练
这是最容易被跳过的一步。我的做法是不碰线上目录,解压到临时目录,再对比:
mkdir /tmp/restore-test
tar -xzf /var/backups/myapp/myapp-XXXX.tar.gz -C /tmp/restore-test
diff -rq /opt/myapp/data /tmp/restore-test/data && echo "一致"
如果服务还在写数据,diff 会有少量差异,属于正常;重点是确认压缩包能解开、关键文件都在、应用能用这份数据启动。真正的演练可以再进一步:用备份起一个临时实例,看能不能正常登录、数据是否完整。
四、踩坑
- 备份和数据放同一块盘,盘坏了就全没了。所以光有本机备份不够,至少再同步一份到别处(对象存储、另一台机器或网盘),本机这份只是防误删。
- 脚本没写
set -e时,tar 失败了脚本照样“成功”,空文件占着名额,把好备份挤掉。加上set -euo pipefail后失败会让 service 变成 failed,一眼就能发现。 - 备份文件权限默认可能让其他用户读到。里面常常有密钥和数据库,目录建议
chmod 700,脚本以 root 运行即可。 - Persistent 只对 OnCalendar 类 timer 生效,改成 OnBootSec 之类就没这个效果了,别混用。
五、小结
整套东西不到五十行配置:一个脚本、一个 service、一个 timer。真正有价值的是最后那次恢复演练——它让“我有备份”从一种感觉变成了一个验证过的事实。建议每次改了备份方式之后,都重新演练一遍。
- 点赞
- 收藏
- 关注作者
评论(0)