IaC和Terraform概述:环境能创建出来,为什么还要写成代码?
开一台云服务器,通常不需要写代码。在控制台选地域、镜像、规格和网络,确认之后等它启动就行。
控制台已经能完成的事情,为什么还要换一种语言重新描述?学习 IaC 时,我觉得这个问题值得先想清楚。
如果只创建一台临时机器,手动操作确实方便。麻烦出现在第二套环境上。测试环境跑通之后,生产环境也要准备同样的网络、安全组和服务器。照着控制台再点一遍,哪些参数必须一致,哪些参数应该变化?过一段时间,同事又调整了安全组,原来的操作文档还能不能作为依据?
创建动作结束得很快,后面的维护却会持续很久。基础设施即代码,也就是 Infrastructure as Code,主要处理的就是这段持续变化的过程。
从控制台到脚本,已经解决了哪些问题?
云资源通常可以通过控制台、CLI 或 API 创建。控制台适合人工操作,CLI 方便写脚本,API 则可以接入应用和流水线。它们最后都会调用云平台提供的能力。
把操作写成脚本,已经能省掉不少重复劳动。例如创建安全组、开通服务器,再把公网 IP 输出给后续部署任务。只要接口和参数明确,这条链路就可以自动执行。
但脚本运行到一半失败时,问题会多起来:安全组已经创建,服务器还没有创建,再跑一次会怎样?如果机器已经存在,只想修改实例名称,脚本会更新原来的机器,还是再开一台?
这些逻辑都能自己写,只是脚本需要逐渐掌握资源查询、身份识别、差异比较和失败恢复。随着管理对象增多,维护成本也会增加。
Terraform 把这部分资源管理能力做成了通用工具。我们描述希望得到的资源,工具结合已经管理的对象和云平台返回的信息,计算接下来应该执行的操作。
声明式配置到底声明了什么?
可以把一个基础设施需求写成几句话:
- 在指定地域准备一台 Ubuntu 云服务器。
- 服务器接入指定子网,并绑定一个安全组。
- 安全组允许管理端访问 SSH。
- 创建完成后,提供服务器的公网 IP。
这里描述了目标和资源关系。服务器创建前需要哪些信息、哪些 API 要先调用,可以交给工具根据引用关系安排。
下面是 Terraform 中声明安全组的一个片段:
1 | resource "tencentcloud_security_group" "web" { |
这段配置表达的是:当前配置要管理一个腾讯云安全组,它在 Terraform 内部的名称是 web,云上的名称是 iac-demo-web。第一次应用时需要创建;资源已经存在且配置没有变化时,就不应该再创建一个副本。
Terraform 的这种行为依赖状态记录和 Provider 的实现。不能据此推断“任何脚本执行多少次都没有副作用”。例如在资源创建后追加一段远程 Shell,它是否能重复执行,还要看脚本本身。
IaC 是一类工程实践,也不要求所有工具都使用同一种语言、同一种状态文件。本文讨论的声明式配置和 state,是理解 Terraform 这条实现路线的重点。
代码、state 和云上资源为什么要分开?
配置文件和 state 都描述资源,初看似乎保存一份就够了。
实际创建安全组之后,云平台会返回一个 ID。Terraform 需要记录:配置里的 tencentcloud_security_group.web,对应云上的哪个安全组。下一次修改配置时,它才能找到同一个对象。
三者承担的工作不同:
| 对象 | 保存什么 | 用来回答什么 |
|---|---|---|
.tf 配置 |
期望的资源属性与依赖关系 | 希望环境变成什么样? |
| state | 资源地址与远端对象的映射,以及已记录的属性 | 这份配置正在管理哪些对象? |
| 云平台 | 实际存在的资源及其当前状态 | 资源现在到底是什么样? |
state 是上一次记录下来的信息,云上资源可能已经被其他操作改变。正常执行 terraform plan 时,Terraform 会通过 Provider 读取相关资源,刷新它对远端状态的认识,再生成变更计划。
如果有人从控制台修改了被管理的属性,下一次计划可能就会显示差异。这叫配置漂移。此时需要判断这次修改是否应该保留:合理的调整应写回配置,不合理的调整可以通过后续应用纠正。
Terraform CLI 通常在执行命令时进行这些工作。它不会因为电脑里保存着一份 .tf,就一直在后台检查云资源。
写进 Git 后,变更怎样被审查?
假设原来只允许管理端访问 SSH,现在要开放一个业务端口。通过控制台直接修改,评审者只能依赖操作说明和平台日志。通过 IaC 修改,则可以先看到配置差异,再检查 Terraform 计算出的执行计划。
一条常见的流程是:
1 | 修改配置并提交 Git |
Git diff 和 plan 要一起看。修改一行代码,有时会触发资源替换;一个看起来很小的参数调整,可能意味着先删除旧资源再创建新资源。单看代码行数,容易低估影响。
IaC 也给自动化检查提供了入口。例如在流水线里检查网络开放范围、资源标签和允许使用的实例规格。不过这些检查需要额外配置,Terraform 不会自动知道团队的生产标准。
版本控制能回退到什么程度?
配置存进 Git,可以追溯谁在什么时候修改了什么,也可以恢复旧版本的配置。接下来仍然需要重新生成计划,判断怎样把当前环境调整到旧配置描述的样子。
这里有一个不能省略的限制:已经删除的数据库,即使按旧配置重新创建,里面的数据也不会自动回来。数据恢复需要备份和恢复机制,云盘、IP 等对象能否原样恢复,也取决于资源本身的生命周期。
因此,我会把“回退配置”和“恢复业务”分开检查。前者由版本管理帮助完成,后者还涉及数据、访问入口以及服务是否恢复可用。
类似地,相同配置能够提高环境的一致性,但不能承诺每次得到完全相同的结果。若配置查询“当前可用的某个镜像”并直接取第一条,下一次查询结果变了,新建环境也可能变化。需要稳定复现时,镜像、依赖版本和关键输入都要明确下来。
Terraform 负责到哪里?
Terraform 由 HashiCorp 开发,通过 Provider 接入不同平台。腾讯云、AWS、阿里云等云平台,以及 Kubernetes、Cloudflare 等服务,都可以通过相应的 Provider 管理。
多平台支持带来的便利,是可以在一个工作流里管理不同系统。至于具体资源怎么写,仍然要看各个平台的资源模型。腾讯云 CVM 的配置不能只改一个 Provider 名称,就变成 AWS EC2。
在交付链路中,我会先按管理对象划分职责:
| 管理对象 | 常见的处理方式 |
|---|---|
| 网络、云服务器、云数据库等资源 | Terraform 调用平台 API 管理 |
| 机器内部的软件与系统配置 | 镜像预置、cloud-init、Ansible 等 |
| 集群里的应用运行状态 | Kubernetes 及相应的应用交付工具 |
这些边界可以重叠。例如 Terraform 有 Helm Provider,也能调用脚本安装软件。是否放在同一份配置里,要考虑它们的变更频率、依赖关系和失败后的恢复方式。
学习时把虚拟机、K3s 和 Argo CD 串起来,有助于看懂完整的依赖链。实际维护时,如果应用频繁更新,而基础设施变化很少,就值得把两者的执行流程分开。
笔记还提到了 Pulumi 和 Crossplane。它们都与 IaC 有关,但使用方式不同:Pulumi 支持使用通用编程语言描述资源;Crossplane 基于 Kubernetes 的资源与控制器机制管理外部基础设施。这里先把 Terraform 的工作流学清楚,工具对比可以留到出现具体选型需求时再做。
从一个小环境开始验证
对学习项目,我更愿意先管理一台服务器和它的安全组。创建完成后,修改一个容易检查的属性,重新生成计划,再观察实际结果。最后确认这套环境能按预期清理。
这几步能暴露很多只看概念时察觉不到的问题:凭证从哪里读取,资源 ID 保存在哪里,计划是否出现了意外删除,重复执行为什么没有继续创建新机器。
下一篇《Terraform概述》会沿着这套环境,展开 HCL、Provider、资源依赖和 state 的关系。
参考资料
- Terraform 文档
- Terraform Provider Registry
- 课程代码:
lesson/module_2/demo_1、demo_2、demo_3。

