Terraform 状态基础 #

什么是状态? #

Terraform 状态是 Terraform 跟踪管理资源的方式。状态文件记录了 Terraform 管理的所有资源及其属性,是 Terraform 实现声明式配置的关键。

text
┌─────────────────────────────────────────────────────────────┐
│                    状态的作用                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │ 资源映射     │     │ 状态跟踪     │     │ 依赖关系    │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                             │
│  - 配置与真实资源的映射                                    │
│  - 记录资源当前状态                                        │
│  - 存储资源依赖关系                                        │
│  - 提高性能(缓存)                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

状态文件 #

默认状态文件 #

Terraform 默认在当前目录创建 terraform.tfstate 文件:

text
project/
├── main.tf
├── terraform.tfstate     状态文件
├── terraform.tfstate.backup  备份文件
└── .terraform/

状态文件结构 #

json
{
  "version": 4,
  "terraform_version": "1.6.6",
  "serial": 1,
  "lineage": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
  "outputs": {
    "instance_ip": {
      "value": "54.123.45.67",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_instance",
      "name": "example",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "id": "i-1234567890abcdef0",
            "ami": "ami-0c55b159cbfafe1f0",
            "instance_type": "t2.micro",
            "public_ip": "54.123.45.67",
            "tags": {
              "Name": "example-instance"
            }
          }
        }
      ]
    }
  ],
  "check_results": null
}

状态文件字段说明 #

text
┌─────────────────────────────────────────────────────────────┐
│                    状态文件字段                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  version           状态文件格式版本                         │
│  terraform_version 创建状态的 Terraform 版本                │
│  serial            状态序列号(每次更新递增)                │
│  lineage           状态唯一标识符                           │
│  outputs           输出值                                   │
│  resources         资源列表                                 │
│  check_results     检查结果                                 │
│                                                             │
└─────────────────────────────────────────────────────────────┘

状态的作用 #

1. 资源映射 #

text
┌─────────────────────────────────────────────────────────────┐
│                    资源映射                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  配置文件                    状态文件                       │
│  ┌─────────────────┐        ┌─────────────────┐            │
│  │ aws_instance    │   ->   │ i-1234567890    │            │
│  │   "example"     │        │                 │            │
│  └─────────────────┘        └─────────────────┘            │
│                                                             │
│  Terraform 通过状态文件知道:                               │
│  - 哪些资源已被创建                                        │
│  - 资源的真实 ID                                           │
│  - 资源的当前属性                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. 状态跟踪 #

hcl
resource "aws_instance" "example" {
  ami           = "ami-0c55b159cbfafe1f0"
  instance_type = "t2.micro"
}
text
┌─────────────────────────────────────────────────────────────┐
│                    状态跟踪                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  terraform plan 时:                                        │
│  1. 读取状态文件                                           │
│  2. 刷新状态(获取真实资源状态)                            │
│  3. 对比配置与状态                                         │
│  4. 生成执行计划                                           │
│                                                             │
│  terraform apply 时:                                       │
│  1. 执行变更                                               │
│  2. 更新状态文件                                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3. 依赖关系 #

状态文件存储资源间的依赖关系,确保正确的创建和销毁顺序。

text
┌─────────────────────────────────────────────────────────────┐
│                    依赖关系                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  创建顺序:                                                 │
│  VPC → Subnet → Security Group → Instance                  │
│                                                             │
│  销毁顺序(反向):                                         │
│  Instance → Security Group → Subnet → VPC                  │
│                                                             │
│  状态文件记录这些依赖关系                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

4. 元数据存储 #

状态文件存储资源的元数据:

json
{
  "dependencies": [
    "aws_subnet.public",
    "aws_security_group.web"
  ],
  "deposed_key": ""
}

状态管理挑战 #

1. 团队协作 #

text
┌─────────────────────────────────────────────────────────────┐
│                    团队协作问题                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  本地状态文件:                                             │
│  ❌ 无法共享                                               │
│  ❌ 无法协作                                               │
│  ❌ 容易冲突                                               │
│  ❌ 容易丢失                                               │
│                                                             │
│  解决方案:远程状态                                         │
│  ✅ 集中存储                                               │
│  ✅ 状态锁定                                               │
│  ✅ 版本控制                                               │
│  ✅ 团队共享                                               │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2. 敏感信息 #

