2. Terraform核心机制精讲

Terraform 的执行模型可以概括为一条“声明式闭环”:用户用 HCL 描述期望状态,Provider 把 HCL 翻译成各云厂商的 API 调用,State 记录真实资源的身份映射,Plan 计算期望与现状的差异,Apply 执行差异,Destroy 反向回收。理解这条闭环,比记住任何单个命令都重要,因为多云迁移中的绝大多数问题,都出在“某一环的假设在另一朵云上不成立”。

Provider:能力边界与认证入口

Provider 是 Terraform 与云 API 之间的适配层。它负责三件事:声明资源类型与参数 schema、把 HCL 值转换为 API 请求、把 API 返回结果写回 State。以 AWS 为例,一个最小可用配置如下:

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

provider "aws" {
  region = "ap-southeast-1"
}

provider "aws" {
  alias  = "tokyo"
  region = "ap-northeast-1"
}

这里的关键点是 alias。多云或同云多区域场景中,资源必须显式绑定到某个 Provider 实例,例如 provider = aws.tokyo。如果省略,资源会落到默认 Provider 上,迁移时极易出现“资源建在了错误区域”的问题。认证方面,AWS 走环境变量或 IAM Role,Azure 走 Service Principal 或 Managed Identity,GCP 走 Service Account JSON。差异在于:AWS 的凭证可以按 region 隔离,Azure 的 subscription 与 tenant 是两级作用域,GCP 的 project 与 region 需要同时指定。迁移前应先确认目标云的认证链是否能在 CI 中无交互完成。

Resource:声明式描述与隐式依赖

Resource 是 Terraform 管理的最小单元。它不描述“怎么做”,只描述“最终要有什么”。例如:

resource "aws_instance" "web" {
  ami           = "ami-0abcd1234"
  instance_type = "t3.micro"
  subnet_id     = aws_subnet.public.id
  tags = {
    Name = "web-01"
  }
}

注意 subnet_id = aws_subnet.public.id 这一行:它既是参数引用,也是隐式依赖。Terraform 会据此构建依赖图,先创建 subnet,再创建 instance。多云迁移时,这种隐式依赖往往需要重写,因为不同云的资源粒度不同。例如 AWS 的 Security Group 是独立资源,而 GCP 的防火墙规则绑定在 VPC 上;Azure 的 NSG 既可以关联子网也可以关联网卡。迁移时不能只替换资源类型名,还要重新梳理依赖方向。

State:真实资源的身份账本

State 是 Terraform 最容易被低估的组件。它记录的是“HCL 地址 → 真实资源 ID”的映射,而不是资源本身。默认本地 terraform.tfstate 只适合单人实验;团队和多云场景必须使用远程后端,例如 S3 + DynamoDB 锁、Azure Storage Account、GCS Bucket。远程后端解决三件事:状态共享、并发锁、版本历史。

多云迁移中,State 的常见操作是 terraform state mv 和 terraform import。前者用于重命名或移动资源地址,后者用于把已存在的云资源纳入管理。例如把旧模块中的实例迁移到新模块:

terraform state mv \
  module.old.aws_instance.web \
  module.new.aws_instance.web

执行后必须运行 terraform plan 确认没有意外重建。如果 plan 显示 forces replacement,说明资源地址变了但真实 ID 没变,Terraform 会认为需要销毁重建,此时应回退并检查地址是否写错。

Plan 与 Apply:差异计算与执行

terraform plan 做的是三路比较:HCL 期望值、State 记录值、真实 API 返回值。输出中的符号含义固定:+ 创建,- 销毁,~ 原地更新,-/+ 销毁后重建。多云迁移时,最需要警惕的是 -/+,因为重建意味着 IP、磁盘、负载均衡后端等可能变化。

terraform apply 按依赖图并行执行,默认并发度为 10。执行过程中,State 会在每个资源成功后增量写入。如果中途失败,已成功的资源会保留在 State 中,下次 plan 只处理剩余差异。这一点与“一次性事务”不同,迁移时应接受“部分成功”并逐步收敛。

Destroy:反向回收与保护机制

terraform destroy 按依赖图反向执行,先删依赖者,再删被依赖者。生产环境应配合 prevent_destroy = true 和 lifecycle 块使用:

resource "aws_db_instance" "main" {
  # ...
  lifecycle {
    prevent_destroy = true
  }
}

多云差异在于:AWS 的删除通常是异步的,需要等待状态变为 terminated;Azure 的资源组删除会级联删除内部资源;GCP 的某些资源有软删除窗口。迁移后如果直接 destroy,可能因为异步未完成而报错,建议在 CI 中增加重试或等待逻辑。

Terraform 声明式闭环与多云差异点 HCL 配置 期望状态声明 Provider 认证 / API 适配 云厂商 API AWS / Azure / GCP State 地址 → 真实 ID terraform plan HCL 期望值 vs State 记录值 vs 真实 API 返回值 terraform apply 按依赖图并行执行,State 增量写入 terraform destroy 反向依赖回收,prevent_destroy 保护 多云关键差异 • Provider alias 绑定区域 • 资源粒度不同(SG/NSG/FW) • State 后端需远程共享 • 删除异步性差异 • 认证链 CI 无交互要求 • 隐式依赖需重新梳理 迁移检查点 1. plan 无 -/+ 重建 2. state mv 后地址一致 3. import 后 plan 为空 4. 远程后端锁生效 5. destroy 前备份 State 6. 异步删除加重试

多云场景下的关键差异与迁移检查

把上述机制放到多云迁移中,差异集中在五个方面。第一,Provider 的 region 与 project 作用域不同,AWS 用 region,Azure 用 subscription + resource group,GCP 用 project + region,迁移时必须逐层对齐。第二,资源粒度不同,安全组、路由表、子网的绑定关系需要重新设计。第三,State 后端必须远程化,且要确认目标云的对象存储支持锁机制。第四,删除语义不同,AWS 异步、Azure 级联、GCP 软删除,destroy 后要验证资源确实消失。第五,认证链要能在 CI 中无交互完成,否则 plan 和 apply 都会卡住。

迁移前建议先做一次“空跑”:在目标云用最小配置创建 1 个 VPC、1 个子网、1 个实例,执行 plan → apply → destroy 全流程,确认 Provider 认证、State 后端、删除语义都符合预期,再迁移真实资源。
不要直接对生产 State 执行 terraform state mv 或 import 而不备份。建议先 terraform state pull > backup.tfstate,确认 plan 无意外重建后再继续。

最后给出一个可直接使用的迁移检查表,字段按“检查项 / 命令或操作 / 通过标准”组织:

检查项命令或操作通过标准
Provider 认证terraform plan无认证错误,能读取目标云 API
State 后端terraform init远程后端连接成功,锁可用
资源地址迁移terraform state mvplan 无 -/+ 重建
存量资源纳管terraform importimport 后 plan 为空或仅标签差异
删除保护lifecycle.prevent_destroydestroy 被阻止,需手动解除
异步删除destroy 后查 API资源状态为 deleted/terminated