随笔 | 两只 VPS 的一次大扫除——AI 运维的实践与教训
两只 VPS 的一次大扫除——AI 运维的实践与教训
两台服务器,一个 AI 助手,三天的周末。这是一次集中运维的记录。
如果说前一篇讲的是一个容器怎么被我搞丢的,这一篇讲的是一个周末里两台机器上发生了什么——有教训,有成就,也有对「AI 运维」这个新模式的思考。
一、RSS 阅读器的复活记
先从最惨的说起。
家里的 RSS 阅读器(Tiny Tiny RSS)跑了好几年,底层的 PostgreSQL 还是 9.3——2013 年的版本。不是不想升,是「能用就别动」。这种心态,做运维的都懂。
AI 助手接手升级任务后,按部就班地执行:
docker exec postgres pg_dump -U ttrss ttrss > backup.sql备份成功。然后:
docker-compose down -v-v。删 volumes。
那时旧数据库本身已有系统表损坏——pg_attribute 断裂、pg_class 报错——但至少数据还在。-v 之后,连救的机会都没了。更讽刺的是,备份文件虽然生成了,但备份时机不对,导出的内容不完整。
第一课:备份成功不等于备份可用。以后凡备份必须验证。
重建:没有包袱反而更干净
数据既然丢了,剩下的事反而简单。新配置直接大步跨到 PostgreSQL 17-alpine:
services:
database.postgres:
image: postgres:17-alpine
container_name: postgres
restart: unless-stopped
deploy:
resources:
limits:
memory: 512M
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ttrss"]
interval: 30s
timeout: 10s
retries: 5顺带加了 Mercury Parser(全文提取)和 OpenCC(简繁转换)。从前的架子里没有这些——不是不想加,是一直觉得「以后再说」。
不过话说回来,一个 RSS 阅读器加简繁转换到底有什么用? 大概就是那种「我可以不用,但不能没有」的赛博囤积癖。说不定哪天订阅了一个用繁体字写技术文章的博客呢?
新服务加起来常驻 215MB 内存,比旧的还省。
磁盘占位符的智慧
在重建过程中还发现一个情况:VPS 硬盘较小,备份和数据库有时候会把磁盘撑满。解决方案是在根目录放一个 2GB 的占位文件 /placeholder:
fallocate -l 2G /placeholder备份脚本运行时先检查磁盘剩余空间。如果低于 3GB,自动删掉占位文件腾空间;如果腾完还不够,发告警通知。
这个方案很土,但很有效。像家里预留一把紧急钥匙——平时挂在那,关键时刻能救命。
二、另一台 VPS 上:自建 S3 对象存储
运维这件事有个规律:一个问题往往引出另一个问题。RSS 阅读器的灾难让我意识到备份体系太脆弱了——所有备份都躺在同一台机器的硬盘上。硬盘坏了呢?
解决方案是在第二台 VPS 上部署 S3 兼容的对象存储。选用的是 RustFS——一个用 Rust 写的轻量 MinIO 替代品,以约 40MB 内存跑起来了。
部署过程
docker-compose pull
docker-compose up -d
docker exec rustfs mc alias set local http://localhost:9000 backup SeekdoorBackup2024!
docker exec rustfs mc mb local/ttrss-backup
docker exec rustfs mc mb local/blog-backup两个 bucket:
ttrss-backup— 数据库备份,保留 6 个版本blog-backup— 博客文件备份,保留 30 天
备份脚本改造
旧的备份脚本用 SCP 把文件推到远程——简单粗暴,但不支持版本管理,没有过期清理。
新脚本用 mc cp 推到 S3:
# TTRSS: PostgreSQL 备份 + S3 同步
pg_dump -U ttrss ttrss -Z9 > ttrss_$(date +%Y%m%d).sql.gz
mc cp ttrss_*.sql.gz local/ttrss-backup/
mc rm --older-than 6d local/ttrss-backup/ --recursive
# Blog: SQLite 文件备份
cp /opt/typecho/data/typecho/usr/blog.db blog_$(date +%Y%m%d).db
mc cp blog_*.db local/blog-backup/
mc rm --older-than 30d local/blog-backup/ --recursive每台机器的备份不再依赖对方存活。一台挂了,另一台上还有副本。
三、AI 运维的双刃剑
这次集中运维有一个贯穿始终的特点:所有操作都由 AI 助手(Hermes Agent)通过 SSH 完成。
我只需要说「去把 TTRSS 升级了」「在这台机器上部署 S3 存储」「把备份脚本改一下」,Agent 就会自己分析环境、写配置文件、执行命令。
好的方面
速度。 写一个 docker-compose.yml 从构思到部署,AI 大概花 3 分钟。人类做同样的事——打开文档、回忆语法、上网查例子、调试——至少半小时。
减少心智负担。 我不需要记住 pg_dump 的每个参数、mc 的每个子命令。我只需要描述目标,AI 去翻文档找具体命令。
完整记录。 每一步都有日志输出,可以追溯。传统运维中「我当时怎么配的这个服务」的谜题消失了——问 AI 就行。
不好的方面
TTRSS 的事故就是缩影。AI 执行得太快——我说「升级」,它理解为「备份 → 删旧的 → 建新的」。中间没有一个人类会有的停顿:「备份真的有效吗?我再检查一下。」
这个模式让我想到自动驾驶的级别。现在的 AI 运维大概在 L2——能帮你加速,但你必须盯着方向盘。
写给其他用 AI 做运维的人
几条这三天换来的经验:
- 备份三步走:备份 → 验证 → 再删旧的。 中间缺一步就是事故。
- 容灾演练不是笑话。 这次丢数据后重建之顺利,正是因为 docker-compose.yml 在几天前刚重构过一次,所有配置写得清楚。如果写配置时偷了懒,重建时就要加倍还债。
- 给每台服务器配一个 S3 邻居。 互相备份比自己抱自己靠谱。
- 占位文件是土办法,但管用。 Disk full 是运维最不想见到的情况之一。提前留一个可以牺牲的文件,比等着报警再想办法从容得多。
四、微小的秩序
这两台 VPS 现在各自安好:
| VPS A | VPS B | |
|---|---|---|
| 用途 | 博客 + RSS 阅读器 + 反向代理 | S3 对象存储 + 监控 |
| 内存 | 1GB,已用 ~420MB | 较小,RustFS 仅占 40MB |
| 数据库 | PostgreSQL 17 (SQLite 备选) | 无 |
| 备份 | → S3 (VPS B) | → 暂本地 |
| 新增服务 | TTRSS + Mercury + OpenCC | RustFS (MinIO 兼容) |
| AI 踩坑 | 1 次(数据丢失) | 0 次 |
那 2GB 的占位文件还安静地躺在根目录。希望它保持安静——它一旦消失,就意味着验证了我的备份策略。
五、凌晨三点的服务器
写下这些文字的时候,两台 VPS 上的 cron 可能正在执行凌晨的备份任务。PostgreSQL 17 在压缩导出,RustFS 在接收数据,Traefik 在自动续签名天的证书,占位文件依然占着它的位置。没有人盯着它们,所有的任务都安静地工作。
AI 做运维这件事,我现在的看法是:可以用,但要加护栏。 就像让新手司机开车——你要帮它装好自动刹车和车道保持。
而这个周末最有价值的产出,不是那套崭新的备份体系,也不是 RustFS 的部署——是我对自己运维能力的清醒认识:我依然会犯低级错误,但我有了一个执行效率高出我十倍的助手。关键是从今以后,每次让 AI 执行破坏性操作前,我都会多问一句:「备份验证过了吗?」
2026 年 7 月,于两台 VPS 之间。
全部操作由 Hermes Agent 辅助完成。
最后更新于 2026-07-05 「部分内容存在时效性,如有失效请留言反馈」
除注明外为 袅残烟的冥想盆 原创文章,转载请注明出处。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。