Terraform 效能優化與平行處理

Terraform Performance Optimization and Parallelism

在大型基礎設施專案中,Terraform 的執行效能直接影響部署速度與開發團隊的生產力。本文將深入探討 Terraform 效能優化的各個面向,從平行處理參數到狀態檔案管理,幫助您打造更快速、更有效率的 Infrastructure as Code 工作流程。

Terraform 執行效能概述

Terraform 的執行效能受到多個因素影響:

影響效能的主要因素

  1. 資源數量:管理的資源越多,plan 和 apply 階段所需時間越長
  2. Provider API 回應速度:不同雲端供應商的 API 延遲差異
  3. 狀態檔案大小:龐大的 state file 會增加讀取和寫入時間
  4. 網路延遲:遠端後端和 Provider 之間的網路狀況
  5. 資源依賴關係:複雜的依賴鏈會限制平行處理能力

Terraform 執行階段

1
2
3
4
5
# Terraform 主要執行階段及其效能特性
terraform init      # 初始化:下載 provider、module
terraform plan      # 規劃:讀取狀態、計算差異
terraform apply     # 應用:建立/修改/刪除資源
terraform destroy   # 銷毀:刪除所有資源

每個階段都有其效能瓶頸,了解這些階段有助於針對性優化。

平行處理參數(-parallelism)

Terraform 預設會平行處理無依賴關係的資源,-parallelism 參數可調整同時執行的操作數量。

預設值與調整

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 預設平行度為 10
terraform apply

# 增加平行度以加速大量資源的部署
terraform apply -parallelism=20

# 降低平行度以減少 API rate limiting
terraform apply -parallelism=5

# 完全序列化執行(除錯用途)
terraform apply -parallelism=1

平行度設定最佳實踐

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 針對不同情境的建議設定

# AWS - 大型專案(考慮 API rate limits)
terraform apply -parallelism=15

# Azure - 一般專案
terraform apply -parallelism=10

# GCP - 小型專案可適度提高
terraform apply -parallelism=25

# 混合雲環境 - 保守設定
terraform apply -parallelism=8

環境變數設定

1
2
3
4
5
6
# 透過環境變數設定預設平行度
export TF_CLI_ARGS_apply="-parallelism=15"
export TF_CLI_ARGS_plan="-parallelism=15"

# 或在 shell profile 中永久設定
echo 'export TF_CLI_ARGS_apply="-parallelism=15"' >> ~/.bashrc

注意事項

過高的平行度可能導致:

  • 雲端供應商 API rate limiting
  • 網路頻寬飽和
  • 本地記憶體不足

建議逐步調整並監控執行結果,找出最適合您環境的設定值。

狀態檔案優化

State file 是 Terraform 效能的關鍵因素之一。

狀態檔案壓縮

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 使用支援壓縮的後端
terraform {
  backend "s3" {
    bucket = "my-terraform-state"
    key    = "prod/terraform.tfstate"
    region = "ap-northeast-1"

    # 啟用伺服器端加密(同時可略微減少傳輸大小)
    encrypt = true
  }
}

狀態檔案分割

對於大型專案,將單一巨大的狀態檔案分割成多個較小的檔案:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 專案結構範例
infrastructure/
├── network/
│   ├── main.tf
│   ├── variables.tf
│   └── backend.tf      # 獨立的 state file
├── compute/
│   ├── main.tf
│   ├── variables.tf
│   └── backend.tf      # 獨立的 state file
└── database/
    ├── main.tf
    ├── variables.tf
    └── backend.tf      # 獨立的 state file

使用 terraform_remote_state 跨專案引用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 在 compute 專案中引用 network 的輸出
data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "my-terraform-state"
    key    = "network/terraform.tfstate"
    region = "ap-northeast-1"
  }
}

resource "aws_instance" "web" {
  subnet_id = data.terraform_remote_state.network.outputs.subnet_id
  # ...
}

定期清理狀態檔案

1
2
3
4
5
6
7
8
# 移除已不存在的資源引用
terraform state rm module.old_module

# 檢視狀態檔案內容
terraform state list

# 重新整理狀態(謹慎使用)
terraform refresh

Provider 快取設定

