Terraform 狀態檔管理與遠端後端

Learn how to manage Terraform state files including state concepts, local vs remote state, S3 backend configuration, state locking, and state operations

在 Terraform 中,狀態檔(State File)是追蹤基礎設施資源的核心機制。正確管理狀態檔對於團隊協作、資源追蹤和基礎設施維護至關重要。本文將深入探討狀態檔的概念、遠端後端配置以及常用的狀態操作指令。

State 檔概念(State File Concepts)

什麼是 Terraform State?

Terraform State 是一個 JSON 格式的檔案,用於儲存 Terraform 管理的基礎設施資源的當前狀態。預設情況下,這個檔案名為 terraform.tfstate,存放在工作目錄中。

State 檔的作用

功能說明
資源追蹤記錄 Terraform 管理的所有資源及其屬性
效能優化避免每次執行時都需要查詢雲端 API
相依性管理維護資源之間的相依關係
變更偵測比對計畫變更與實際狀態的差異

State 檔結構

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{
  "version": 4,
  "terraform_version": "1.5.0",
  "serial": 10,
  "lineage": "abc123-def456-ghi789",
  "outputs": {
    "vpc_id": {
      "value": "vpc-0123456789abcdef0",
      "type": "string"
    }
  },
  "resources": [
    {
      "mode": "managed",
      "type": "aws_vpc",
      "name": "main",
      "provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
      "instances": [
        {
          "schema_version": 1,
          "attributes": {
            "id": "vpc-0123456789abcdef0",
            "cidr_block": "10.0.0.0/16",
            "enable_dns_hostnames": true,
            "tags": {
              "Name": "main-vpc"
            }
          }
        }
      ]
    }
  ]
}

State 檔的重要性

  1. 真相來源(Source of Truth):State 檔是 Terraform 認知的基礎設施真實狀態
  2. 資源映射:將設定檔中的資源對應到雲端的實際資源
  3. 元資料儲存:包含資源相依性和其他重要元資料
  4. 敏感資料:可能包含密碼、金鑰等敏感資訊(需妥善保護)

本地 vs 遠端狀態(Local vs Remote State)

本地狀態(Local State)

本地狀態是 Terraform 的預設行為,狀態檔直接存放在工作目錄中。

本地狀態的優點

  • 設定簡單,無需額外配置
  • 適合個人開發和學習
  • 執行速度快

本地狀態的缺點

  • 不適合團隊協作
  • 無法防止並行操作衝突
  • 檔案可能遺失或損壞
  • 敏感資料暴露風險

遠端狀態(Remote State)

遠端狀態將 State 檔儲存在遠端儲存服務中,如 AWS S3、Azure Blob Storage 或 Terraform Cloud。

遠端狀態的優點

優點說明
團隊協作多人可安全共享相同的狀態
狀態鎖定防止並行操作造成衝突
版本控制支援狀態檔版本歷史
安全性加密儲存和存取控制
可靠性利用雲端服務的高可用性

遠端狀態的缺點

  • 需要額外的基礎設施設定
  • 可能增加網路延遲
  • 需要管理存取權限

選擇建議

1
2
3
個人專案或學習 → 本地狀態
團隊協作專案 → 遠端狀態
生產環境 → 遠端狀態 + 狀態鎖定

S3 後端設定(S3 Backend Configuration)

AWS S3 是最常用的 Terraform 遠端後端之一,配合 DynamoDB 可實現狀態鎖定功能。

建立 S3 儲存桶和 DynamoDB 表

首先,需要建立存放狀態檔的基礎設施:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# 建立 S3 儲存桶
resource "aws_s3_bucket" "terraform_state" {
  bucket = "my-terraform-state-bucket"

  tags = {
    Name        = "Terraform State Bucket"
    Environment = "management"
  }
}

# 啟用版本控制
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 = "AES256"
    }
  }
}

# 封鎖公開存取
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
}

# 建立 DynamoDB 表用於狀態鎖定
resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-state-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }

  tags = {
    Name        = "Terraform State Locks"
    Environment = "management"
  }
}

配置 S3 後端

在專案中配置 S3 後端:

1
2
3
4
5
6
7
8
9
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-locks"
  }
}

