Skip to main content

terraform

📅 2026-04-08 ✏️ 2026-04-08 CS INFRA
No related notes

1 · terraform#

S - 什么场景:要创建和维护云基础设施,例如 VPC、子网、安全组、ECS/EC2、RDS、Kubernetes 集群、DNS 记录

C - 什么冲突:手工点控制台效率低、不可审计、难以复现;Shell 脚本虽然能自动化,但资源依赖关系、变更对比、状态追踪都很难管

Q - 什么问题:如何用一种可版本化、可复现、可审查的方式去管理基础设施?

A - 回答问题Terraform — 最主流的 IaC(Infrastructure as Code)工具之一。你用声明式配置描述“想要什么基础设施”,Terraform 负责计算差异并调用云厂商 API 把现实状态收敛到期望状态

1.1 · 0. 为什么需要 Terraform#

S: 一开始资源少,直接在云控制台点一点击就能用 C: 环境一多(dev/staging/prod)、资源一多(网络/机器/数据库/权限),手工操作就会出现遗漏、漂移、无法复现 Q: 怎么把“搭基础设施”这件事工程化? A: 把基础设施写成代码,纳入 Git、Code Review、CI/CD,这就是 IaC;Terraform 是最典型的实现

Terraform 带来的核心价值:

  • 可复现:同一份配置可以反复创建相同环境
  • 可审查:变更先看 plan,再决定要不要执行
  • 可追踪:基础设施变更进入 Git 历史
  • 可组合:把常见基础设施封装成 module 重复复用

1.2 · 1. 核心范式:声明式 IaC#

S: 你想创建一套云资源 C: 命令式脚本要自己安排顺序、处理幂等、判断资源是否已存在,脚本很快变脆 Q: 能不能只描述“目标”,不手写“每一步怎么做”? A: 声明式 — 你描述期望状态,Terraform 计算当前状态与目标状态的差异,然后执行变更

你写 .tf 配置(期望状态)

terraform 读取 state(当前已知状态)

对比真实资源与配置

生成执行计划(plan)

调用 provider API 执行

更新 state

这和 Kubernetes 的“声明式 + 控制循环”有相似之处,但 Terraform 更偏:

  • 一次性执行式收敛:你运行一次 apply,它做完退出
  • 不是常驻控制器:不会持续 watch 并自动修复漂移

1.3 · 2. 核心对象#

1.4 · Provider — 连接具体平台#

Terraform 本身不懂阿里云、AWS、GCP、Kubernetes,它通过 Provider 插件 和外部系统交互。

例如:

  • hashicorp/aws:管理 AWS 资源
  • aliyun/alicloud:管理阿里云资源
  • hashicorp/kubernetes:管理 Kubernetes 资源
  • hashicorp/helm:管理 Helm Release

你可以把 Provider 理解成“某个平台的 API 适配器”。

1.5 · Resource — Terraform 管理的资源#

Terraform 最核心的对象就是 resource

resource "aws_instance" "web" {
  ami           = "ami-123456"
  instance_type = "t3.micro"
}

含义:

  • aws_instance:资源类型
  • web:本地名字
  • 块里的字段:这个资源的期望属性

Terraform 会把每个 resource 看成状态图中的一个节点,并根据引用关系推导依赖顺序。

1.6 · Data Source — 读,不创建#

有些信息不是你创建的,而是“查出来再复用”,这时用 data

data "aws_vpc" "default" {
  default = true
}

区别:

  • resource:创建或管理对象
  • data:查询已有对象

1.7 · Variable / Output — 输入与输出#

  • variable:给配置传参
  • output:把关键结果导出给人看,或给其他模块使用
variable "region" {
  type    = string
  default = "us-east-1"
}

output "instance_ip" {
  value = aws_instance.web.public_ip
}

1.8 · Module — 可复用配置单元#

当一组资源经常一起出现,例如“VPC + 子网 + 路由表 + NAT”,就应该抽成 module

你可以把 module 理解成“基础设施函数”:

  • 输入:variables
  • 内部:多个 resources
  • 输出:outputs

Terraform 的工程化能力,很大程度上就建立在 module 复用上。

1.9 · 3. 工作流:init → plan → apply → destroy#

这是 Terraform 入门必须记住的主线。

1.10 · terraform init#

初始化当前工作目录:

  • 下载 provider 插件
  • 初始化 backend
  • 准备 module 依赖

第一次进入一个 Terraform 项目,通常先跑它。

1.11 · terraform plan#

根据配置 + state 生成执行计划,但不真正修改资源

