Terraform 远程状态 #

什么是远程状态? #

远程状态允许将 Terraform 状态文件存储在远程位置,而不是本地文件系统。这使得团队协作、状态共享和状态安全变得更加容易。

text
┌─────────────────────────────────────────────────────────────┐
│                    远程状态的优势                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  ┌─────────────┐     ┌─────────────┐     ┌─────────────┐   │
│  │ 团队协作     │     │ 状态锁定     │     │ 安全存储    │   │
│  └─────────────┘     └─────────────┘     └─────────────┘   │
│                                                             │
│  - 多人共享同一状态                                        │
│  - 防止并发操作冲突                                        │
│  - 加密存储敏感信息                                        │
│  - 自动备份和版本控制                                      │
│                                                             │
└─────────────────────────────────────────────────────────────┘

后端类型 #

标准后端 #

text
┌─────────────────────────────────────────────────────────────┐
│                    标准后端                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  云存储:                                                   │
│  ├── S3           AWS S3                                   │
│  ├── GCS          Google Cloud Storage                     │
│  ├── Azure Blob   Azure Blob Storage                       │
│  └── OSS          Alibaba Cloud OSS                        │
│                                                             │
│  服务:                                                     │
│  ├── Terraform Cloud  HashiCorp 托管服务                   │
│  ├── Consul          HashiCorp Consul                      │
│  ├── etcd            etcd 键值存储                         │
│  └── HTTP            HTTP 后端                             │
│                                                             │
│  数据库:                                                   │
│  ├── PostgreSQL     PostgreSQL 数据库                      │
│  └── MySQL          MySQL 数据库                           │
│                                                             │
└─────────────────────────────────────────────────────────────┘

增强后端 #

text
┌─────────────────────────────────────────────────────────────┐
│                    增强后端                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  Terraform Cloud / Enterprise                              │
│  - 远程操作                                                │
│  - 状态管理                                                │
│  - 变量管理                                                │
│  - 运行历史                                                │
│  - 策略执行                                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

S3 后端 #

基本配置 #

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

完整配置 #

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"
    dynamodb_table       = "terraform-state-lock"
    acl                  = "private"
    workspace_key_prefix = "environments"
    skip_metadata_api_check = false
  }
}

配置参数 #

text
┌─────────────────────────────────────────────────────────────┐
│                    S3 后端参数                               │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  bucket               S3 存储桶名称                         │
│  key                  状态文件路径                          │
│  region               AWS 区域                              │
│  encrypt              启用加密                              │
│  kms_key_id           KMS 密钥 ID                           │
│  dynamodb_table       DynamoDB 表(状态锁定)               │
│  acl                  访问控制列表                          │
│  workspace_key_prefix 工作空间前缀                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

创建 S3 后端资源 #

hcl
resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-terraform-state"
  
  lifecycle {
    prevent_destroy = true
  }
}

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

resource "aws_s3_bucket_server_side_encryption_configuration" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.terraform_state.id
    }
  }
}

resource "aws_s3_bucket_public_access_block" "terraform_state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

resource "aws_dynamodb_table" "terraform_state_lock" {
  name         = "terraform-state-lock"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"
  
  attribute {
    name = "LockID"
    type = "S"
  }
}

resource "aws_kms_key" "terraform_state" {
  description             = "Terraform state encryption key"
  deletion_window_in_days = 10
  enable_key_rotation     = true
}

Azure Blob 后端 #

基本配置 #

hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "tfstate12345"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
  }
}

完整配置 #

hcl
terraform {
  backend "azurerm" {
    resource_group_name  = "terraform-state-rg"
    storage_account_name = "tfstate12345"
    container_name       = "tfstate"
    key                  = "prod.terraform.tfstate"
    
    subscription_id      = "00000000-0000-0000-0000-000000000000"
    tenant_id            = "00000000-0000-0000-0000-000000000000"
    
    use_azuread_auth     = true
  }
}

GCS 后端 #

基本配置 #

hcl
terraform {
  backend "gcs" {
    bucket = "my-terraform-state"
    prefix = "prod"
  }
}

完整配置 #

hcl
terraform {
  backend "gcs" {
    bucket      = "my-terraform-state"
    prefix      = "prod"
    credentials = "service-account.json"
    encryption  = "google-managed"
  }
}

Terraform Cloud 后端 #

配置 #

hcl
terraform {
  cloud {
    organization = "my-organization"
    
    workspaces {
      name = "my-workspace"
    }
  }
}

多工作空间 #

hcl
terraform {
  cloud {
    organization = "my-organization"
    
    workspaces {
      tags = ["networking", "production"]
    }
  }
}

Consul 后端 #

hcl
terraform {
  backend "consul" {
    address = "consul.example.com:8500"
    scheme  = "https"
    path    = "terraform/state/prod"
    lock    = true
  }
}