後端配置參數說明

參數說明必填
bucketS3 儲存桶名稱
key狀態檔在儲存桶中的路徑
regionS3 儲存桶所在區域
encrypt是否啟用伺服器端加密
dynamodb_table狀態鎖定用的 DynamoDB 表
profileAWS CLI profile 名稱
role_arn用於存取的 IAM 角色 ARN

多環境狀態管理

使用不同的 key 來區分環境:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# 開發環境
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "dev/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-locks"
  }
}

# 正式環境
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-locks"
  }
}

使用 Workspace 管理多環境

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 建立新的 workspace
terraform workspace new dev
terraform workspace new staging
terraform workspace new prod

# 切換 workspace
terraform workspace select prod

# 列出所有 workspace
terraform workspace list

# 顯示當前 workspace
terraform workspace show

配合 workspace 的後端配置:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    dynamodb_table = "terraform-state-locks"
    workspace_key_prefix = "environments"
  }
}

狀態檔路徑將會是:environments/<workspace_name>/terraform.tfstate

狀態鎖定(State Locking)

什麼是狀態鎖定?

狀態鎖定是一種防止多個使用者同時修改狀態檔的機制。當一個操作正在進行時,其他操作將被阻擋,直到鎖定被釋放。

狀態鎖定的重要性

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
沒有狀態鎖定的風險:
┌─────────────┐     ┌─────────────┐
│   使用者 A   │     │   使用者 B   │
│ terraform   │     │ terraform   │
│   apply     │     │   apply     │
└──────┬──────┘     └──────┬──────┘
       │                   │
       ▼                   ▼
┌─────────────────────────────────┐
│         terraform.tfstate       │
│           (衝突發生!)            │
└─────────────────────────────────┘

DynamoDB 狀態鎖定機制

當使用 DynamoDB 進行狀態鎖定時:

  1. 取得鎖定:Terraform 在 DynamoDB 表中建立一筆記錄
  2. 執行操作:進行 plan/apply 等操作
  3. 釋放鎖定:操作完成後刪除鎖定記錄

鎖定記錄範例:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  "LockID": "my-terraform-state-bucket/prod/terraform.tfstate",
  "Info": {
    "ID": "abc123-def456",
    "Operation": "OperationTypeApply",
    "Who": "user@hostname",
    "Version": "1.5.0",
    "Created": "2023-10-09T10:00:00Z"
  }
}

處理鎖定問題

查看鎖定狀態

1
2
3
4
5
6
7
8
9
# 如果遇到鎖定錯誤,會顯示鎖定資訊
terraform plan
# Error: Error acquiring the state lock
# Lock Info:
#   ID:        abc123-def456
#   Path:      my-terraform-state-bucket/prod/terraform.tfstate
#   Operation: OperationTypeApply
#   Who:       user@hostname
#   Created:   2023-10-09T10:00:00Z

強制解除鎖定

1
2
3
4
5
# 使用 Lock ID 強制解除鎖定(謹慎使用!)
terraform force-unlock abc123-def456

# 確認解除
terraform force-unlock -force abc123-def456

跳過鎖定(僅限特殊情況)

1
2
# 不建議在生產環境使用
terraform apply -lock=false

鎖定超時設定

1
2
# 設定鎖定等待時間(預設為 0s)
terraform apply -lock-timeout=5m

狀態操作指令(State Commands)

Terraform 提供多種指令來管理和操作狀態檔。

terraform state list

列出狀態檔中的所有資源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 列出所有資源
terraform state list

# 輸出範例:
# aws_vpc.main
# aws_subnet.public[0]
# aws_subnet.public[1]
# aws_internet_gateway.main
# aws_route_table.public

# 使用過濾器
terraform state list aws_subnet.*

terraform state show

顯示特定資源的詳細資訊:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 顯示資源詳細資訊
terraform state show aws_vpc.main

# 輸出範例:
# resource "aws_vpc" "main" {
#     arn                              = "arn:aws:ec2:ap-northeast-1:123456789012:vpc/vpc-0123456789abcdef0"
#     cidr_block                       = "10.0.0.0/16"
#     enable_dns_hostnames             = true
#     enable_dns_support               = true
#     id                               = "vpc-0123456789abcdef0"
#     instance_tenancy                 = "default"
#     tags                             = {
#         "Name" = "main-vpc"
#     }
# }