Provider plugins 的下載和初始化會消耗大量時間,適當的快取設定可顯著提升效能。

Plugin 快取目錄

1
2
3
4
5
6
7
8
# 設定全域 plugin 快取目錄
export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"

# 建立快取目錄
mkdir -p $TF_PLUGIN_CACHE_DIR

# 永久設定
echo 'export TF_PLUGIN_CACHE_DIR="$HOME/.terraform.d/plugin-cache"' >> ~/.bashrc

CLI 設定檔

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# ~/.terraformrc 或 %APPDATA%/terraform.rc (Windows)
plugin_cache_dir = "$HOME/.terraform.d/plugin-cache"

# 停用 checkpoint(減少網路請求)
disable_checkpoint = true

# Provider 安裝方法設定
provider_installation {
  filesystem_mirror {
    path    = "/usr/share/terraform/providers"
    include = ["registry.terraform.io/*/*"]
  }
  direct {
    exclude = []
  }
}

離線模式與本地映像

1
2
3
4
5
# 下載 provider 到本地目錄
terraform providers mirror /path/to/local/mirror

# 使用本地映像
terraform init -plugin-dir=/path/to/local/mirror

Provider 版本鎖定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# versions.tf - 明確鎖定版本避免重複下載
terraform {
  required_version = ">= 1.5.0"

  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 5.0"
    }
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "= 3.75.0"
    }
  }
}

資源依賴優化

減少不必要的依賴關係可提升平行處理效率。

明確依賴 vs 隱含依賴

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 隱含依賴(Terraform 自動偵測)
resource "aws_instance" "web" {
  subnet_id = aws_subnet.main.id  # 隱含依賴 aws_subnet.main
}

# 明確依賴(當隱含依賴不足時使用)
resource "aws_instance" "app" {
  # ...

  depends_on = [
    aws_iam_role_policy_attachment.app_policy
  ]
}

避免不必要的依賴

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 不良實踐 - 產生不必要的依賴
resource "aws_instance" "web" {
  tags = {
    Name = aws_vpc.main.tags["Name"]  # 不必要地依賴 VPC
  }
}

# 良好實踐 - 使用變數
variable "environment" {
  default = "production"
}

resource "aws_instance" "web" {
  tags = {
    Name = "${var.environment}-web"
  }
}

使用 count 和 for_each 優化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# 使用 for_each 建立多個獨立資源(可平行處理)
resource "aws_instance" "web" {
  for_each = toset(["web-1", "web-2", "web-3"])

  ami           = var.ami_id
  instance_type = "t3.micro"

  tags = {
    Name = each.key
  }
}

# 避免使用 count 搭配 element()(可能產生依賴)
# 不建議
resource "aws_instance" "web" {
  count = 3

  subnet_id = element(aws_subnet.main[*].id, count.index)
}

資源群組化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 使用 module 將相關資源群組化
module "web_tier" {
  source = "./modules/web-tier"

  vpc_id     = module.network.vpc_id
  subnet_ids = module.network.public_subnet_ids
}

module "app_tier" {
  source = "./modules/app-tier"

  vpc_id     = module.network.vpc_id
  subnet_ids = module.network.private_subnet_ids

  # 明確表達依賴關係
  depends_on = [module.web_tier]
}

大型專案分割策略

對於管理數百甚至數千個資源的大型專案,適當的分割策略至關重要。

Workspace 分割

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 建立不同環境的 workspace
terraform workspace new development
terraform workspace new staging
terraform workspace new production

# 切換 workspace
terraform workspace select production

# 列出所有 workspace
terraform workspace list
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 根據 workspace 調整設定
locals {
  environment = terraform.workspace

  instance_count = {
    development = 1
    staging     = 2
    production  = 5
  }
}

resource "aws_instance" "web" {
  count = local.instance_count[local.environment]
  # ...
}

目錄結構分割

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 依功能分割
infrastructure/
├── 01-foundation/          # VPC、IAM 等基礎設施
│   ├── main.tf
│   └── outputs.tf
├── 02-data/                # 資料庫、快取
│   ├── main.tf
│   └── outputs.tf
├── 03-compute/             # EC2、ECS、Lambda
│   ├── main.tf
│   └── outputs.tf
└── 04-monitoring/          # CloudWatch、告警
    ├── main.tf
    └── outputs.tf

