用 systemd timer 给 VPS 做每日自动快照与清理:一次配置长期省心
手上这台 40G 的云服务器跑了几个月,最烦的不是性能,而是「不知不觉磁盘就满了」:apt 缓存、旧内核、journal 日志、临时文件,每样都不大,加起来能把根分区吃到 80%。手动 `df -h` 看一眼再清理,隔两周就忘。
这篇记录怎么用 systemd timer 把「每日体检 + 自动清理 + 关键数据快照」固化下来,配置一次,之后不用管。
一、为什么不直接用 cron
cron 能用,但 systemd timer 有几个实际优势:
- 支持 `Persistent=true`,机器关机错过的时间点,开机后会补跑一次;cron 直接跳过。
- 日志统一进 journald,`journalctl -u xxx` 就能看,不用自己重定向到文件。
- 可以声明依赖、资源限制、运行超时,出问题不会卡死。
- 随机延迟 `RandomizedDelaySec` 避免整点一起跑。
对个人 VPS 来说,`Persistent=true` 这一条就够值了。
二、清理脚本
先写清理逻辑,放在 `/usr/local/bin/vps-daily-clean.sh`:
#!/bin/bash
set -euo pipefail
LOG_TAG="vps-clean"
log() { echo "[$(date '+%F %T')] $*"; }
# 1. apt 缓存
apt-get clean
log "apt cache cleaned"
# 2. 无用的自动依赖
apt-get -y autoremove --purge >/dev/null 2>&1 || true
log "autoremove done"
# 3. journal 日志压到 200M 以内
journalctl --vacuum-size=200M >/dev/null 2>&1 || true
log "journal vacuumed"
# 4. /tmp 下超过 7 天的文件
find /tmp -type f -atime +7 -delete 2>/dev/null || true
log "/tmp cleaned"
# 5. 旧内核:保留当前运行的 + 最新一个
CURRENT=$(uname -r)
dpkg -l 'linux-image-*' 2>/dev/null \
| awk '/^ii/{print $2}' \
| grep -v "$CURRENT" \
| grep -v 'linux-image-cloud-amd64' \
| tail -n +2 \
| xargs -r apt-get -y purge
log "old kernels purged (kept $CURRENT)"
# 6. 报告磁盘
df -h / | tail -1 | while read -r line; do log "disk: $line"; done
几个注意点:
- `set -euo pipefail` 让脚本出错就退出,但每步清理都加了 `|| true`,避免某一步失败中断整个流程。
- 旧内核那段 `tail -n +2` 是关键:先排除正在运行的内核,再从剩下的里跳过最新的一个,只删更老的。删错内核会导致无法启动。
- `linux-image-cloud-amd64` 是元包,必须排除。
赋权:
chmod +x /usr/local/bin/vps-daily-clean.sh
先手动跑一遍确认没问题:
/usr/local/bin/vps-daily-clean.sh
journalctl -n 20 --no-pager
三、配置 timer
`/etc/systemd/system/vps-daily-clean.service`:
[Unit]
Description=Daily VPS cleanup
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/vps-daily-clean.sh
Nice=10
IOSchedulingClass=idle
TimeoutStartSec=600
`/etc/systemd/system/vps-daily-clean.timer`:
[Unit]
Description=Run VPS cleanup daily
[Timer]
OnCalendar=*-*-* 04:30:00
RandomizedDelaySec=30m
Persistent=true
Unit=vps-daily-clean.service
[Install]
WantedBy=timers.target
`Nice=10` 和 `IOSchedulingClass=idle` 让清理任务在低优先级跑,不会和业务抢资源。
启用:
systemctl daemon-reload
systemctl enable --now vps-daily-clean.timer
systemctl list-timers --all | grep vps
`list-timers` 会显示下次触发时间和上次运行结果,这是最直接的验证方式。
四、加一个配置快照
光清理不够,配置改坏了想回滚得有备份。加一段每天打包 `/etc` 里的关键配置:
BACKUP_DIR=/var/backups/vps
mkdir -p "$BACKUP_DIR"
tar czf "$BACKUP_DIR/etc-$(date +%F).tar.gz" \
/etc/ssh /etc/systemd/system /etc/nginx 2>/dev/null || true
# 只保留最近 14 份
ls -1t "$BACKUP_DIR"/etc-*.tar.gz 2>/dev/null | tail -n +15 | xargs -r rm -f
放在清理脚本末尾即可。这样每天有一份 `/etc` 快照,保留 14 天,出问题直接解包对照。
五、踩过的坑
**1. timer 不触发**:`systemctl enable` 了但没 `--now`,或者只 enable 了 service 没 enable timer。检查 `systemctl list-timers` 里有没有条目。
**2. `Persistent=true` 依赖时间戳文件**:在 `/var/lib/systemd/timers/` 下。如果手动删了这个目录,补跑功能会失效,重新 `daemon-reload` 会重建。
**3. 删内核把系统搞挂**:一定要用 `uname -r` 排除当前内核,别用 `dpkg -l | head -1` 这种粗暴写法。
**4. journal 占用比想象大**:默认上限是磁盘的 10%,40G 盘就是 4G。`--vacuum-size=200M` 收得比较狠,但排查问题时 200M 够用了。
**5. 脚本在 timer 里跑失败但手动能跑**:多半是 PATH 不同。systemd 的 PATH 很精简,脚本里用绝对路径最稳。
小结
整套配置不到 50 行,解决的是「日常运维容易忘」这个真问题。核心就三件事:清理脚本 + service + timer,加上 `Persistent=true` 保证不漏跑。
配好之后每天 4:30 左右自动跑一次,磁盘长期稳定在 20% 以下,再也不用惦记。
- 点赞
- 收藏
- 关注作者
评论(0)