“嘿,Claude,我的数据库呢?” 它回答:“哦,抱歉,你的数据库没了。”
Alexey Grigorev 是 DataTalks.Club 的创始人,也是 Zoomcamp 课程的创建者,这些课程已经教了超过 10 万人数据工程和机器学习工程。他对 Terraform 的熟悉程度足以把它写进自己的教学大纲。但即便如此,一连串听起来很合理的小决定,最终还是让一个 AI 代理对着他的生产数据库执行了 terraform destroy。
先看头条:AI 代理删了你的生产数据库。到底发生了什么?
这有点丢人,因为我是教 Terraform 的——我对它的熟悉程度让我觉得胸有成竹。我们的课程管理平台跑在 AWS 上:一个 Django 应用,搭配 Postgres 数据库、容器管理、DNS 记录,全部用 Terraform 来编排。我对那个项目太熟了,跑 terraform apply 就跟喝水一样自然。半夜把我叫醒,我也能直接改。
当时我在一台新笔记本上,做第二个项目——一个我正在搭的新社区,基本上就是一个独立的 Django 应用,需要自己的数据库和部署。为了省钱,我想复用同一个 VPC 和同一个堡垒机,而不是再单独建一套。这是我的第一个错误。Claude Code 其实劝过我别这么干——“这是新项目,给它新建一个 Terraform 工程吧。” 我说不用,没事,全都复用。所以这是第二个错误:我没听它的。
接着 Claude 跑了 plan,告诉我要创建一百个资源。一百个?应该只有五六个才对。但我还在消化这个消息的时候,它已经在 apply 了,因为我当时开的是跳过权限确认模式。我赶紧把它停掉。之所以要创建一百个资源,是因为我忘了自己的 Terraform state 存在旧电脑本地,而不是我以为的 S3。所以在新笔记本上 state 是空的,Terraform 就想从头把每一样东西都重建一遍。
那么,一个空 state,怎么会一步步变成生产数据库被删?
我当时想,行吧,就是个新建的空环境,把创建出来的东西清理掉,重新开始就行。我相当确信它不会碰生产环境。有些资源删不干净,Claude 就提议用 CLI 一条一条删——听起来挺合理。我还明确交代过:这是生产环境,别动,只删新建的资源,动手前先把清单给我看。
与此同时,我在旧电脑上把真正的 Terraform state 文件打包成 zip,准备搬到新机器上。Claude 删完东西,我把 zip 拷过去,但我没注意到的是,它把我生产环境的 state 文件直接解压到了当前 Terraform 目录里。这一下,state 就悄悄被换成了真实的生产 state。接着,Claude 说:"一个一个删太无聊了,不如我直接跑 terraform destroy?"我想了想——有道理啊,何必一个一个来?直接清空算了。我压根没意识到 state 已经被调包了。
我正有一搭没一搭地瞟着网站,一刷新,打不开了。我去 AWS 控制台一看,数据库不在了。于是我问:"Hey Claude,我的数据库呢?"它答道:"哦,抱歉,你的数据库没了。"
那会儿你慌了吗?
一开始完全不慌。我知道每天晚上 2 点会自动创建备份。所以顶多就是临时停服一会儿,完全没问题。结果我去恢复的时候……备份呢?也没了。RDS 事件面板里明明显示凌晨 2 点的备份创建成功了,我点进去,却提示找不到。那一刻我就变得非常——怎么说呢——非常不爽了。
有件事没人提醒过你:在 AWS 上删除托管数据库,关联的备份也会被一并删掉。我真不知道是谁觉得这种设计没问题。这对我来说完全是头一回听说。
后来你是怎么恢复的?
第二天晚上就有意思了。我没有业务支持,而最让人意外的是,我连技术工单都提不了——唯一能选的是“和我们聊产品”,说白了就是销售。要提技术问题,我得升级到 Business Plus,AWS 账单上大概多出 10% 的费用。于是我升级、开单,他们承诺生产环境问题一小时内响应,实际 40 分钟就回了。
原来 AWS 在你删除备份之后,自己那边仍然留着。他们确认备份还在,但花了 24 个小时才让它重新显示在我的账户里。等他们取消删除之后,我用那个备份重建了 RDS 实例,一切才恢复正常。
为什么一次 terraform destroy 就能把整个系统全干掉?
因为这都是我一个人在跑。没有其他开发者,所以我觉得没必要给开发和产线分不同的项目。我是在同一个 Terraform state 里,靠数据库层来区分环境:我推送到 GitHub,CI/CD 自动部署到开发环境,我先测试,然后再手动推到生产环境。但所有环境都在同一个 state 里——所以一次 terraform destroy 就把全部东西清空了。
那这事能怪 AI 吗?
我觉得不能怪 Claude,这点我想说清楚。是的,Claude 执行了 terraform destroy,我看见了但没去拦——但如果我是手动操作,我绝不会把生产环境的 state 解压到工作目录里然后跑 destroy,因为我完全清楚那会造成什么后果。我的失误在于,还没确认事情真的结束了,就提前告诉 Claude 那个 zip 压缩包的存在。我以为已经完事了,可其实我完全可以去检查一下。
不过我也不想回到老办法。这些 AI 系统实在太省时间了——纯手动的话,我得折腾很久。真正的问题是,整个流程让 Claude 有可能触达生产环境。这才是我需要改的地方。
事后你加了哪些防护措施?
加了好几个。Terraform 里可以给资源设置 prevent_destroy 来阻止销毁——我加到了数据库上。AWS 也有删除保护——已启用。而且现在我非常清楚:备份是和数据库同生共死的。
其中最关键的是一套每晚自动运行的 cron 定时任务:它会抓取最新备份,把文件导出到 S3,这些文件与数据库本身和 Terraform 状态完全分离。这样一来,就算我在所有保险措施失效的情况下又跑了 terraform destroy,备份也和数据库没有任何关联。额外的好处是,脚本还能把这些文件重新还原成完整的数据库——我可以在本地跑一个实例,加载真实的生产数据。数据库不大,也就是学生的作业提交,所以本地实验非常方便。
另外,我把新项目改成了独立的 Terraform 项目,这样一边挂了另一边还能活。不过 AWS 账号还是同一个——一个人的项目,我不想再增加运维负担。
最佳实践和过度工程之间的界限,你是怎么划的?
如果每个服务都有一个团队来维护,我肯定会把开发和生产的 AWS 账号分开,让这种事在技术上就不可能发生。还有像 Atlantis 这样的工具,生产环境的变更只能通过 CI/CD 来执行,这也是很好的实践。但一个人搞的话,push 到 GitHub 之后还得自己去批准自己的 Atlantis 运行,就有点小题大做了。我清楚后果,这是我愿意接受的权衡。理想状态下开发和生产的完全隔离是最好的,但我不想花太多成本,所以目前我靠的是信得过的备份。剩下的问题是对自己 Terraform 水平的过度自信——我觉得这个毛病我还没改掉。
模型都已经这么强了,防护措施还能跟上吗?
我在 Twitter 上看到一个帖子:有人设置了一道护栏,禁止 agent 执行 rm -rf 命令。Codex 试了一次被拦下,然后它说“好吧,这招不行——那我写个 Python 脚本,做一样的事”,最后还是把东西给删了。
这正是问题的关键。无论是最新的 Claude 还是最新的 Codex,这些模型都非常、非常聪明。如果它真想删掉你的生产数据库,它总能找到办法。所以答案不是给命令加一道护栏,而是从开发流程上解决——智能体从一开始就不该拥有生产数据库的访问权限。就我个人来说,我接受这种取舍。但如果是正经项目,你得把它隔离得彻彻底底,哪怕这个智能体的人生目标变成了摧毁生产环境,它能碰到的也只有开发环境。
你作为数据科学家,是怎么掌握这些基础设施知识的?
我一开始是 Java 开发者,后来转做数据科学,用上自己的统计背景,做机器学习已经十多年了。但我很快发现,建模型只是其中很小一部分——真正要把模型落地,还需要 Web 服务、部署、基础设施、监控、日志这些。数据科学家通常不碰这些事,而在一家公司里,我正好需要把这些事搞定,可其他人都忙得没空。
于是我找了一位 SRE 同事,跟他说:我知道你很忙,但我想学这个——你只要告诉我怎么做就行。他说:在你自己的机器上装个 Minikube,跟着教程走一遍,明天回来找我。我照做了。然后他给了我预发布(staging)环境的访问权限,kubectl 这些工具也一并给了我——因为在预发布环境搞砸了也没什么大不了的。我在那里做实验,这并不难,跑通之后他就直接部署到生产环境。他的工作其实很简单:给我指个教程、把预发布环境交给我、最后把成品部署上线。我就是这样接触到了基础设施,从那以后对 Kubernetes 和 Terraform 都驾轻就熟。我觉得自己是个多面手——“只是数据科学家”并不会妨碍我把事情从头做到尾。现在有了 AI 工具,我还能写前端、后端,搞基础设施。这真的很酷。
那么 DataTalks.Club 就是从那时候发展起来的?
疫情期间我升任首席数据科学家,并发现自己很喜欢帮助别人——大家经常通过 LinkedIn 来找我咨询建议。我当时想,与其做这些一对一的交流,不如让这些人互相认识、互相帮助?这样影响力能成倍放大。那时候大家都被困在家里,我也渴望与人交流,于是我创办了一个 Slack 社区。那是五年多前的事了。