Terragrunt 整合

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# terragrunt.hcl - 簡化多專案管理
terraform {
  source = "../modules//vpc"
}

include {
  path = find_in_parent_folders()
}

inputs = {
  vpc_cidr = "10.0.0.0/16"
  environment = "production"
}

dependencies {
  paths = []
}
1
2
3
# 使用 Terragrunt 平行執行
terragrunt run-all plan --parallelism=3
terragrunt run-all apply --parallelism=3

微服務架構的專案組織

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
# 每個微服務獨立的 Terraform 設定
microservices/
├── service-a/
│   ├── terraform/
│   │   ├── main.tf
│   │   └── backend.tf
│   └── src/
├── service-b/
│   ├── terraform/
│   │   ├── main.tf
│   │   └── backend.tf
│   └── src/
└── shared-infrastructure/
    ├── networking/
    ├── security/
    └── monitoring/

遠端後端效能考量

選擇和設定適當的遠端後端對於團隊協作和效能都很重要。

常見後端比較

後端延遲鎖定機制適用情境
S3 + DynamoDBDynamoDBAWS 環境首選
Azure BlobBlob LeaseAzure 環境首選
GCS原生支援GCP 環境首選
Terraform Cloud內建企業級管理
Consul內建混合雲環境

S3 後端優化設定

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
terraform {
  backend "s3" {
    bucket         = "my-terraform-state"
    key            = "prod/terraform.tfstate"
    region         = "ap-northeast-1"
    encrypt        = true

    # DynamoDB 用於狀態鎖定
    dynamodb_table = "terraform-state-lock"

    # 啟用版本控制(資料保護)
    # 需在 S3 bucket 設定中啟用

    # 使用 IAM Role(建議)
    role_arn = "arn:aws:iam::123456789012:role/TerraformStateAccess"
  }
}

減少後端延遲

1
2
3
4
5
6
7
8
9
# 選擇最近的區域
terraform {
  backend "s3" {
    region = "ap-northeast-1"  # 選擇離團隊最近的區域
  }
}

# 使用 VPC Endpoint(私有網路)
# 需額外設定 AWS VPC Endpoint for S3

狀態鎖定最佳實踐

1
2
3
4
5
# 手動解除卡住的鎖定(謹慎使用)
terraform force-unlock LOCK_ID

# 設定鎖定超時
terraform apply -lock-timeout=5m

Terraform Cloud/Enterprise 設定

1
2
3
4
5
6
7
8
9
terraform {
  cloud {
    organization = "my-organization"

    workspaces {
      name = "my-workspace"
    }
  }
}
1
2
3
# 環境變數設定
export TF_CLOUD_ORGANIZATION="my-organization"
export TF_TOKEN_app_terraform_io="your-api-token"

效能診斷與監控

有效的診斷工具和方法可幫助識別效能瓶頸。

Terraform 日誌等級

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 啟用詳細日誌
export TF_LOG=DEBUG
export TF_LOG_PATH="./terraform.log"

# 可用的日誌等級
# TRACE - 最詳細
# DEBUG - 除錯資訊
# INFO  - 一般資訊
# WARN  - 警告
# ERROR - 僅錯誤

# 針對特定元件啟用日誌
export TF_LOG_CORE=DEBUG
export TF_LOG_PROVIDER=DEBUG

執行時間分析

1
2
3
4
5
6
7
# 使用 time 命令測量執行時間
time terraform plan

# 輸出範例:
# real    1m23.456s
# user    0m45.123s
# sys     0m12.345s

自訂效能監控腳本

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/bin/bash
# terraform-perf.sh - Terraform 效能監控腳本

START_TIME=$(date +%s)

# 執行 Terraform 命令
terraform "$@" 2>&1 | tee terraform_output.log

END_TIME=$(date +%s)
DURATION=$((END_TIME - START_TIME))

# 分析資源數量
RESOURCES_ADDED=$(grep -c "will be created" terraform_output.log || echo 0)
RESOURCES_CHANGED=$(grep -c "will be updated" terraform_output.log || echo 0)
RESOURCES_DESTROYED=$(grep -c "will be destroyed" terraform_output.log || echo 0)

