腾讯云轻量应用服务器不支持自动快照:用本机脚本 + systemd timer 实现双槽位轮换

腾讯云轻量应用服务器没有自动快照功能,我的实例又只有 2 个快照槽位。如果只靠手动创建,恢复点很快就会被用完,或者干脆想不起来做。最后我用一个跑在服务器本机的脚本调用腾讯云 API,自动删除最旧的自动快照、再创建一个新快照,由 systemd timer 每周日凌晨 04:30 触发一次。
先把最终方案放在前面,只想抄作业的读者可以直接用这套配置。
快速解决
- 两个快照槽位全部用于自动快照,不保留固定人工基线。
- 自动快照统一使用
Auto-Snapshot-前缀,脚本只删除这个前缀下的快照,其他名称的人工快照默认受保护。 - 每周执行一次,时间为每周日 04:30,由
systemd timer调度,不用 Cloudflare Workers,也不用传统 cron。 - Timer 设置
Persistent=false:如果服务器在计划时间没有运行,本周直接跳过,恢复开机后不补跑。 - 脚本运行在被备份的轻量云本机。这样服务器发生严重故障、脚本无法运行时,不会有外部调度器继续创建可能已经损坏的新快照并覆盖旧恢复点。
环境
| 项 | 值 |
|---|---|
| 实例 | lhins-xxxxxxxx(替换为自己的实例 ID) |
| 地域 | na-siliconvalley(美国西部 / 硅谷) |
| 脚本路径 | /root/tencent-snapshot.sh |
| 自动快照前缀 | Auto-Snapshot- |
| 保留数量 | 2 |
脚本顶部的关键配置:
TENCENT_SECRET_ID=""
TENCENT_SECRET_KEY=""
TENCENT_REGION="na-siliconvalley"
INSTANCE_ID="lhins-xxxxxxxx"
SNAPSHOT_PREFIX="Auto-Snapshot-"
KEEP_SNAPSHOTS=2
SecretId 与 SecretKey 直接写在这台服务器的本地脚本里,只保留在服务器本地,不要同步到任何云端笔记或版本管理。脚本文件权限:
chmod 700 /root/tencent-snapshot.sh
CAM 权限
快照脚本使用独立的 CAM API 密钥,只授予快照相关权限:
{
"version": "2.0",
"statement": [
{
"effect": "allow",
"action": [
"lighthouse:DescribeAllSnapshotsOverview",
"lighthouse:DescribeSnapshots",
"lighthouse:DescribeSnapshotsDeniedActions",
"lighthouse:CreateInstanceSnapshot",
"lighthouse:DeleteSnapshots"
],
"resource": [
"*"
]
}
]
}
测试时踩过一个坑:调用创建快照报 UnauthorizedOperation.NoPermission,检查后发现是策略里漏了 lighthouse:CreateInstanceSnapshot,补上之后创建成功。
快照轮换逻辑
脚本每次执行依次做这些事:
- 执行可选健康检查。
- 调用
DescribeSnapshots查询当前实例快照。 - 如果存在非
NORMAL状态的快照,停止,不进行删除。 - 如果已有 2 个快照,只从
Auto-Snapshot-前缀的快照里找最老的一个。 - 调用
DeleteSnapshots删除这个最老的自动快照。 - 等待旧快照确认删除完成。
- 再执行一次健康检查。
- 执行
sync,尽量把文件系统缓存刷入磁盘。 - 调用
CreateInstanceSnapshot创建新快照。 - 等待新快照进入
NORMAL状态后结束。
因为只删指定前缀的快照,其他名称的人工快照默认受到保护,不会被轮换掉。
两个槽位就这样持续滚动,实际看到的快照名类似:
Auto-Snapshot-20260906T203000Z
Auto-Snapshot-20260913T203000Z
下一周执行时删除较旧的一个,再生成新的恢复点。
健康检查
脚本支持 PRECHECK_COMMAND,留空则跳过:
PRECHECK_COMMAND=""
也可以换成一个简单的检查,比如确认文件系统可写:
PRECHECK_COMMAND='touch /tmp/.snapshot-check && rm -f /tmp/.snapshot-check'
设计原则:健康检查失败就停止轮换,避免在服务器明显异常的时候删除历史恢复点。创建快照前保留一个固定动作,把缓存刷进磁盘:
PRE_SNAPSHOT_COMMAND="sync"
systemd Service
文件:/etc/systemd/system/tencent-snapshot.service
[Unit]
Description=Tencent Lighthouse Automatic Snapshot
After=network-online.target
Wants=network-online.target
[Service]
Type=oneshot
ExecStart=/root/tencent-snapshot.sh
TimeoutStartSec=30min
这个 service 只负责把脚本执行一次,不常驻后台。
systemd Timer
文件:/etc/systemd/system/tencent-snapshot.timer
[Unit]
Description=Run Tencent Lighthouse Snapshot Weekly
[Timer]
OnCalendar=Sun *-*-* 04:30:00
AccuracySec=1min
Persistent=false
[Install]
WantedBy=timers.target
Persistent=false 是刻意设置的,不是忘了开。如果服务器在周日 04:30 处于关机或故障状态,恢复后不会立刻补做快照,而是保留已有恢复点,等下一周正常轮换。这一点和很多备份 timer 的默认习惯相反,原因在后面的取舍部分说明。
启用自动运行
systemctl daemon-reload
systemctl enable --now tencent-snapshot.timer
确认 timer 已启用:
systemctl is-enabled tencent-snapshot.timer
预期输出:
enabled
确认 timer 正在等待:
systemctl is-active tencent-snapshot.timer
预期输出:
active
查看下一次执行时间:
systemctl list-timers --all | grep tencent-snapshot
手工测试
先检查 Bash 语法:
bash -n /root/tencent-snapshot.sh
无输出即通过。
直接运行脚本:
/root/tencent-snapshot.sh
也可以模拟未来 timer 的调用方式:
systemctl start tencent-snapshot.service
查看执行状态:
systemctl status tencent-snapshot.service
注意 Type=oneshot 的 service 执行成功后会变成 inactive (dead),这是正常现象,重点看退出状态是不是 0/SUCCESS。
日志与排障
看最近 100 行:
journalctl -u tencent-snapshot.service -n 100 --no-pager
看最近 7 天:
journalctl -u tencent-snapshot.service --since "7 days ago"
实时跟随:
journalctl -u tencent-snapshot.service -f
一次正常轮换的日志依次是:
开始处理实例
健康检查通过
查询当前快照
删除最老自动快照
等待删除完成
执行 sync
创建新快照
等待快照进入 NORMAL
快照轮换完成
为什么调度放在本机,而不是 Cloudflare Workers
最早的想法是把调度放到 Cloudflare Workers 上,好处是服务器自己出故障时,备份调度器不会跟着一起失效。这个方案最后放弃了,原因就出在那 2 个快照槽位上:
如果服务器已经发生数据损坏,但腾讯云控制面仍然能正常创建快照,外部调度器会按计划继续跑——每跑一次就删掉一个旧快照、写入一个基于损坏状态的新快照。两个槽位很快转完一轮,最后连一个干净的恢复点都不剩。
反过来,把调度放在本机是一种 fail-safe:服务器严重故障到本地脚本跑不起来时,自动快照自然停止,现存两个恢复点不会再被滚动覆盖。配合 Persistent=false,服务器停机期间同样不会补跑。
每周一次而不是每天,也是同一个限制下的选择。运行越频繁,两个恢复点之间的时间跨度越短。每周一次意味着通常可以保留本周和上周两个恢复点,更偏向灾难恢复,而不是细粒度的历史版本。
注意事项
- 腾讯云快照是系统盘级恢复点,不应视作唯一的数据备份方案。
- 如果数据库或应用数据非常重要,还应该增加独立的数据级备份,比如数据库 dump、配置文件归档或对象存储备份。
- 修改
SNAPSHOT_PREFIX之后,要确保现有两个希望被自动管理的快照也改成相同前缀,否则脚本会把它们当成人工快照并拒绝删除。 - 不要把腾讯云 SecretKey 写进云端笔记、Git 仓库或日志。
常见问题
腾讯云轻量应用服务器支持自动快照吗?
只有 2 个快照槽位时,为什么不把调度放在 Cloudflare Workers 等外部调度器上?
systemd timer 为什么设置 Persistent=false?
为什么每周一次而不是每天?
调用创建快照时报 UnauthorizedOperation.NoPermission 怎么办?
KEEP READING