Terraform 架构深度解析

Terraform 不是魔法。它看起来只需要写几行配置,就能神奇地创建出复杂的云基础设施。但在这「简单」的背后,有一套精心设计的架构在运转。

理解 Terraform 的架构,不仅能帮助你更好地使用它,还能在遇到问题时快速定位原因。

整体架构

Terraform 的架构可以分为五个核心组件:

flowchart TD
    subgraph Core["Terraform Core"]
        A[配置文件] --> B[Terraform Core]
        C[状态文件] --> B
        D[Provider Plugin] --> B
        E[Backend Plugin] --> B
        B --> F[执行引擎]
        B --> G[状态管理]
        B --> H[资源图]
    end

    subgraph Providers["Providers"]
        I[AWS Provider]
        J[GCP Provider]
        K[Azure Provider]
    end

    subgraph State["状态存储"]
        L[Local]
        M[S3 + DynamoDB]
        N[Terraform Cloud]
    end

    D --> I
    D --> J
    D --> K

    E --> L
    E --> M
    E --> N

核心组件

组件职责说明
Configuration Parser解析 HCL/JSON 配置将配置文件转换为内部结构
State Manager管理基础设施状态追踪实际资源
Resource Graph构建资源依赖图分析资源间的依赖关系
Plan Builder生成执行计划计算当前状态与期望状态的差异
Executor执行变更调用 Provider API 创建/更新/销毁资源

工作流程

标准工作流程

sequenceDiagram
    participant User as 用户
    participant CLI as Terraform CLI
    participant Core as Terraform Core
    participant Provider as Provider Plugin
    participant Cloud as 云平台

    User->>CLI: terraform init
    CLI->>Core: 初始化 Provider、后端
    Core->>Provider: 下载并初始化 Provider
    Core->>Core: 解析模块

    User->>CLI: terraform plan
    CLI->>Core: 执行 plan
    Core->>Core: 读取状态
    Core->>Core: 构建资源图
    Core->>Core: 计算差异
    Core->>Provider: 读取远程状态
    Provider->>Cloud: API 调用
    Cloud-->>Provider: 资源信息
    Provider-->>Core: 状态差异
    Core-->>CLI: 生成计划
    CLI-->>User: 显示计划

    User->>CLI: terraform apply
    CLI->>Core: 执行 apply
    loop 对每个资源
        Core->>Provider: 创建/更新资源
        Provider->>Cloud: API 调用
        Cloud-->>Provider: 响应
        Provider-->>Core: 资源信息
        Core->>Core: 更新状态
    end
    Core-->>CLI: 完成
    CLI-->>User: 变更摘要

初始化阶段(terraform init)

$ terraform init

Initializing the backend...
Initializing provider plugins...
- Finding hashicorp/aws versions matching "~> 5.0"...
- Installing hashicorp/aws v5.31.0...
Terraform has been successfully initialized!

做了什么:

  1. 初始化 backend(本地或远程)
  2. 下载 required_providers 声明的 Provider
  3. 安装模块(如果使用了 module)
  4. 检查 backend 配置

规划阶段(terraform plan)

$ terraform plan

Terraform will perform the following actions:

  # aws_instance.web will be created
  + resource "aws_instance" "web" {
      + ami                          = "ami-12345678"
      + arn                          = (known after apply)
      + instance_type                = "t3.medium"
      + private_ip                   = (known after apply)
      + public_ip                    = (known after apply)
      + tags                         = {
          + "Environment" = "prod"
          + "Name"        = "web-server"
        }
    }

Plan: 1 to add, 0 to change, 0 to destroy.

做了什么:

  1. 读取当前配置文件
  2. 读取当前状态文件
  3. 构建资源依赖图
  4. 调用 Provider 获取远程资源状态
  5. 计算差异(哪些需要创建/更新/销毁)
  6. 生成执行计划

应用阶段(terraform apply)

$ terraform apply

Terraform will perform the following actions:

  # aws_instance.web will be created
  + resource "aws_instance" "web" {
      ...
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions exactly as planned.
  Type 'yes' to execute the Terraform plan.

Enter a value: yes

aws_instance.web: Creating...
aws_instance.web: Still creating... [10s elapsed]
aws_instance.web: Creation complete after 15s [id=i-1234567890abcdef0]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

做了什么:

  1. 确认用户同意(或使用 -auto-approve
  2. 按照依赖顺序执行资源操作
  3. 更新状态文件
  4. 显示变更摘要

状态管理

状态的作用

flowchart LR
    A[配置文件] --> B[期望状态]
    C[实际状态] --> D[差异计算]
    B --> D
    D --> E[执行计划]
    F[状态文件] --> C
    C --> F

状态文件是 Terraform 的「记忆」——它记录了上次执行后,云平台上实际存在哪些资源。

Backend 类型

本地后端(默认)
terraform {
  backend "local" {
    path = "terraform.tfstate"
  }
}
S3
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/web/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-locks"
  }
}
S3 后端的好处
  • 状态共享:团队成员可以访问同一份状态
  • 状态锁定:DynamoDB 表防止并发修改
  • 版本控制:S3 自带版本控制,可回滚
  • 加密:状态文件可以加密存储 :::

状态锁定

$ terraform apply

