在大型基礎設施專案中,Terraform 的執行效能直接影響部署速度與開發團隊的生產力。本文將深入探討 Terraform 效能優化的各個面向,從平行處理參數到狀態檔案管理,幫助您打造更快速、更有效率的 Infrastructure as Code 工作流程。
Terraform 的執行效能受到多個因素影響:
影響效能的主要因素
- 資源數量:管理的資源越多,plan 和 apply 階段所需時間越長
- Provider API 回應速度:不同雲端供應商的 API 延遲差異
- 狀態檔案大小:龐大的 state file 會增加讀取和寫入時間
- 網路延遲:遠端後端和 Provider 之間的網路狀況
- 資源依賴關係:複雜的依賴鏈會限制平行處理能力
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
|
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 + DynamoDB | 低 | DynamoDB | AWS 環境首選 |
| Azure Blob | 低 | Blob Lease | Azure 環境首選 |
| 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
|
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"
|
效能診斷與監控
有效的診斷工具和方法可幫助識別效能瓶頸。
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 "========================================"
|
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 效能優化是一個持續的過程,需要根據專案規模和需求不斷調整。以下是關鍵要點的整理:
效能優化檢查清單
進階建議
- 持續監控:將效能指標納入 CI/CD pipeline
- 文件化:記錄專案的效能基準和優化歷史
- 團隊培訓:確保團隊成員了解效能最佳實踐
- 定期審查:每季度檢視 Terraform 設定和效能
透過這些優化策略,您可以顯著提升 Terraform 的執行效率,減少部署時間,提高團隊生產力。
參考資源