echo "========================================"
echo "Terraform 效能報告"
echo "========================================"
echo "執行時間: ${DURATION} 秒"
echo "新增資源: ${RESOURCES_ADDED}"
echo "變更資源: ${RESOURCES_CHANGED}"
echo "刪除資源: ${RESOURCES_DESTROYED}"
echo "========================================"

使用 Terraform Graph 分析依賴

1
2
3
4
5
6
7
8
# 產生依賴圖
terraform graph | dot -Tpng > dependency-graph.png

# 產生 SVG 格式(可縮放)
terraform graph | dot -Tsvg > dependency-graph.svg

# 篩選特定類型
terraform graph -type=plan | dot -Tpng > plan-graph.png

效能基準測試

 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
#!/bin/bash
# benchmark.sh - Terraform 效能基準測試

ITERATIONS=5
TOTAL_TIME=0

for i in $(seq 1 $ITERATIONS); do
    echo "執行第 $i 次測試..."

    # 清理快取
    rm -rf .terraform

    # 測量 init 時間
    INIT_START=$(date +%s.%N)
    terraform init -input=false > /dev/null 2>&1
    INIT_END=$(date +%s.%N)

    # 測量 plan 時間
    PLAN_START=$(date +%s.%N)
    terraform plan -input=false > /dev/null 2>&1
    PLAN_END=$(date +%s.%N)

    INIT_TIME=$(echo "$INIT_END - $INIT_START" | bc)
    PLAN_TIME=$(echo "$PLAN_END - $PLAN_START" | bc)

    echo "  Init: ${INIT_TIME}s, Plan: ${PLAN_TIME}s"

    TOTAL_TIME=$(echo "$TOTAL_TIME + $INIT_TIME + $PLAN_TIME" | bc)
done

AVG_TIME=$(echo "scale=2; $TOTAL_TIME / $ITERATIONS" | bc)
echo "平均執行時間: ${AVG_TIME}s"

CI/CD 整合監控

 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
# .github/workflows/terraform.yml
name: Terraform Performance

on:
  pull_request:
    paths:
      - 'terraform/**'

jobs:
  performance:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v3
        with:
          terraform_version: 1.6.0

      - name: Terraform Init
        id: init
        run: |
          START=$(date +%s)
          terraform init
          echo "duration=$(($(date +%s) - START))" >> $GITHUB_OUTPUT          

      - name: Terraform Plan
        id: plan
        run: |
          START=$(date +%s)
          terraform plan -no-color -out=tfplan
          echo "duration=$(($(date +%s) - START))" >> $GITHUB_OUTPUT          

      - name: Performance Report
        run: |
          echo "### Terraform Performance Report" >> $GITHUB_STEP_SUMMARY
          echo "| Phase | Duration |" >> $GITHUB_STEP_SUMMARY
          echo "|-------|----------|" >> $GITHUB_STEP_SUMMARY
          echo "| Init | ${{ steps.init.outputs.duration }}s |" >> $GITHUB_STEP_SUMMARY
          echo "| Plan | ${{ steps.plan.outputs.duration }}s |" >> $GITHUB_STEP_SUMMARY          

總結

Terraform 效能優化是一個持續的過程,需要根據專案規模和需求不斷調整。以下是關鍵要點的整理:

效能優化檢查清單

  • 根據環境調整 -parallelism 參數
  • 設定 Provider plugin 快取目錄
  • 將大型專案分割成多個狀態檔案
  • 優化資源依賴關係,減少不必要的 depends_on
  • 選擇離團隊最近的遠端後端區域
  • 建立效能監控和基準測試機制
  • 定期清理和維護狀態檔案

進階建議

  1. 持續監控:將效能指標納入 CI/CD pipeline
  2. 文件化:記錄專案的效能基準和優化歷史
  3. 團隊培訓:確保團隊成員了解效能最佳實踐
  4. 定期審查:每季度檢視 Terraform 設定和效能

透過這些優化策略,您可以顯著提升 Terraform 的執行效率,減少部署時間,提高團隊生產力。

參考資源

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