不知你是否经历过这种名场面:为了快速修复一个线上Bug,直接登录云控制台手动改了安全组规则,想着“回头再补文档”。结果三个月后,系统扩容,新的实例自动应用了旧的配置,服务直接不可用,所有人都在排查代码,最后发现是基础设施配置漂移。
我曾经也是“控制台点点点(ClickOps)”的忠实拥趸,觉得写代码管理服务器太麻烦。直到三年前的一个周五下午,因为手动操作失误,我不小心把生产环境的RDS实例当成测试环境给重启了——那几分钟的报警声,我现在想起来还手心冒汗。
从那时候起,我开始死磕Terraform,强制自己和团队走IaC(基础设施即代码)路线。这几年踩坑无数,今天想复盘一下,从“能用”到“好用”,我们到底做对了哪些事。
拒绝“巨石”配置,模块化才是解药
刚开始接触Terraform时,为了图省事,我把所有的资源定义(VPC、EC2、RDS、S3)全塞进了一个 main.tf 文件里。起初看着挺爽,一个文件掌控天下。
但随着业务扩张,问题来了:
我们的核心业务系统竟然有几千行代码堆在一个文件里。每次执行 terraform plan,光是刷新状态就要等上5分钟。更可怕的是,有次新来的同事想改一下S3的权限,结果因为没看清上下文,手滑删掉了一段VPC的配置,差点造成整个网络层重建。
这次事故让我意识到:基础设施也需要“微服务化”。
我们后来的做法是,严格遵循**模块化(Modules)**原则。不要重复造轮子,也不要搞大杂烩。我们将基础设施拆解为基础网络、应用服务、数据存储三个层级。
# 现在的调用方式:清晰、解耦
module "vpc" {
source = "./modules/network"
cidr = "10.0.0.0/16"
}
module "app_cluster" {
source = "./modules/compute"
vpc_id = module.vpc.vpc_id
instance_count = 3
}
落地建议:
建立一个标准的目录结构至关重要。我推荐使用 modules/ 存放通用模板(如创建一个标准的Web服务器),而在 environments/(dev, stage, prod)中去调用这些模块。这样,你只需要测试一次模块代码,就能放心地在生产环境复用,彻底消灭“开发环境没问题,上线就崩”的玄学。
别把状态文件(State)留在本地
这大概是新手最容易踩的坑,没有之一。
Terraform的核心在于 tfstate 文件,它记录了云上资源的实际状态。最开始,我们团队只有两个人,大家都在自己电脑上跑代码,tfstate 文件就存在各自的本地硬盘里。
有一次,我休假去露营了,同事急需扩容服务器。但他电脑上的状态文件是旧的(因为我上次更新完没同步给他),他一执行 terraform apply,Terraform以为现有的几台服务器是“多余的”或者“不存在的”,试图重建资源,直接导致了严重的资源冲突和状态锁死。
解决方法其实很简单,但必须强制执行:远端存储(Remote State)。
我们将状态文件托管在AWS S3(配合DynamoDB做锁机制)或者阿里云OSS上。这样,无论谁在操作,Terraform读取的永远是唯一的、最新的“真理”。
“基础设施的状态,是团队的共同资产,绝不是某个工程师电脑里的私有文件。”
具体操作: 配置 Backend 是项目初始化的第一步。
terraform {
backend "s3" {
bucket = "my-company-tfstate"
key = "prod/app.tfstate"
region = "ap-northeast-1"
dynamodb_table = "terraform-locks" # 防止两个人同时操作
}
}
这就好比代码必须进Git仓库一样,状态文件必须进云端存储。自从上了这个锁机制,我们再也没出现过多人协作导致配置被覆盖的乌龙。
告别“裸奔”,把Plan作为代码审查的一部分
以前我们的发布流程是这样的:开发写好 .tf 文件 -> 本地跑 terraform plan 看一眼(甚至不看) -> 直接 terraform apply -> 祈祷不报错。
这种“裸奔”上线非常危险。因为人眼是会疲劳的,面对控制台输出的几百行绿字(新增)和红字(删除),你很难瞬间发现那个关键的数据库参数被修改了。
我们引入了 GitOps 的工作流。
现在,任何基础设施的变更,都必须提 Pull Request (PR)。我们配置了 CI 工具(如 GitHub Actions 或 GitLab CI),当 PR 提交时,机器人自动运行 terraform plan,并将输出结果以评论的形式贴在 PR 里。
真实收益: 就在上个月,这个机制救了我们要命的一击。一个实习生在调整负载均衡配置时,误删了一个关键的 Listener 规则。如果不看 Plan,直接 Apply,线上流量瞬间就会中断。但在 PR 评论区,那个显眼的红色 "-" 号(表示删除)被资深运维一眼揪了出来,直接驳回了合并请求。
这不仅仅是工具的升级,更是流程的规范。它强制我们在执行毁灭性打击之前,有一个冷静的“二次确认”窗口。
写在最后
使用 Terraform 管理云资源,最大的门槛其实不是 HCL 语法,而是思维方式的转变——从“命令式”(告诉机器怎么做)转变为“声明式”(告诉机器我要什么)。
虽然前期编写代码、梳理资源、导入现有架构会非常痛苦(我花了整整两个月才把遗留资产理顺),但当你在周五下午只需合并一行代码,就能优雅、安全地完成全套环境部署时,你会发现这一切都是值得的。
现在,我想把麦克风交给你: 你在管理云资源时,是更倾向于“控制台可视化操作”带来的直观,还是“IaC代码化”带来的可追溯?或者你有更惨痛的“删库”经历?
欢迎在评论区分享你的故事,哪怕是吐槽也好。
给想落地的朋友3个具体行动建议:
- 从非核心业务入手: 别上来就重构生产数据库,先拿测试环境的一台跳板机或者日志服务器练手。
- 开启状态锁: 哪怕团队只有你一个人,也请配置 Remote Backend 和 State Locking,这是职业素养。
- 善用
terraform import: 只有新资源才能用代码管理是误区,花点时间把旧资源 import 进来,哪怕只是为了看清楚现状。