监控与备份¶
一、这页讲什么¶
服务「平时能用」和「出事能扛」是两件事。这页把后者补上:每天自动巡检一次(磁盘、内存、失败的服务、监听端口),发现问题有人收到通知;关键数据每天备份到另一块盘,并且真的恢复过一次。
读完能做成:一台服务器上跑起每日巡检与每日备份,收到第一条异常通知,还完成一次恢复演练。
二、开始之前¶
| 项 | 内容 |
|---|---|
| 更新日期 | 2026-10-21 |
| 适用版本 | Ubuntu 24.04、systemd 255、restic 0.18 |
| 预计耗时 | 2 小时(含一次恢复演练) |
| 风险级别 | 中。涉及常驻定时任务与备份目录,先在测试机走一遍 |
| 前置 | 一台 Linux 服务器;一块与系统盘独立的备份盘或远端存储;有 sudo 权限 |
先想清楚三件事:哪些数据丢了算事故(数据库、配置、上传文件)、备份放哪(不能与源数据同盘)、出问题时通知发给谁。
三、动手做¶
3.1 先手动跑一次巡检¶
不写脚本,先把要看的东西手工看一遍,知道正常长什么样。
$ df -h /
Filesystem Size Used Avail Use% Mounted on
/dev/sda1 98G 42G 51G 46% /
$ free -h
total used free shared buff/cache available
Mem: 31Gi 7.2Gi 1.1Gi 312Mi 23Gi 23Gi
$ systemctl --failed
UNIT LOAD ACTIVE SUB DESCRIPTION
nginx.service loaded failed failed A high performance web server
$ ss -tlnp | grep -E ':(80|443|22)'
LISTEN 0 511 0.0.0.0:80 0.0.0.0:* users:(("nginx",pid=812,fd=6))
四项都能打印出结果就算成。systemctl --failed 有输出说明已经有服务挂了,先处理它再继续。
3.2 写成脚本,用 systemd timer 每天跑¶
cron 能跑,但 systemd timer 自带日志、失败重试与依赖,排障时更好查。
$ sudo tee /usr/local/bin/daily-check.sh >/dev/null <<'EOF'
#!/usr/bin/env bash
set -uo pipefail
echo "== $(date -Is) =="
df -h / | tail -1
free -h | sed -n '2p'
systemctl --failed --no-legend
ss -tlnp | grep -c LISTEN
EOF
$ sudo chmod +x /usr/local/bin/daily-check.sh
$ sudo /usr/local/bin/daily-check.sh
== 2026-10-21T10:40:03+08:00 ==
/dev/sda1 98G 42G 51G 46% /
Mem: 31Gi 7.2Gi 1.1Gi 312Mi 23Gi 23Gi
脚本手工跑通、输出四段就算成。
接着写服务与定时器,让它每天 09:00 跑并记进 journal。
# /etc/systemd/system/daily-check.service
[Unit]
Description=Daily host check
[Service]
Type=oneshot
ExecStart=/usr/local/bin/daily-check.sh
# /etc/systemd/system/daily-check.timer
[Unit]
Description=Run daily check at 09:00
[Timer]
OnCalendar=*-*-* 09:00:00
Persistent=true
[Install]
WantedBy=timers.target
$ sudo systemctl daemon-reload && sudo systemctl enable --now daily-check.timer
Created symlink /etc/systemd/system/timers.target.wants/daily-check.timer → /etc/systemd/system/daily-check.timer.
$ systemctl list-timers daily-check.timer
NEXT LEFT UNIT ACTIVATES
Wed 2026-10-22 09:00:00 CST 22h daily-check.timer daily-check.service
$ journalctl -u daily-check.service -n 5
Oct 21 09:00:02 server-a systemd[1]: Starting Daily host check...
Oct 21 09:00:03 server-a daily-check.sh[9213]: == 2026-10-21T09:00:02+08:00 ==
list-timers 显示下次触发时间、journalctl 有本次输出,两项都满足就算成。
异常要能主动通知:在脚本末尾加一条判断,磁盘使用率超过 80% 或存在失败服务时推一条消息出去。判断放在脚本里比放在告警系统里简单,也更容易审。
3.3 配置备份¶
备份工具选 restic 或 rsync 都行,关键不在工具,在于备份不在同一块盘、有保留策略、能校验。下面按 restic 写。
$ sudo apt install -y restic
$ export RESTIC_REPOSITORY=/mnt/backup/restic
$ export RESTIC_PASSWORD_FILE=/root/.restic-pass
$ restic init
created restic repository 3f9a1c7b2e at /mnt/backup/restic
$ restic backup /srv/data --tag daily
repository 3f9a1c7b opened, using repository format 2
Files: 412 new, 0 changed, 0 unmodified
Added to the repository: 128.4 MiB (96.2 MiB stored)
snapshot 8c1d2e saved
看到 snapshot ... saved 就算成。
加保留策略,否则备份盘会被撑满。每周保留最近 7 天、每月保留 6 个月,并让 restic 校验一次数据完整性。
$ restic forget --keep-daily 7 --keep-monthly 6 --prune
Applying Policy: keep 7 daily, 6 monthly snapshots
keep 7 snapshots:
...
$ restic check
using temporary cache in /tmp/restic-check-cache-1234
create exclusive lock for repository
load indexes
check all packs
no errors were found
no errors were found 才算备份可用。把 backup 与前一条 forget --prune 一起放进同一个 timer,顺序执行。
3.4 演练一次恢复¶
没恢复过的备份等于没有备份。挑一份快照,恢复到临时目录,比对文件数与内容。
$ restic restore latest --target /tmp/restore-test
restoring <Snapshot 8c1d2e of /srv/data at 2026-10-21 09:12:44> to /tmp/restore-test
$ diff -r /srv/data /tmp/restore-test/srv/data && echo SAME
SAME
$ rm -rf /tmp/restore-test
diff 无差异、打印 SAME 就算成。恢复演练每季度做一次,做完记下日期与耗时。
四、做完怎么确认¶
| 检查项 | 期望结果 |
|---|---|
systemctl list-timers |
巡检与备份两个 timer 都有下次触发时间 |
journalctl -u daily-check.service |
有最近一次巡检输出 |
restic snapshots |
有当天快照 |
restic check |
no errors were found |
| 恢复演练 | 恢复到临时目录后 diff 无差异 |
| 手动拔掉通知测试 | 手机能在 1 分钟内收到 |
五、卡住了怎么排查¶
| 症状 | 多半是 | 怎么办 |
|---|---|---|
| timer 到点没跑 | Persistent 没开、机器当时关机 |
开 Persistent=true,list-timers 看 NEXT 时间 |
| 备份任务报磁盘满 | 保留策略没生效或没 prune | 先 restic forget --prune,再查备份盘容量 |
| 恢复后文件权限不对 | 非 root 恢复、或备份时用了不同用户 | 用同样的用户恢复,或恢复后重设属主 |
| restic 密码没了 | 密码写在临时环境变量里没落盘 | 密码单独存好并纳入密钥管理;丢了打不开仓库 |
巡检脚本报 Permission denied |
sudo 执行的脚本读了用户目录 | 检查脚本跑的权限与路径 |
| 通知没送到 | 出口配置错了,或起了多个机器人 | 手动 curl 测试一次,只留一个出口 |
| 时间对不上 | 时区或 NTP 没配 | timedatectl 看时区,开自动同步 |
六、为什么这样能成¶
巡检解决「坏之前有人知道」,备份解决「坏了能恢复」,演练解决「恢复这一步本身是否可信」。三件事分开做,任何一件缺失都会在事故里暴露。
备份的三条硬规则:至少两份副本、放在两种存储上、其中一份离开这台机器(常见说法是 3-2-1)。快照不是备份——同一个盘上的快照跟着盘一起坏。保留策略决定空间,校验决定数据是否完整,恢复演练决定备份是否真的可用。
告警要能叫醒人:只写日志没人看,只在仪表盘画曲线也没人看。异常汇总成一条消息发到人手上,才算闭环。
七、边界与替代¶
- 只要单机排查、不要求恢复:用
journalctl与df手工看即可,不必上定时任务。 - 数据可以丢:缓存、构建产物这类目录不必备份,写清楚哪些不备份比全备更重要。
- 没有独立的第二块存储:先解决存储,再做备份方案;同盘备份不算备份。
- 不要追求全自动修复:自动重启能掩盖根因,先做到「知道 + 能恢复」,自动化放在后面。
- 备份文件里不要存明文密码:仓库密码与加密密钥单独管理。
八、官方资料¶
- restic 文档(仓库、快照、保留策略):https://restic.readthedocs.io/en/stable/
- systemd.timer 手册:https://www.freedesktop.org/software/systemd/man/latest/systemd.timer.html
- systemd.service 手册:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html
- rsync 手册:https://download.samba.org/pub/rsync/rsync.1
- journalctl 手册:https://www.freedesktop.org/software/systemd/man/latest/journalctl.html