它会告诉你:

  • 哪些资源会被创建(+
  • 哪些会被修改(~
  • 哪些会被销毁(-

这是 Terraform 最重要的安全机制之一:先看 diff,再决定 apply

1.12 · terraform apply#

真正执行变更,把基础设施推进到目标状态。

通常流程是:

terraform plan
terraform apply

也可以直接 terraform apply,它会先展示计划再询问确认。

1.13 · terraform destroy#

销毁当前配置管理的所有资源。适合临时环境,但生产环境必须慎用。

1.14 · 4. State:Terraform 为什么需要状态文件?#

S: Terraform 不是已经有 .tf 配置了吗? C: 配置只描述“我想要什么”,但不知道“现在已经有什么”、资源 ID 是多少、哪些对象归我管理 Q: Terraform 靠什么追踪资源? A: state 文件,默认是 terraform.tfstate

state 的作用:

  • 记录 Terraform 管理过的资源及其属性
  • 记录资源真实 ID(例如实例 ID、VPC ID)
  • 作为 plan 的比较基准
  • 帮助 Terraform 建立依赖图和变更路径

如果没有 state,Terraform 很难判断:

  • 一个资源是“已经存在,应修改”
  • 还是“根本不存在,应新建”

1.14.1 · 本地 state 与远端 state#

入门时常见是本地 terraform.tfstate,但团队协作通常要放到远端 backend,例如:

  • S3 + DynamoDB Lock
  • 阿里云 OSS
  • Terraform Cloud

远端 state 的价值:

  • 团队共享
  • 避免多人各自持有不同状态
  • 提供锁,防止并发 apply

1.15 · 5. 一个最小例子#

下面是一个极简的 Terraform 配置骨架:

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
  }
}

provider "aws" {
  region = "us-east-1"
}

resource "aws_instance" "web" {
  ami           = "ami-123456"
  instance_type = "t3.micro"

  tags = {
    Name = "demo-web"
  }
}

output "public_ip" {
  value = aws_instance.web.public_ip
}

执行流程:

terraform init
terraform plan
terraform apply

背后的含义是:

  1. 安装 AWS Provider
  2. 读取当前 state
  3. 发现 aws_instance.web 不存在
  4. 调用 AWS API 创建实例
  5. 把实例 ID 和属性写入 state
  6. 输出实例公网 IP

1.16 · 6. HCL:Terraform 的配置语言#

Terraform 使用 HCL(HashiCorp Configuration Language),特点是:

  • 比 JSON 更适合人写
  • 结构清晰,适合表达层级配置
  • 支持引用、表达式、条件、循环

常见写法:

name = "web"
count = 2
instance_type = var.instance_type
subnet_id = aws_subnet.app.id

几个入门期最常见的引用规则:

  • var.xxx:引用变量
  • aws_instance.web.id:引用资源属性
  • module.vpc.vpc_id:引用模块输出

1.17 · 7. Terraform 的依赖关系是怎么推出来的?#

Terraform 默认根据引用关系自动推导依赖。

例如:

resource "aws_subnet" "app" {
  vpc_id = aws_vpc.main.id
}

因为 aws_subnet.app 引用了 aws_vpc.main.id,所以 Terraform 知道:

  • 先创建 aws_vpc.main
  • 再创建 aws_subnet.app

必要时也可以显式写 depends_on,但入门阶段记住一句话就够:

能靠引用表达依赖,就不要手写 depends_on。

1.18 · 8. 适合 Terraform 做什么,不适合做什么?#

1.19 · 适合

  • 云资源编排:VPC、ECS/EC2、LB、RDS、DNS、IAM
  • Kubernetes 基础对象管理
  • 多环境基础设施模板化
  • 把基础设施纳入 GitOps / CI/CD

1.20 · 不太适合

  • 细粒度服务器内配置(更偏 Ansible)
  • 高频变更、秒级控制循环(更偏 Kubernetes Controller)
  • 复杂业务发布编排

一个常见分工是:

  • Terraform:创建机器、网络、托管服务、集群
  • Ansible / 脚本:进入机器做配置
  • Kubernetes / Helm:部署容器应用

1.21 · 9. 常用命令#

terraform fmt        # 格式化 .tf 文件
terraform validate   # 校验配置语法和结构
terraform init       # 初始化工作目录
terraform plan       # 查看执行计划
terraform apply      # 执行变更
terraform destroy    # 销毁资源
terraform show       # 查看 state 或 plan 内容
terraform output     # 查看输出值
terraform state list # 列出 state 中的资源

1.22 · 10. 入门阶段最容易踩的坑#

  1. 没理解 state:删了 state 不等于删了云资源,反而会让 Terraform“失忆”
  2. 直接 apply 不看 plan:容易误删或误改资源
  3. 把敏感信息写进代码或 state:密码、密钥要谨慎处理
  4. 滥用 depends_on:很多依赖本来可以通过引用自然表达
  5. 一个目录塞太多环境:dev/prod 通常要拆开管理

1.23 · 11. 一句话总结#

Terraform 的本质不是“写几个 .tf 文件去调云 API”,而是:

用声明式配置 + 状态管理 + 差异计算,把基础设施变更变成一件可复现、可审查、可协作的工程活动。

https://developer.hashicorp.com/terraform/docs

2 · links#

  1. https://developer.hashicorp.com/terraform/docs
  2. https://developer.hashicorp.com/terraform/language
  3. https://developer.hashicorp.com/terraform/intro