terraform state mv

移動或重新命名資源:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 重新命名資源
terraform state mv aws_vpc.main aws_vpc.primary

# 移動到模組
terraform state mv aws_vpc.main module.network.aws_vpc.main

# 從模組移出
terraform state mv module.network.aws_vpc.main aws_vpc.main

# 移動整個模組
terraform state mv module.old_name module.new_name

terraform state rm

從狀態中移除資源(不會刪除實際資源):

1
2
3
4
5
6
7
8
# 移除單一資源
terraform state rm aws_instance.example

# 移除模組中的資源
terraform state rm module.vpc.aws_subnet.public

# 移除整個模組
terraform state rm module.vpc

terraform state pull

從遠端後端拉取狀態檔:

1
2
3
4
5
# 拉取狀態並輸出到標準輸出
terraform state pull

# 儲存到檔案
terraform state pull > terraform.tfstate.backup

terraform state push

推送本地狀態到遠端後端:

1
2
3
4
5
# 推送狀態(謹慎使用!)
terraform state push terraform.tfstate.backup

# 強制推送
terraform state push -force terraform.tfstate.backup

terraform import

匯入現有資源到 Terraform 管理:

1
2
3
4
5
6
7
8
# 匯入 VPC
terraform import aws_vpc.main vpc-0123456789abcdef0

# 匯入 EC2 執行個體
terraform import aws_instance.web i-0123456789abcdef0

# 匯入到模組
terraform import module.vpc.aws_vpc.main vpc-0123456789abcdef0

匯入前需要先在設定檔中定義資源:

1
2
3
4
# 先定義資源區塊
resource "aws_vpc" "main" {
  # 匯入後再填寫詳細設定
}

terraform refresh

更新狀態檔以反映實際基礎設施:

1
2
3
4
5
# 刷新狀態
terraform refresh

# 注意:在 Terraform 1.5+ 中,建議使用
terraform apply -refresh-only

狀態操作最佳實踐

操作建議
狀態備份操作前先執行 terraform state pull 備份
狀態移動使用 terraform state mv 而非手動編輯
資源匯入匯入後立即執行 terraform plan 驗證
狀態推送除非必要,否則避免使用 state push
鎖定解除確認無其他操作進行中才使用 force-unlock

進階技巧

狀態檔資料源

從其他狀態檔讀取資料:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 從其他專案讀取 VPC ID
data "terraform_remote_state" "network" {
  backend = "s3"

  config = {
    bucket = "my-terraform-state-bucket"
    key    = "network/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

# 使用讀取的資料
resource "aws_instance" "web" {
  ami           = "ami-0123456789abcdef0"
  instance_type = "t3.micro"
  subnet_id     = data.terraform_remote_state.network.outputs.public_subnet_ids[0]
}

敏感資料處理

1
2
3
4
5
# 標記輸出為敏感
output "database_password" {
  value     = aws_db_instance.main.password
  sensitive = true
}

狀態檔加密

使用 AWS KMS 加密狀態檔:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
terraform {
  backend "s3" {
    bucket         = "my-terraform-state-bucket"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true
    kms_key_id     = "arn:aws:kms:ap-northeast-1:123456789012:key/12345678-1234-1234-1234-123456789012"
    dynamodb_table = "terraform-state-locks"
  }
}

總結

Terraform 狀態檔管理是基礎設施即程式碼實踐中的關鍵環節。透過本文介紹的概念和技術,您可以:

  • 理解 State 檔:掌握狀態檔的結構、作用和重要性
  • 選擇適當的後端:根據專案需求選擇本地或遠端狀態
  • 配置 S3 後端:使用 AWS S3 和 DynamoDB 建立安全的遠端狀態管理
  • 實施狀態鎖定:防止並行操作造成的衝突
  • 操作狀態檔:使用各種指令管理和維護狀態

正確的狀態管理將大幅提升團隊協作效率和基礎設施的可靠性。

參考資源

comments powered by Disqus
Built with Hugo
Theme Stack designed by Jimmy