PostgreSQL 后端 #

hcl
terraform {
  backend "pg" {
    conn_str    = "postgres://user:pass@db.example.com/terraform_state"
    schema_name = "terraform"
  }
}

HTTP 后端 #

hcl
terraform {
  backend "http" {
    address        = "https://example.com/state/my-project"
    lock_address   = "https://example.com/lock/my-project"
    unlock_address = "https://example.com/unlock/my-project"
    username       = "user"
    password       = "pass"
  }
}

后端配置方法 #

1. 直接配置 #

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

2. 部分配置 #

hcl
terraform {
  backend "s3" {}
}
bash
terraform init \
  -backend-config="bucket=my-terraform-state" \
  -backend-config="key=prod/terraform.tfstate" \
  -backend-config="region=us-east-1"

3. 配置文件 #

创建 backend.hcl

hcl
bucket = "my-terraform-state"
key    = "prod/terraform.tfstate"
region = "us-east-1"
bash
terraform init -backend-config=backend.hcl

4. 环境变量 #

bash
export TF_CLI_ARGS_init="-backend-config=backend.hcl"
terraform init

状态锁定 #

自动锁定 #

大多数远程后端支持自动状态锁定:

text
┌─────────────────────────────────────────────────────────────┐
│                    状态锁定流程                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. terraform apply 开始                                   │
│  2. 获取状态锁                                             │
│  3. 执行操作                                               │
│  4. 更新状态                                               │
│  5. 释放状态锁                                             │
│                                                             │
│  如果锁已被占用:                                           │
│  Error: Error acquiring the state lock                     │
│                                                             │
└─────────────────────────────────────────────────────────────┘

S3 + DynamoDB 锁定 #

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

手动解锁 #

bash
terraform force-unlock <LOCK_ID>

状态隔离 #

按环境隔离 #

text
┌─────────────────────────────────────────────────────────────┐
│                    环境隔离                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  S3 存储桶结构:                                            │
│  my-terraform-state/                                       │
│  ├── dev/                                                  │
│  │   └── terraform.tfstate                                 │
│  ├── staging/                                              │
│  │   └── terraform.tfstate                                 │
│  └── prod/                                                 │
│      └── terraform.tfstate                                 │
│                                                             │
│  每个环境独立的状态文件                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

按组件隔离 #

text
┌─────────────────────────────────────────────────────────────┐
│                    组件隔离                                  │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  my-terraform-state/                                       │
│  ├── networking/                                           │
│  │   └── terraform.tfstate                                 │
│  ├── compute/                                              │
│  │   └── terraform.tfstate                                 │
│  └── database/                                             │
│      └── terraform.tfstate                                 │
│                                                             │
│  每个组件独立的状态文件                                    │
│                                                             │
└─────────────────────────────────────────────────────────────┘

读取远程状态 #

terraform_remote_state 数据源 #

hcl
data "terraform_remote_state" "vpc" {
  backend = "s3"
  
  config = {
    bucket = "my-terraform-state"
    key    = "networking/terraform.tfstate"
    region = "us-east-1"
  }
}

resource "aws_instance" "example" {
  subnet_id = data.terraform_remote_state.vpc.outputs.subnet_id
}

输出引用 #

hcl
data "terraform_remote_state" "network" {
  backend = "s3"
  
  config = {
    bucket = "my-terraform-state"
    key    = "network/terraform.tfstate"
    region = "us-east-1"
  }
}

locals {
  vpc_id     = data.terraform_remote_state.network.outputs.vpc_id
  subnet_ids = data.terraform_remote_state.network.outputs.subnet_ids
}

迁移状态 #

从本地迁移到远程 #

bash
terraform init -migrate-state

更换后端 #

bash
terraform init -migrate-state

强制迁移 #

bash
terraform init -migrate-state -force-copy

最佳实践 #

1. 启用版本控制 #

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

2. 启用加密 #

hcl
resource "aws_s3_bucket_server_side_encryption_configuration" "state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm     = "aws:kms"
      kms_master_key_id = aws_kms_key.state.id
    }
  }
}

3. 阻止公开访问 #

hcl
resource "aws_s3_bucket_public_access_block" "state" {
  bucket = aws_s3_bucket.terraform_state.id
  
  block_public_acls       = true
  block_public_policy     = true
  ignore_public_acls      = true
  restrict_public_buckets = true
}

4. 使用状态锁定 #

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

5. 分离状态文件 #

hcl
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "${path_relative_to_include()}/terraform.tfstate"
    region = "us-east-1"
  }
}

下一步 #

掌握了远程状态后,接下来学习 状态命令,了解如何使用 Terraform 状态管理命令!

最后更新:2026-03-29