Error: Error acquiring the state lock
Acquiring state lock. This may take a moment...

│ Error: InvalidLockToken: Lock token provided is invalid or expired

│ Terraform acquires a state lock to protect the state from another
│ writer modifying the state at the same time.

状态锁定防止多人同时修改状态导致的不一致。

Provider 架构

Provider 工作原理

flowchart TD
    subgraph Core["Terraform Core"]
        A[Resource Graph]
    end

    subgraph Provider["AWS Provider"]
        B[AWS SDK]
        C[Resource Mapper]
        D[API Wrapper]
    end

    subgraph AWS["AWS API"]
        E[EC2 API]
        F[S3 API]
        G[RDS API]
    end

    A --> B
    B --> C
    C --> D
    D --> E
    D --> F
    D --> G

Provider 生命周期

sequenceDiagram
    participant Core as Terraform Core
    participant Provider as Provider Plugin

    Core->>Provider: Configure(credentials)
    Provider->>Provider: 初始化 AWS SDK
    Provider-->>Core: 配置完成

    loop 每个资源
        Core->>Provider: PlanResourceChange(request)
        Provider-->>Core: planned state

        Core->>Provider: ApplyResourceChange(request)
        Provider->>AWS: API 调用
        AWS-->>Provider: 响应
        Provider-->>Core: actual state
    end

    Core->>Provider: Close()

常用 Provider

Provider描述GitHub Stars
AWSAmazon Web Services10k+
AzureMicrosoft Azure3k+
GoogleGoogle Cloud Platform3k+
KubernetesKubernetes 集群2k+
HelmHelm Charts1k+
VaultHashiCorp Vault500+

资源图

Terraform 使用有向无环图(DAG)来表示资源间的依赖关系。

图的构建

资源依赖
resource "aws_vpc" "main" {
  cidr_block = "10.0.0.0/16"
}

resource "aws_subnet" "public" {
  vpc_id     = aws_vpc.main.id  # 依赖 VPC
  cidr_block = "10.0.1.0/24"
}

resource "aws_instance" "web" {
  subnet_id      = aws_subnet.public.id  # 依赖子网
  instance_type = "t3.medium"
}

对应的依赖图:

flowchart TD
    A[aws_vpc.main] --> B[aws_subnet.public]
    B --> C[aws_instance.web]

并行执行

flowchart TD
    subgraph 顺序执行
        A[VPC] --> B[Subnet 1]
        A --> C[Subnet 2]
        A --> D[Subnet 3]
        B --> E[Instance 1]
        C --> F[Instance 2]
        D --> G[Instance 3]
    end

没有依赖关系的资源可以并行创建,提高效率。

没有依赖的资源
resource "aws_s3_bucket" "bucket1" {}
resource "aws_s3_bucket" "bucket2" {}
resource "aws_s3_bucket" "bucket3" {}

# 这三个 bucket 可以并行创建

变更执行顺序

Terraform 按照以下规则决定执行顺序:

规则一:显式依赖优先

resource "aws_instance" "db" {
  instance_type = "r6g.large"
}

resource "aws_instance" "web" {
  # 明确依赖 db
  depends_on = [aws_instance.db]
}

规则二:隐式依赖通过引用自动发现

resource "aws_instance" "web" {
  subnet_id = aws_subnet.main.id  # 隐式依赖
}

规则三:特定资源的隐式依赖

某些资源类型有隐式的创建顺序:

  • 安全组需要先于 EC2 创建(需要安全组 ID)
  • IAM 角色需要先于 EC2 创建(需要实例配置文件)

规则四:depends_on 显式声明

resource "aws_db_instance" "main" {
  allocated_storage = 100
}

resource "aws_instance" "app" {
  depends_on = [aws_db_instance.main]  # 必须显式声明
}

深入理解 Plan

Plan 的类型

类型说明触发条件
Normal Plan创建/更新/销毁资源的计划terraform plan
Refresh-only Plan只更新状态,不修改资源terraform plan -refresh-only
Destroy Plan销毁所有资源terraform plan -destroy

Plan 文件

# 保存计划到文件
terraform plan -out=tfplan

# 使用计划文件
terraform apply tfplan
Plan
type Plan struct {
    Version   uint64
    Backend   BackendState
    Variables map[string]DynamicValue

    Changes *ChangesStruct
    PriorState *State
    ConfigStates *State
}

type ChangesStruct struct {
    Resources []*ResourceInstanceChange
}

计划的局限性

:::warning Plan 可能不准确

  • Provider 可能返回意外的资源差异
  • 外部系统的变更不会被 Terraform 检测到
  • 某些 API 调用可能在 apply 时才返回最终状态

这就是为什么即使 plan 通过了,apply 时也可能出错。

总结

Terraform 的架构设计使其能够:

  1. 声明式管理:你描述结果,Terraform 负责实现
  2. 状态驱动:通过状态文件追踪实际基础设施
  3. 依赖图优化:自动解析依赖,支持并行执行
  4. 可插拔架构:Provider 插件机制支持任意平台

理解这些核心概念,能帮助你:

  • 更好地组织代码结构
  • 排查执行过程中的问题
  • 优化大规模 Terraform 的性能
下一步

想学习 Terraform 的语法?请阅读 Terraform 核心语法