- 状态共享:团队成员可以访问同一份状态
- 状态锁定: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
资源图
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 的类型
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 时也可能出错。