Terraform 是 HashiCorp 开发的声明式基础设施即代码(Infrastructure as Code,缩写 IaC,指用代码描述和管理云资源)工具,2014 年发布,用 Go 语言编写。它通过 HCL(HashiCorp Configuration Language,HashiCorp 配置语言)描述云资源期望状态,以 plan(生成执行计划)与 apply(执行变更)两阶段流程完成资源的创建、更新与销毁。Terraform Registry 提供 3000+ 官方及社区 Provider(云厂商插件),覆盖 AWS、Azure、GCP、Kubernetes、阿里云、腾讯云等主流平台,是目前多云与混合云环境下事实标准的基础设施编排工具。
本文按「认识 → 安装 → 上手 → 深入 → 生产」组织:先讲为什么需要 Terraform 与本地环境安装;再用一个 AWS EC2 示例在 15 分钟内跑通首个资源;随后拆解状态管理、依赖图、模块化等核心能力;最后给出远程状态、CI/CD、漂移检测等生产方案与避坑清单,并附同类工具对比、典型应用场景、常见误区与面试题。
掌握 Terraform 意味着能对云计算资源做版本化、可审查、可复现的交付,这是 DevOps 与 AI 基础设施工程师的核心竞争力,也是多云时代运维自动化的硬门槛。
目录
速览卡是工具类内容的固定首屏模块:30 秒判断「这工具是什么、能不能商用、适不适合我」。
为什么需要 Terraform:把点按操作变成可审查的代码
传统方式下,云资源靠控制台点选或临时脚本创建:没有版本记录、没有代码评审,环境之间配置逐步漂移,账号与区域增多后人肉运维必然失守。而临时脚本是命令式流程,只描述“怎么做”不描述“变成什么样”,重复执行会产生重复资源。这个问题在微服务与 AI 算力集群规模扩大后尤其致命——几十台 GPU 节点的手工交付耗时长且不可复现。
Terraform 采用声明式思路:你在 .tf 文件中描述目标状态,工具负责“如何达成”。核心工作流是 init → plan → apply:plan 输出变更清单(新增/修改/删除),审查通过后 apply 才执行;destroy 可一键清理。幂等性保证同一份配置反复执行结果一致。terraform.tfstate 状态文件记录真实资源与配置的映射关系,是后续 diff 和增量变更的依据。
与 Ansible(面向配置变更、无状态)和 Pulumi(用通用编程语言)相比,Terraform 用专门 DSL 把“基础设施拓扑”本身做成可版本化、可 diff、可协作的产物。它的 Provider 生态横跨 3000+ 平台,多云覆盖广度在同类工具中最大,这也是它成为 IaC 代名词的主要原因。
安装与环境配置:3 步就绪
步骤一:安装二进制。 macOS 推荐 Homebrew;Windows 可用 Chocolatey(choco install terraform)或 winget install HashiCorp.Terraform;Linux(Debian/Ubuntu)建议添加 HashiCorp 官方 apt 仓库,这样升级走系统包管理器,避免手动管理 PATH。也可以直接下载官方 zip 解压到 /usr/local/bin。
步骤二:配置云厂商凭据。 Terraform 本身不保存云账号密码。AWS 用 aws configure 生成 ~/.aws/credentials,或设置 AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY 环境变量,Provider 会读取标准 SDK 凭据链。给 IAM 用户配最小权限即可,不要用账号根密钥。
步骤三:验证与补全。 运行 terraform version 确认安装成功;terraform -install-autocomplete 开启命令行 Tab 补全,提升日常效率。
# macOS:Homebrew 安装brew tap hashicorp/tapbrew install hashicorp/tap/terraform # Ubuntu/Debian:官方 apt 仓库wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpgecho "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.listsudo apt update && sudo apt install terraform -y # 验证terraform version
快速上手:15 分钟在 AWS 创建第一台 EC2
最小可用流程是“写配置 → init → plan → apply → destroy”。先在空目录创建 main.tf,内容包含 required_providers(锁定 aws provider 为 ~> 5.0)、provider 块(指定区域)、一个 data 源查找最新的 Amazon Linux AMI(镜像 ID 按区域自动解析,避免硬编码失效镜像)、一个 aws_instance 资源和一个 output 输出实例 ID。
1. 执行 mkdir terraform-demo && cd terraform-demo,将下方 main.tf 保存到该目录。
2. 准备 AWS 凭据:aws configure 或设置环境变量,确认 IAM 用户具备 EC2 读写权限。
3. 运行 terraform init:下载 aws provider 插件并生成 .terraform.lock.hcl 依赖锁文件。
4. 运行 terraform fmt 统一格式,再运行 terraform validate 做语法与内部引用校验。
5. 运行 terraform plan 查看执行计划,确认它只创建 1 个实例、不会动其他资源。
6. 运行 terraform apply,输入 yes 确认后创建资源。
7. 查看 output 输出的实例 ID,到 AWS 控制台核对;验证完运行 terraform destroy 清理,避免持续计费。
进阶技巧:把可复用的网络、计算逻辑抽到 modules/ 目录形成自定义模块;多套环境用 -var-file=dev.tfvars、prod.tfvars 区分参数,同一份代码交付不同环境。
# main.tfterraform { required_providers { aws = { source = "hashicorp/aws" version = "~> 5.0" } }} provider "aws" { region = "ap-northeast-1"} data "aws_ami" "amazon_linux" { most_recent = true owners = ["amazon"] filter { name = "name" values = ["al2023-ami-2023.*-x86_64"] }} resource "aws_instance" "web" { ami = data.aws_ami.amazon_linux.id instance_type = "t2.micro" tags = { Name = "terraform-demo" }} output "instance_id" { value = aws_instance.web.id}
核心能力详解:4 大支柱
支柱一:声明式配置与执行计划。 HCL 语法描述期望状态而非操作步骤。plan 会列出每个资源的 create/update/delete 三类变更,-out 参数可将计划存入文件供 show 复查;-target 只影响指定资源,缩小变更爆炸半径;plan -detailed-exitcode 以退出码(0 无差异、1 报错、2 有差异)供 CI 脚本消费,是后面漂移检测的基础。
支柱二:状态管理。 terraform.tfstate 是真实世界与配置的映射,记录资源 ID、全部属性与元数据。生产环境必须使用远程后端(S3、Azure Storage、GCS、Consul 等),并配合 DynamoDB 等锁机制防止并发 apply 互相覆盖;state mv、state rm、import 负责调整资源归属和纳管存量资源。
支柱三:依赖图与并行执行。 Terraform 会自动分析资源间引用关系(被引用的资源即依赖)构建有向无环图,图中无依赖的节点并行创建(默认并发 10,-parallelism 可调)。无法从引用推导的隐式依赖用 depends_on 显式声明,避免“安全组还没建好就挂到实例上”的竞态。
支柱四:模块与 Provider 生态。 module 把 VPC、Kubernetes 集群等单元封装成可复用组件,支持输入变量、输出值与版本约束;Terraform Registry 承载 3000+ Provider 与海量公开模块;for_each/count 实现批量创建与条件逻辑,如按可用区循环创建子网。
生产部署与监控:从上线到运维
部署方式一:远程状态后端。 生产环境严禁本地状态文件。用 S3 存储 + DynamoDB 锁是最成熟的免费方案:S3 开启加密与版本控制,DynamoDB 表提供乐观锁,防止多成员同时执行 apply 造成状态损坏。后端在上线第一天就配置,后期迁移成本高。
部署方式二:CI/CD 集成。 在 GitHub Actions 或 GitLab CI 中,对每个 Merge Request 自动执行 terraform plan 并把结果作为评论展示;人工 review 通过后再由具备高权限的流水线执行 apply。Atlantis 是专为 Terraform 设计的 PR 自动化工具,直接在 PR 内完成 plan/apply 对话。dev/staging/prod 用不同 backend key 与不同 tfvars 文件隔离。
部署方式三:策略与安全。 用 checkov、tfsec 对配置做静态扫描(检查公网暴露、加密缺失等);密钥通过 Vault、AWS SSM 或环境变量注入,禁止明文写在 .tf 文件;模块与 Provider 固定版本范围,升级走测试环境验证。生产账号的 IAM 策略按“创建资源所需最小权限”收敛,避免 Terraform Runner 权限过大。
可观测性。 漂移检测是 IaC 的核心运维动作:定时执行 terraform plan -detailed-exitcode,退出码 2 表示实际资源与配置不一致,触发告警工单;云厂商审计日志(如 CloudTrail)可回溯每次资源的变更来源;HCP Terraform 提供 Run 历史、状态版本对比与策略检查,适合需要治理能力的团队。
<p class="para-label">避坑清单:</p>
<ul class="dash-list"><li>坑 1:把 tfstate 提交进 Git。状态文件含数据库口令、私钥等明文敏感值,且并发修改会损坏;必须用远程后端并做访问控制。</li><li>坑 2:无状态锁直接上生产。多人/多流水线同时 apply 会互相覆盖状态,导致资源与实际脱节;务必用 DynamoDB 等后端起锁。</li><li>坑 3:手动编辑 tfstate 或控制台手改资源。状态与真实资源不一致后,下次 plan 会出现意外重建或删除;用 import 和 state 命令矫正,别手改。</li><li>坑 4:Provider 版本写死 latest 或不锁版本。升级可能引入破坏性变更造成资源替换;提交 .terraform.lock.hcl 并在 required_providers 中用 ~> 限定。</li><li>坑 5:用 provisioner(local-exec/remote-exec)做配置管理。官方明确这是最后手段;容器内装软件应优先用 user-data、镜像构建或 Ansible。</li><li>坑 6:生产环境跳过 plan 审查直接 auto-approve。plan 的 diff 是防呆网,能提前暴露替换/删除类高危变更;CI 中把 apply 与 plan 分离并加人工审批。</li></ul>
terraform { backend "s3" { bucket = "my-company-tfstate" key = "prod/network/terraform.tfstate" region = "ap-northeast-1" encrypt = true dynamodb_table = "terraform-state-lock" }}
| 维度 | Terraform | Pulumi | Ansible | CloudFormation |
|---|---|---|---|---|
| 定位 | 声明式 IaC 编排工具 | 代码优先 IaC 工具 | 配置管理与自动化 | AWS 原生 IaC 服务 |
| 编排范式 | 声明式 HCL + plan/apply | 命令式/声明式通用语言 | 声明式 YAML Playbook | 声明式 YAML/JSON 模板 |
| 类型约束 | HCL 静态校验 + validate | 编译器类型检查 | 弱类型,运行时校验 | 模板语法校验 |
| 学习曲线 | 中等,HCL 易上手 | 较陡,需懂编程语言 | 平缓,YAML 门槛低 | 中等,绑定 AWS 生态 |
| 生态集成 | 3000+ Provider,多云 | 100+ Provider,多云 | 海量模块,支持网络设备 | 覆盖全部 AWS 服务 |
| 生产部署 | 远程状态+锁定,最成熟 | 依赖 Pulumi Cloud 或自建 | 无状态,天然适合变更 | 状态由 AWS 托管 |
| License | BUSL-1.1(源码可用) | Apache 2.0 | GPL-3.0 | 专有 |
| 适合谁 | 多云/混合云工程团队 | 习惯写代码的研发团队 | 运维与配置管理场景 | AWS 全栈深度绑定团队 |
选型建议:多云与混合云场景、团队以 DevOps/运维为主时优先选 Terraform,生态与状态管理最成熟;团队以开发者为主且希望用 TypeScript/Python 管理资源,选 Pulumi;已有大量虚拟机、需要持续配置收敛与软件部署,Ansible 更合适;深度绑定 AWS、不想自建状态后端,直接用 CloudFormation。
版本迭代
Terraform 从 0.x 走向 1.x 经历了语言稳定到工程化成熟的过程:1.0(2021)确立升级兼容性承诺,1.6(2023)完成许可切换并引入测试框架,1.8 起围绕 S3 后端、临时资源、OIDC 身份认证等企业级能力持续增强。截至当前,正式发布主线为 1.11.x。
| 版本 | 时间 | 变化 | 提升 |
|---|---|---|---|
| 1.0 | 2021-06 | 首个稳定大版本 | 确立 1.x 内升级不破坏既有配置与状态的兼容性承诺 |
| 1.3 | 2022-10 | 变量与资源增强 | 新增 `sensitive` 变量防止敏感值明文输出;支持资源默认标签 |
| 1.6 | 2023-10 | 许可切换与测试能力 | 从 MPL-2.0 切换至 BUSL-1.1;引入 `terraform test` 与 `import` 配置块 |
| 1.8 | 2024-04 | 后端与函数能力 | S3 后端全面支持 AWS SDK 标准配置链;Provider 自定义函数进入预览 |
| 1.10 | 2024-11 | 临时资源 | 引入 ephemeral 资源/值预览(临时凭证传递);支持 plan 模式 |
| 1.11 | 2025-02 | 后端身份认证 | S3 后端支持 OIDC 工作负载身份认证;write-only 属性进入预览 |
Terraform 非 ML 模型,无公开基准评测分数,其版本演进主要体现为工程能力沉淀——许可模式(MPL→BUSL)、测试框架转正、临时资源、OIDC 认证均面向企业级治理与安全场景。选型建议:新项目直接用当前稳定版(1.11.x);若团队要求 OSI 认证开源许可,评估同源分叉 OpenTofu 后再做迁移测试。
AI 应用场景
AI/ML 训练与推理集群的声明式交付
阶段:AI 基础设施编排、算力集群资源生命周期管理
解决的问题:GPU 训练集群涉及 VPC、EKS、GPU 节点组、安全组、共享存储等多类资源,手工创建耗时且每套环境配置漂移。Terraform 把整套拓扑写成模块,plan 可提前暴露节点组缩容等高风险变更,避免误删训练中实例。
具体案例:某 MLOps 团队用 Terraform 模块在同一账号 3 个区域部署 GPU 节点组(按需 + Spot 混合),单集群交付从人工控制台操作的数小时级缩短到一次 terraform apply 的 15 分钟;通过修改 tfvars 即可在 dev/staging 复制同构环境,训练任务异常时可快速重建算力资源。
多云统一编排与资源一致性
阶段:混合云资源编排、跨云环境一致性
解决的问题:不同云厂商控制台操作方式与 API 各不相同,脚本各自维护导致能力割裂。Terraform 用同一套 HCL 语义覆盖 AWS/Azure/GCP,Provider 差异被封装在模块内,上层只暴露统一参数。
具体案例:某合规要求数据本地化的团队,通过同一套网络与计算模块更换 Provider 参数,即可在另一朵云重建相同拓扑,实测网络、计算与存储模块复用率可达 60%–80%;配合远程后端,两个云的状态统一纳管,避免多云孤儿资源。
多环境复制与漂移告警
阶段:环境一致性编排、资源状态审计
解决的问题:dev/staging/prod 配置依赖手工同步,环境差异导致“在我机器上能跑”。Terraform 用同一模块 + 每环境 tfvars 保证三套环境同构,用定时 plan 检测漂移。
具体案例:某平台团队在 CI 中为每个 Merge Request 自动执行 plan 并评论 diff,生产变更须 review 后由流水线 apply;每天晚上定时运行 terraform plan -detailed-exitcode,退出码 2 即触发漂移告警,平均修复时间从手动排查询的 2 小时降至 20 分钟。
常见误区
误区“我把 Terraform 当 Ansible 用,apply 完再用 remote-exec 进去装 Nginx、改配置文件,一条龙搞定。”
正解Terraform 的职责是资源生命周期管理——创建、更新、销毁云资源,不负责对资源内部做软件安装与配置收敛。官方文档明确把 provisioner 列为“最后手段”(last resort)。正确组合是:用云厂商 user-data(如 EC2 User Data)完成首次初始化,或叠加 Ansible/Chef 等配置管理工具,或用 Packer 预构建镜像。Terraform 只保证“机器和网络建出来了”,不保证内部状态收敛。
为何常见:provisioner 文档真实存在且早期教程常用它做演示,“能跑通”被误认为“最佳实践”,混淆了基础设施编排与配置管理两个不同层级。
误区“状态文件就是资源清单,我直接提交到 Git 仓库,团队同步多方便。”
正解state 记录所有资源属性值——数据库口令、连接串、密钥对私钥、密码哈希等都会以明文形式出现在 tfstate 中。官方要求状态文件必须做访问控制,生产环境用远程后端(S3 加密 + 严格 IAM、HCP Terraform 等),并限制可写人员;提交 Git 等于把生产凭据放进代码仓库,属高危事故。Git 保管的应只是 .terraform.lock.hcl 锁文件。
为何常见:本地 demo 时 tfstate 看起来只有资源 ID 和 IP,容易忽略敏感属性;Git 又是团队最顺手的同步方式,习惯使然。
误区“CI 里我直接 terraform apply -auto-approve,省得每次手动确认,效率高。”
正解plan 的 diff 是 Terraform 的安全网,能提前暴露替换(destroy 后 create)和删除类高危变更——这两类对生产的影响远大于原地更新。生产流程要求在 PR/MR 中展示 plan 结果并人工审批,必要时用 -target 缩小变更范围。跳过 plan 审查等于放弃 IaC 的核心价值——可审查、可回滚、可追溯。
为何常见:本地学习时资源小、删了无所谓,auto-approve 缩短执行时间后形成惯性,迁移到生产也照旧。
误区“我在 required_providers 里写 latest,让 Terraform 每次自动拉最新 provider,省心。”
正解Terraform 官方推荐用 ~>(允许 minor 版本内升级)锁定 Provider 版本范围,并将生成的 .terraform.lock.hcl 提交到版本库,保证团队与 CI 使用完全一致的插件版本。Provider 升级可能引入破坏性变更,导致 plan 出现意外的资源替换;生产目录锁版本,升级先到 test 环境验证再提升。
为何常见:安装时默认拉取最新版本,“一直能用”掩盖了可复现性问题,且很少有人逐条读 Provider changelog。
误区“Terraform 开源免费,我把它集成进商业产品对外交付也没问题。”
正解自 v1.6.0 起,HashiCorp 将 Terraform 从 MPL-2.0 切换为 BUSL-1.1(Business Source License,商业源码许可)。BUSL 允许查看、修改、非商业使用源码,但将产品作为商业服务对外提供或构建竞争性产品有额外限制。需要 OSI 认证开源许可的团队可评估同源分叉 OpenTofu(MPL-2.0)。商用前务必逐条核对许可条款。
为何常见:大量旧教程停留在 MPL 时代,且 HashiCorp 宣传口径以 "source-available" 为主,社区讨论容易忽略许可变更的边界。
面试题
Q1. Terraform 的标准命令执行顺序是?
- A.plan → init → apply
- B.init → plan → apply← 正确答案
- C.apply → plan → init
- D.init → apply → plan
答案:B。init 负责初始化目录、下载 Provider 与配置后端,必须最先执行;plan 生成执行计划供 review;apply 才实际变更资源。顺序颠倒会导致缺少 Provider 或未审查直接变更。
Q2. Terraform 配置文件使用哪种声明语言?
- A.YAML 声明文件
- B.JSON 描述文件
- C.HCL(HashiCorp 配置语言)← 正确答案
- D.Python 脚本代码
答案:C。Terraform 原生使用 HCL,它比 YAML/JSON 更紧凑且支持注释、表达式与内置函数;JSON 是 HCL 的兼容子集但不是主用语言,Python 是 Pulumi 的写法。
Q3. terraform.tfstate 状态文件中可能包含的最敏感内容是什么?
- A.云账号的登录口令
- B.全部资源属性及敏感值← 正确答案
- C.命令执行的审计日志
- D.Provider 插件源码包
答案:B。state 记录资源的全部属性值,包括数据库密码、连接串、私钥等敏感信息。云账号口令不写入 state(凭证走 SDK 凭据链),审计日志与插件源码也不属于 state 内容。
Q4. 下列哪个命令既不会创建也不会删除真实资源,仅做变更预览?
- A.terraform apply -auto-approve
- B.terraform state rm 资源地址
- C.terraform plan -detailed-exitcode← 正确答案
- D.terraform destroy -auto-approve
答案:C。plan 只读取状态与云端现状生成 diff,不修改任何资源;apply/destroy 会真实变更或删除资源,state rm 只从状态文件移除记录而不动真实资源(有失控风险,需谨慎)。
Q5. 关于远程状态后端,以下哪些是推荐实践?
- A.使用 S3 并开启存储加密← 正确答案
- B.用 DynamoDB 实现状态锁← 正确答案
- C.将 tfstate 保存进 Git 仓库
- D.限制后端桶的 IAM 写权限← 正确答案
答案:ABD。S3 加密保护状态中敏感值,DynamoDB 锁防止并发 apply 覆盖,IAM 最小权限限制可写者。C 是典型反模式:tfstate 含明文敏感数据且并发下会损坏。
Q6. 以下哪些做法会导致生产环境风险?
- A.提交 lock 文件到版本库
- B.CI 跳过 plan 审查直接 apply← 正确答案
- C.多个 apply 同时操作同一状态← 正确答案
- D.用 -target 限制变更范围
答案:BC。跳过 plan 审查会把替换/删除类高危变更直接带上生产;同一状态并发 apply 无锁会损坏状态文件。提交 lock 文件保证版本一致、用 -target 缩小爆炸半径都是安全实践。
Q7. for_each 相对 count 的主要优势是什么?
- A.执行性能更高速度更快
- B.以 map/set 键为索引,删除中间元素不引发重建← 正确答案
- C.无需 Provider 也能完成遍历
- D.自动处理全部网络依赖
答案:B。count 依赖整数索引,删除列表中部元素会导致后续资源索引前移,触发不必要的替换;for_each 按 map/set 的键寻址,单个元素删除只影响自身,适合批量子网、实例等场景。
Q8. Terraform 官方对 provisioner(local-exec/remote-exec)的定位是什么?
- A.首选的配置管理方式
- B.最后手段,优先用 user-data 等方案← 正确答案
- C.完全禁用不允许使用
- D.仅限销毁阶段使用
答案:B。官方文档明确 provisioner 是 last resort。首选云厂商 user-data、预构建镜像(Packer)或叠加 Ansible 等配置管理工具;provisioner 无状态且失败不易重试,不能保证配置收敛。
Q9. 为保证团队协作时状态文件安全且一致,应该怎么做?
- A.采用 S3 远程后端存储← 正确答案
- B.允许全部成员写入状态桶
- C.后端启用 DynamoDB 锁定← 正确答案
- D.将状态文件提交到版本库
答案:AC。远程后端 + 锁是并发安全的基础;状态桶写权限必须收敛到少数服务账户,全员可写无法追责。提交版本库会让明文敏感值泄露且并发修改必损坏,属双重反模式。
Q10. 持续发现基础设施漂移(实际资源与配置不一致)最有效的方法是什么?
- A.人工登录控制台逐项比对
- B.定时执行 plan --detailed-exitcode 并按退出码告警← 正确答案
- C.手动编辑 tfstate 对齐当前现状
- D.删除重建全部资源来验证
答案:B。plan -detailed-exitcode 在退出码 2 时表示存在 diff,可接入定时任务或事件驱动流水线自动告警,实现对漂移的持续检测。人工比对效率低,手改 tfstate 会制造更严重的不一致,删除重建风险不可控。