json
{
  "attributes": {
    "password": "my-secret-password",
    "api_key": "secret-api-key"
  }
}

状态文件可能包含敏感信息:

text
┌─────────────────────────────────────────────────────────────┐
│                    敏感信息处理                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ⚠️ 状态文件中的敏感信息是明文                              │
│                                                             │
│  解决方案:                                                 │
│  1. 加密状态文件                                           │
│  2. 限制访问权限                                           │
│  3. 使用远程后端(支持加密)                                │
│  4. 不要将状态文件提交到版本控制                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

3. 状态锁定 #

text
┌─────────────────────────────────────────────────────────────┐
│                    状态锁定                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  并发问题:                                                 │
│  用户 A: terraform apply                                   │
│  用户 B: terraform apply  ← 同时执行                       │
│                                                             │
│  可能导致:                                                 │
│  ❌ 状态损坏                                               │
│  ❌ 资源冲突                                               │
│  ❌ 不一致状态                                             │
│                                                             │
│  解决方案:状态锁定                                         │
│  ✅ 同一时间只有一个操作                                   │
│  ✅ 远程后端支持锁定                                       │
│                                                             │
└─────────────────────────────────────────────────────────────┘

状态安全 #

1. 不要提交状态文件 #

gitignore
.terraform/
*.tfstate
*.tfstate.*
*.tfvars

2. 加密状态文件 #

使用远程后端加密:

hcl
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    kms_key_id     = "alias/terraform-state-key"
  }
}

3. 限制访问权限 #

bash
chmod 600 terraform.tfstate

4. 定期备份 #

hcl
terraform {
  backend "s3" {
    bucket               = "my-terraform-state"
    key                  = "prod/terraform.tfstate"
    region               = "us-east-1"
    encrypt              = true
    dynamodb_table       = "terraform-state-lock"
    skip_metadata_api_check = false
  }
}

状态刷新 #

自动刷新 #

Terraform 在 planapply 时会自动刷新状态:

bash
terraform plan
terraform apply

手动刷新 #

bash
terraform refresh

刷新过程 #

text
┌─────────────────────────────────────────────────────────────┐
│                    刷新过程                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. 读取状态文件                                           │
│  2. 对每个资源调用 Provider API                            │
│  3. 获取资源的当前状态                                     │
│  4. 更新状态文件                                           │
│                                                             │
│  注意:                                                    │
│  - 刷新会修改状态文件                                      │
│  - 可能检测到配置漂移                                      │
│  - 资源被手动修改时会更新                                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

状态文件版本 #

版本兼容性 #

text
┌─────────────────────────────────────────────────────────────┐
│                    版本兼容性                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Terraform 版本与状态版本:                                 │
│  - Terraform 0.12+  → 状态版本 4                           │
│  - Terraform 0.7-0.11 → 状态版本 3                         │
│                                                             │
│  升级 Terraform 时:                                        │
│  - 通常向后兼容                                            │
│  - 可能需要状态升级                                        │
│  - 建议先备份状态                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

状态升级 #

bash
terraform state replace-provider

状态最佳实践 #

1. 使用远程状态 #

hcl
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "us-east-1"
    encrypt        = true
    dynamodb_table = "terraform-state-lock"
  }
}

2. 分离状态文件 #

text
project/
├── environments/
│   ├── dev/
│   │   └── terraform.tfstate
│   ├── staging/
│   │   └── terraform.tfstate
│   └── prod/
│       └── terraform.tfstate
└── modules/

3. 状态隔离 #

hcl
resource "aws_s3_bucket" "state" {
  bucket = "my-terraform-state"
  
  versioning {
    enabled = true
  }
  
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "aws:kms"
      }
    }
  }
}

4. 定期备份 #

hcl
resource "aws_s3_bucket_versioning" "state" {
  bucket = aws_s3_bucket.state.id
  versioning_configuration {
    status = "Enabled"
  }
}

下一步 #

了解了状态基础后,接下来学习 远程状态,了解如何配置和使用远程状态存储!

最后更新:2026-03-29