2271 字
11 分钟
Terraform 简介

本文行文:Terraform 是什么 → 为什么需要它(手动点控制台的问题)→ 声明式与命令式的区别

Terraform 是什么#

Terraform 是 HashiCorp 开源的基础设施即代码(Infrastructure as Code,IaC)工具:把云上的 VPC、ECS、SLB、RDS、DNS、Kubernetes 资源写成配置文件,交给它去创建、修改和销毁。

它由三部分构成:

  • HCL 配置语言:HashiCorp Configuration Language,专为描述资源而生,可读性接近声明式配置而非编程语言;
  • Provider 插件生态:每个云厂商或平台对应一个 provider(alicloud、aws、azurerm、kubernetes、cloudflare……),Terraform 本体只是一个调度器,真正调 API 的是 provider;
  • State 状态文件:记录”代码里的资源地址”与”真实资源的 ID”之间的映射,下一次执行靠它算出差异。详见 Terraform 状态文件。

核心工作流只有三步:写配置(write)→ 看计划(plan)→ 执行(apply)。

main.tf
# 声明期望状态:要一个 VPC 和一个交换机
terraform {
required_providers {
alicloud = {
source = "aliyun/alicloud"
version = "~> 1.230"
}
}
}
provider "alicloud" {
region = "cn-hangzhou"
}
resource "alicloud_vpc" "this" {
vpc_name = "demo-vpc"
cidr_block = "10.0.0.0/16"
}
resource "alicloud_vswitch" "this" {
vpc_id = alicloud_vpc.this.id # 引用即依赖:交换机一定在 VPC 之后创建
cidr_block = "10.0.1.0/24"
zone_id = "cn-hangzhou-i"
}

这份文件里没有一个字提到”先创建 VPC 再创建交换机”,也没有提”如果已经存在就跳过”——这些都由 Terraform 自己推导。

为什么需要 Terraform#

不用 IaC 时,基础设施通常是在控制台点出来的,或者用一堆 aliyun / aws CLI 脚本拼出来。规模小的时候还好,一旦要交付第二套环境,问题就会集中爆发:

  • 不可复现:测试环境和生产环境”看起来一样”,但没人说得清差了哪几个参数;
  • 没有审计:谁在什么时候把安全组的 0.0.0.0/0 放开过,日志里查不到意图,只能看到结果;
  • 环境漂移:线上被临时改过几次,代码(如果有)和现实早就脱节,下一次部署直接踩雷;
  • 无法回滚:删错资源的补救方式是”凭记忆再点一遍”;
  • 文档会过期:手写的架构文档描述的是”当时的样子”,而配置文件描述的是”现在应该是什么样”,且能被机器校验。

IaC 的本质是把基础设施的变更过程变成可评审、可重复执行的代码:

能力手动控制台自写 CLI 脚本Terraform 这类 IaC 工具
可复现靠人记部分可完全可,同一份代码处处可建
变更可评审无靠代码评审plan 输出即变更单
幂等天然不幂等要自己判断存在性由工具保证
依赖顺序靠人靠人(sleep、串行)依赖图自动排序
现状感知只看得到资源列表不知道靠 state 精确追踪
并发保护无无远程后端 + 状态锁

需要强调的是,IaC 不只 Terraform 一种:AWS CloudFormation / CDK、Pulumi、Kubernetes 的 YAML + Helm,甚至 Ansible playbook 都算。Terraform 的差异点在于:多云通用 + 声明式 + 有状态——一套写法覆盖阿里云、AWS、K8s 和 SaaS API,并且能算出”从现状到期望”的最小变更。

声明式与命令式#

这两种思路的区别,不在于用什么语言,而在于你描述的是什么。

  • 命令式(imperative):描述”怎么做”——一步步的指令序列,执行结果取决于起点;
  • 声明式(declarative):描述”要什么”——最终状态,执行结果与起点无关,工具负责算出路径。

同样要创建一个 VPC 和一个交换机,命令式脚本大致长这样:

Terminal window
# 命令式:自己拼每一步,自己保证顺序
set -euo pipefail
VPC_ID=$(aliyun vpc CreateVpc --RegionId cn-hangzhou \
--CidrBlock 10.0.0.0/16 --VpcName demo-vpc | jq -r '.VpcId')
VSWITCH_ID=$(aliyun vpc CreateVSwitch --RegionId cn-hangzhou \
--VpcId "$VPC_ID" --CidrBlock 10.0.1.0/24 \
--ZoneId cn-hangzhou-i --VSwitchName demo-vswitch | jq -r '.VSwitchId')
echo "vpc=$VPC_ID vswitch=$VSWITCH_ID"

这段脚本能跑通一次,但再跑一次就会建出第二套 VPC 和交换机——因为它是”执行步骤”,不包含”是否已经达成”的判断。真要写幂等,就得自己查存在性、处理部分失败的中间态、按逆序回滚,脚本很快就会膨胀成一个难以维护的小框架。

声明式则把判断交给工具:

# 同样的目标,只写终态,重复 apply 不会重复创建
resource "alicloud_vpc" "this" {
vpc_name = "demo-vpc"
cidr_block = "10.0.0.0/16"
}
resource "alicloud_vswitch" "this" {
vpc_id = alicloud_vpc.this.id
cidr_block = "10.0.1.0/24"
zone_id = "cn-hangzhou-i"
}

两者对比:

维度命令式(脚本 / CLI)声明式(Terraform)
你写的内容执行步骤期望终态
重复执行通常重复创建已达成则不做事(幂等)
依赖顺序自己安排由引用与依赖图推导
变更预览无,跑起来才知道plan 先算出增删改
部分失败自己写回滚修好配置再跑一次即可收敛
已存在的资源无法感知state 里的资源不再重复创建
排错方式翻日志看 plan 差异与 state

声明式之所以能幂等,关键在于”状态”:Terraform 每次执行都做三方对比——配置文件(期望)、state(上次执行后的记录)、真实 API(现状)。计划 = 期望与 state 的差异 + 刷新回来的现实漂移。没有 state 的声明式工具(比如有的平台只做”提交即创建”)是无法算出”该删什么”的,这也是 state 必须妥善保管的原因。

一次最小的执行流程#

以 main.tf 为例,四个命令构成一个闭环:

Terminal window
terraform init # 下载 provider、初始化后端与锁文件
terraform fmt # 统一格式(可以放进 CI 检查)
terraform validate # 语法与引用检查,不发 API 请求
terraform plan # 只计算差异,不执行
terraform apply # 确认后执行

plan 的输出就是”变更单”,也是评审时真正要看的对象:

terraform plan(节选)
Terraform will perform the following actions:
# alicloud_vpc.this will be created
+ resource "alicloud_vpc" "this" {
+ cidr_block = "10.0.0.0/16"
+ id = (known after apply)
+ vpc_name = "demo-vpc"
}
# alicloud_vswitch.this will be created
+ resource "alicloud_vswitch" "this" {
+ cidr_block = "10.0.1.0/24"
+ vpc_id = (known after apply)
}
Plan: 2 to add, 0 to change, 0 to destroy.

两个细节值得注意:

  • + 表示新增,~ 表示原地修改,-/+ 表示销毁重建(重建是有风险的,要看清是哪个属性导致的);
  • (known after apply) 说明这个值要创建完才知道(比如 id),因为配置文件里并没有、也不该有真实 ID——ID 属于 state,不属于代码。

资源不再需要时,用 terraform destroy 按依赖逆序销毁;只想删其中一部分,就从配置里移除再 plan,确认 - 的条目符合预期后再 apply。

适用与不适用的场景#

小结#

Terraform 用 HCL 描述终态、用 state 记住现状、用 plan 呈现差异,把基础设施变更变成可评审、可重复执行的代码。理解”声明式描述结果而非过程”这一点,比记住任何命令都重要——所有幂等性、依赖推导、变更预览的能力,都是从这句话里长出来的。

Terraform 简介
https://blog-l7wd3.pages.dev/posts/iac/terraform/
作者
L7WD3-Xiao
发布于
2026-10-26
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取