跳至主要內容
ACE 服務實戰 — 第 2/11 篇

用 Terraform 管 GCP 資源:從第一份設定到共用 State

內文字級

用 Terraform 管 GCP 資源:從第一份設定到共用 State
更新:2026-10-07

在 Console 點幾下就能開出一台 VM。等到同樣的設定要在開發、測試和正式環境各做一次,光靠手動操作就很難確認三邊是否一致。用 gcloud 指令也得想辦法追蹤版本、審查變更。

  • 你還記得那台 VM 的防火牆規則是怎麼設的嗎?
  • Staging 和 Production 的設定一致嗎?
  • 新同事如何在 5 分鐘內建起一個一模一樣的環境?

Infrastructure as Code(IaC,基礎設施即程式碼)把資源設定寫成檔案,讓團隊能審查和重複套用。這篇用 Terraform 實際建立 GCP 資源,並說清楚 State 為什麼需要妥善保存。

範例會建立 VPC、VM 和 bucket,也會示範把 State 放進 GCS。操作前,先用下面這張圖看一遍變更怎麼經過預覽和審查。

Terraform 安全變更流程:Git repository 中的 Terraform modules 由短效 CI identity 觸發 terraform plan,plan 比較 Desired configuration、受保護且版本化的 remote state 與 Real resources;Review 與 Policy checks 通過後 terraform apply 才修改 GCP 資源並更新同一份 state,Scheduled plan 偵測 Drift 後回到 review,禁止 long-lived key

Terraform 的安全迴圈有三份必須比對的事實:版本化設定、受保護的 remote state、實際資源。plan 只產生差異,不改資源;review 與 policy checks 通過後才 apply,再更新同一個 state backend。排程 plan 發現 drift 也要回到審查,而不是自動覆蓋人工變更。


一、為什麼要用 Infrastructure as Code?

1.1 手動管理 vs IaC

比較手動(Console/gcloud)IaC(Terraform)
可重複性同一步驟可能有人為誤差設定可重複套用並檢查差異
版本控制操作紀錄需另外整理設定檔可放進 Git 追蹤
多環境管理Dev/Prod 設定可能悄悄不一致共用模組,分開管理環境參數
災難恢復重建環境需要整理原本的設定有設定檔可作為重建起點
Code Review變更前較難看出完整差異可在套用前審查 Plan

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。

1.2 Terraform 的核心工作流程

查看流程與節點文字

箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。

flowchart TB
  W["Write<br/>修改 HCL 期望狀態"] --> V["fmt/validate<br/>檢查格式與語法"]
  V --> P["Plan<br/>比對設定、<br/>State 與真實資源"]
  P --> R{"變更內容經 Review<br/>與政策檢查通過?"}
  R -->|"否"| W
  R -->|"是"| A["Apply<br/>建立、修改或刪除資源"]
  A --> S["更新 Remote State"]
  S --> O["監控結果與偵測 Drift"]
  O --> W
Plan 只是預覽,通過審查的 Apply 才會改動資源;完成後更新同一份遠端 State,下一次變更才能正確比對。

二、Terraform 基礎概念

Terraform 用 HCL(HashiCorp Configuration Language,HashiCorp 設定語言)這種設定語言來描述你想要的資源——下面所有 .tf 檔裡的程式碼都是 HCL,讀起來像在「填表單」,宣告你要什麼,剩下交給 Terraform。

2.1 Provider(提供者)

Provider 是 Terraform 跟雲端平台之間的橋樑,負責告訴 Terraform 怎麼跟 GCP API 溝通。

# main.tf

terraform {
  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 8.0"  # 鎖定 8.x 主版本(截至 2026 年 10 月的最新主版本;最新版請查 Registry)
    }
  }
}

provider "google" {
  project = "my-gcp-project"
  region  = "asia-east1"
}

版本鎖定說明:

  • ~> 8.0:允許 8.0.x 到 8.x.x 的任何版本,但不包含 9.0.0
  • 這樣可以自動獲得修正版本(8.1、8.2)但不會意外升到有破壞性變更的主版本
  • hashicorp/google provider 的主版本大約一年一更(7.0.0 於 2025 年 8 月、8.0.0 於 2026 年 8 月發布,2026 年 10 月初最新為 8.6.0)。實際開新專案前,建議去 Terraform Registry 確認當下的最新主版本,把 ~> 8.0 換成對應數字

2.2 Resource(資源)

Resource 代表你要在 GCP 上建立的實際物件:

# 建立一個 VPC
resource "google_compute_network" "main" {
  name                    = "my-vpc"
  auto_create_subnetworks = false  # Custom Mode
}

# 建立一個 Subnet
resource "google_compute_subnetwork" "main" {
  name          = "asia-east1-subnet"
  ip_cidr_range = "10.1.0.0/24"
  region        = "asia-east1"
  network       = google_compute_network.main.id  # 引用上面的 VPC
}

# 建立一個 VM
resource "google_compute_instance" "web" {
  name         = "web-server"
  machine_type = "e2-micro"
  zone         = "asia-east1-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"  # Debian 12 Bookworm(LTS,Debian 13 Trixie 已是現行穩定版,12 仍受長期支援)
    }
  }

  network_interface {
    subnetwork = google_compute_subnetwork.main.id
    access_config {
      # 空區塊 = 分配外部 IP;移除這個區塊 = 只有內部 IP
    }
  }

  tags = ["web-server"]
}

Resource 引用語法:TYPE.NAME.ATTRIBUTE

  • google_compute_network.main.id 代表「名為 main 的 google_compute_network 資源的 id 屬性」
  • Terraform 會自動建立依賴關係,先建立 VPC,再建立 Subnet
建立 VPC 網路頁面選擇「自動」子網路建立模式,下方表格列出每個 region 各自固定分配一個 /20 子網路

這是 Console 開 VPC 時選「自動模式」的長相——GCP 一口氣在每個 region(撰文時 43 個)各塞一個固定 /20 子網路,省事,但網段全由它決定。上面程式碼那行 auto_create_subnetworks = false 做的,就是把這整張表關掉、改走 Custom Mode,子網路自己一格一格畫。考綱 2.3 就列了建立自訂模式 VPC:預設的 default 網路是自動模式,正式環境幾乎都改用自訂模式,好把 CIDR 網段抓在自己手裡。

2.3 Variables(變數)

把設定抽成變數,讓同一份程式碼可以部署到不同環境:

# variables.tf

variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "environment" {
  description = "Environment name (dev/staging/prod)"
  type        = string
  default     = "dev"
}

variable "region" {
  description = "GCP Region"
  type        = string
  default     = "asia-east1"
}

variable "vm_count" {
  description = "Number of VM instances"
  type        = number
  default     = 1
}
# main.tf 中使用變數
resource "google_compute_instance" "web" {
  name         = "${var.environment}-web-server"  # dev-web-server 或 prod-web-server
  machine_type = var.environment == "prod" ? "e2-standard-2" : "e2-micro"
  zone         = "${var.region}-a"
  # ...
}
# terraform.tfvars(給變數指定值)
project_id  = "my-gcp-project-123"
environment = "prod"
region      = "asia-east1"

2.4 Outputs(輸出)

Outputs 讓你可以取出 Terraform 建立的資源的重要資訊:

# outputs.tf

output "vm_external_ip" {
  description = "External IP of the web server"
  value       = google_compute_instance.web.network_interface[0].access_config[0].nat_ip
}

output "vpc_id" {
  description = "VPC ID"
  value       = google_compute_network.main.id
}

執行 terraform apply 後,會顯示:

Outputs:

vm_external_ip = "34.80.XXX.XXX"
vpc_id = "projects/my-project/global/networks/my-vpc"

2.5 Data Sources(資料來源)

Data Source 讓你引用已經存在的 GCP 資源(不由 Terraform 管理的):

# 引用現有的 VPC(不重新建立)
data "google_compute_network" "existing_vpc" {
  name = "default"
}

# 引用現有的 Service Account
data "google_service_account" "existing_sa" {
  account_id = "my-existing-sa"
}

# 在 resource 中使用 data source
resource "google_compute_instance" "web" {
  # ...
  network_interface {
    network = data.google_compute_network.existing_vpc.id
  }
}

2.6 State File(狀態檔)

State File(terraform.tfstate)是 Terraform 最重要也最需要保護的檔案。

它記錄什麼:

{
  "resources": [
    {
      "type": "google_compute_instance",
      "name": "web",
      "instances": [
        {
          "attributes": {
            "id": "projects/my-project/zones/asia-east1-a/instances/web-server",
            "name": "web-server",
            "machine_type": "e2-micro"
            // ... 所有屬性
          }
        }
      ]
    }
  ]
}

為什麼重要:

  • Terraform 靠 State File 知道「GCP 上的哪些資源是我管的」
  • 比對 State File 和 .tf 設定,計算出需要建立/修改/刪除什麼
  • 如果 State File 丟失,Terraform 就「失憶」了,會嘗試重新建立所有資源
查看流程與節點文字

箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。

flowchart TD
  C["HCL Configuration<br/>想要的狀態"] --> P["Terraform Plan"]
  S["State File<br/>資源位址與已知屬性"] --> P
  G["Google Cloud API<br/>目前真實狀態"] --> P
  P --> D{"三者是否一致?"}
  D -->|"一致"| N["No changes"]
  D -->|"不一致"| A["產生 Create/Update/Delete 計畫"]
  A --> R["人工與政策審查"]
  R --> X["Apply 後修改 GCP 資源"]
  X --> S
State 不是資源本身,而是 Terraform 對資源身分與屬性的記憶;Plan 必須同時參考設定、State 與 Provider 讀到的真實狀態。

⚠️ 絕對不要把 State File 放進 git! 它可能包含敏感資訊(密碼、憑證)。

單機自己用,這個檔放本地沒問題;但一旦進到團隊協作,就得把它搬到大家共用的遠端位置——第四章會講怎麼搬到 GCS。


三、在 GCP 上認證 Terraform

3.1 本地開發:Application Default Credentials

最簡單也最安全的本地開發認證方式:

# 設定 Application Default Credentials
gcloud auth application-default login

# 登入後,Terraform 會自動使用你的帳號身分
terraform plan
terraform apply
# Provider 不需要指定 credentials,ADC 會自動處理
provider "google" {
  project = var.project_id
  region  = var.region
}

3.2 CI/CD 環境:Service Account Impersonation

生產環境的 CI/CD(GitHub Actions、Cloud Build 等)推薦使用 Service Account Impersonation,不需要下載 JSON 金鑰:

provider "google" {
  project = var.project_id
  region  = var.region

  # Impersonate 一個具有所需權限的 Service Account
  impersonate_service_account = "terraform-runner@my-project.iam.gserviceaccount.com"
}
# 設定:讓 CI/CD 的 SA 有權限 impersonate terraform-runner SA
gcloud iam service-accounts add-iam-policy-binding \
    terraform-runner@my-project.iam.gserviceaccount.com \
    --member="serviceAccount:ci-cd-sa@my-project.iam.gserviceaccount.com" \
    --role="roles/iam.serviceAccountTokenCreator"

四、GCS 遠端狀態設定(Team 協作必備)

本地 State File 自己一個人用還行,但只要進到團隊協作,State File 就得放到一個大家共用的遠端位置。

4.1 為什麼需要遠端狀態?

問題本地 StateGCS Remote State
兩人同時執行 apply狀態衝突,資源損毀自動加鎖,防止並發
換電腦後找不到 State狀態丟失永久存在 GCS
需要 Code Review 狀態無法審查版本歷史可追蹤

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。

Terraform 團隊協作流程:工程師透過 Pull Request 與短效 CI 身分執行 plan,取得 GCS 遠端 State 鎖後才能 apply,其他寫入者必須等待

團隊要共用的是受保護的遠端 State,而不是把 state 檔提交進 Git。執行者先取得鎖,再讀取 State、比對真實資源並通過 Review;同時間的另一個 apply 必須等待,完成後才更新 State 並釋放鎖。

4.2 設定 GCS 作為 Backend

# Step 1: 建立用來存放 State 的 GCS Bucket(使用 gcloud storage,取代舊版 gsutil)
gcloud storage buckets create gs://my-terraform-state-bucket --location=asia-east1
gcloud storage buckets update gs://my-terraform-state-bucket --versioning  # 啟用版本控制(重要!)
# terraform.tf(或 main.tf 開頭)

terraform {
  backend "gcs" {
    bucket = "my-terraform-state-bucket"  # 你剛建立的 Bucket
    prefix = "terraform/state"             # State File 的路徑前綴
  }

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 8.0"
    }
  }
}
# Step 2: 初始化(會把本地 State 遷移到 GCS)
terraform init

# 看到這個訊息代表成功:
# Initializing the backend...
# Successfully configured the backend "gcs"!

GCS Backend 的優勢:

  • 自動 State 鎖定:當有人在執行 apply,GCS 會自動加鎖,其他人無法同時操作
  • 無需 DynamoDB:不像舊做法的 AWS S3 Backend 要額外建 DynamoDB 鎖定表(S3 Backend 現在是用 use_lockfile 參數開啟鎖定,預設關閉;DynamoDB 鎖定已棄用),GCS 內建鎖定功能
  • 版本歷史:啟用 GCS 版本控制後,每個 State 變更都有歷史記錄

五、完整實戰範例:VPC + VM + Cloud Storage

下面是一個完整的 Terraform 配置範例,幫你建起一個基本的 GCP 環境:

project/
├── main.tf        # 主要資源定義
├── variables.tf   # 變數定義
├── outputs.tf     # 輸出定義
├── terraform.tf   # 版本和 Backend 設定
└── terraform.tfvars  # 實際值(不放進 git)

terraform.tf

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

  required_providers {
    google = {
      source  = "hashicorp/google"
      version = "~> 8.0"
    }
  }
}

provider "google" {
  project = var.project_id
  region  = var.region
}

variables.tf

variable "project_id" {
  description = "GCP Project ID"
  type        = string
}

variable "region" {
  description = "GCP Region"
  type        = string
  default     = "asia-east1"
}

variable "environment" {
  description = "Environment (dev/staging/prod)"
  type        = string
  default     = "dev"
}

main.tf

# ===== Networking =====

resource "google_compute_network" "vpc" {
  name                    = "${var.environment}-vpc"
  auto_create_subnetworks = false
}

resource "google_compute_subnetwork" "subnet" {
  name          = "${var.environment}-subnet-${var.region}"
  ip_cidr_range = "10.1.0.0/24"
  region        = var.region
  network       = google_compute_network.vpc.id
}

# 防火牆:允許 IAP SSH
resource "google_compute_firewall" "allow_iap_ssh" {
  name    = "${var.environment}-allow-iap-ssh"
  network = google_compute_network.vpc.name

  allow {
    protocol = "tcp"
    ports    = ["22"]
  }

  source_ranges = ["35.235.240.0/20"]  # IAP IP 範圍
  target_tags   = ["iap-ssh"]
}

# ===== Compute =====

resource "google_service_account" "vm_sa" {
  account_id   = "${var.environment}-vm-sa"
  display_name = "${var.environment} VM Service Account"
}

resource "google_compute_instance" "web" {
  name         = "${var.environment}-web-server"
  machine_type = var.environment == "prod" ? "e2-small" : "e2-micro"
  zone         = "${var.region}-a"

  boot_disk {
    initialize_params {
      image = "debian-cloud/debian-12"
      size  = 20  # GB
    }
  }

  network_interface {
    subnetwork = google_compute_subnetwork.subnet.id
    # 沒有 access_config = 無外部 IP(搭配 IAP 使用)
  }

  service_account {
    email  = google_service_account.vm_sa.email
    scopes = ["https://www.googleapis.com/auth/cloud-platform"]
  }

  tags = ["iap-ssh"]

  metadata = {
    enable-oslogin = "TRUE"
  }
}

# ===== Storage =====

resource "google_storage_bucket" "app_data" {
  name          = "${var.project_id}-${var.environment}-app-data"
  location      = "ASIA-EAST1"
  force_destroy = var.environment != "prod"  # prod 環境不允許意外刪除

  versioning {
    enabled = true
  }

  lifecycle_rule {
    condition {
      age = 30  # 30 天後移到 Coldline
    }
    action {
      type          = "SetStorageClass"
      storage_class = "COLDLINE"
    }
  }
}

# 授予 VM SA 讀取 Bucket 的權限
resource "google_storage_bucket_iam_member" "vm_reader" {
  bucket = google_storage_bucket.app_data.name
  role   = "roles/storage.objectViewer"
  member = "serviceAccount:${google_service_account.vm_sa.email}"
}

outputs.tf

output "vm_instance_name" {
  description = "VM instance name"
  value       = google_compute_instance.web.name
}

output "vpc_name" {
  description = "VPC name"
  value       = google_compute_network.vpc.name
}

output "bucket_name" {
  description = "Cloud Storage bucket name"
  value       = google_storage_bucket.app_data.name
}

terraform.tfvars(不放進 git)

project_id  = "my-gcp-project-123456"
region      = "asia-east1"
environment = "dev"

執行 Terraform

# 初始化(下載 provider、設定 backend)
terraform init

# 格式化程式碼(建議每次 commit 前執行)
terraform fmt

# 驗證語法
terraform validate

# 預覽即將發生的變更
terraform plan

# 套用變更(建立資源)
terraform apply

# 查看 state 中的所有資源
terraform state list

# 銷毀所有資源(謹慎!)
terraform destroy

六、Terraform Modules:可重用的程式碼單元

Module 就是 Terraform 裡的「函數」,把常用的資源組合打包起來,之後就能重複拿來用:

modules/
└── network/
    ├── main.tf        # VPC + Subnet + Firewall 的定義
    ├── variables.tf   # 模組接受的參數
    └── outputs.tf     # 模組提供的輸出
# 使用模組(在根目錄的 main.tf 中)
module "network" {
  source = "./modules/network"

  project_id  = var.project_id
  region      = var.region
  environment = var.environment
  cidr_range  = "10.1.0.0/24"
}

# 使用模組的輸出
resource "google_compute_instance" "web" {
  # ...
  network_interface {
    subnetwork = module.network.subnet_id  # 引用模組的輸出
  }
}
查看流程與節點文字

箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。

flowchart TB
  E["Root Module<br/>環境設定"] -->|"project_id、region、CIDR"| N["Network Module"]
  N --> V["建立 VPC"]
  N --> S["建立 Subnet"]
  N --> F["建立 Firewall Rules"]
  S -->|"輸出 subnet_id"| O["Module Output"]
  O --> C["Compute Resource/<br/>Module"]
  E -->|"machine type、image"| C
  C --> VM["建立使用該 subnet 的 VM"]
Root Module 負責組裝;子模組透過 variables 接收差異,再以 outputs 暴露其他資源真正需要的識別值。

公開模組:Terraform Registry 上有 Google 官方維護的 GCP 模組,VPC、GKE、Cloud SQL 都有,直接拿來引用,開發會省事很多。


七、Terraform vs 其他 IaC 工具

工具現狀適用場景
Terraform✅ 業界標準(BSL 授權)多雲環境、大多數 GCP 場景
OpenTofu✅ 開源替代方案(MPL 2.0)需要真正開源授權的組織
Deployment Manager🔴 已於 2026/03/31 結束支援遷移至 Terraform 或 Infra Manager
Config Connector✅ 活躍維護Kubernetes-native GCP 管理
Infra Manager✅ 2023 年 8 月 GA基於 Terraform 的 GCP 託管服務

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。

Terraform vs OpenTofu

2023 年 8 月,HashiCorp 將 Terraform 的授權從 MPL 2.0 改為 Business Source License(BSL),限制了商業競爭者的使用。社群因此 fork 出 OpenTofu,由 Linux Foundation 管理,維持 MPL 2.0 授權。

對你的影響:

  • 個人學習和內部使用:兩者都可以,無任何限制
  • 企業內部部署:通常也不受 BSL 影響
  • 嵌入產品銷售:需要留意 BSL 授權條款,OpenTofu 是較安全的選擇

技術上:OpenTofu 和 Terraform 的 HCL 語法幾乎完全相容,要切換幾乎沒什麼成本。

Deployment Manager 注意事項

🔴 已停止支援:Cloud Deployment Manager 已於 2026 年 3 月 31 日結束支援,不再有官方支援與新功能,官方預計 2027 年 6 月 30 日之後關閉服務;新使用者自 2026 年 6 月 30 日起已無法啟用 API。既有資源仍會繼續運作。如果你還有遺留的 Deployment Manager 設定,盡快遷移。

Google 提供了 dm-convert 工具協助遷移到 Terraform,替代方案是 Infrastructure Manager(基於 Terraform 的 GCP 託管服務)。


八、Terraform 最佳實踐

✅ 必做

實踐說明
State 存 GCS永遠使用遠端 State,不要本地
版本鎖定Provider 版本用 ~> X.0 鎖定主版本
terraform fmt每次 commit 前格式化程式碼
terraform validate確認語法正確再 plan/apply
Commit 前 plan先 plan 確認變更符合預期
模組化複雜資源組合抽成 Module
變數化環境相關值用變數,不寫死
描述所有變數description 欄位一定要填

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。

❌ 禁止

禁止事項原因
把 .tfstate 放進 git可能包含密碼、API 金鑰
把 .tfvars 放進 git包含實際的專案 ID、密碼
硬寫 credentials安全風險,用 ADC 或 Impersonation
手動修改 GCP Console 後不更新 .tf造成 Drift,Terraform 下次 apply 可能覆蓋
直接修改 tfstate高風險操作,容易造成狀態損毀

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。


九、常見問題 FAQ

Q: terraform apply 後我在 Console 手動改了設定,下次 apply 會發生什麼?

Terraform 會偵測到 State Drift——實際的 GCP 狀態跟你 .tf 裡寫的定義對不上,這個落差就叫 drift(漂移)——並在下次 apply 時覆蓋你的手動修改。

解決方法:

  1. 把手動修改也更新到 .tf 文件中
  2. 或者執行 terraform apply -refresh-only,先檢視 GCP 實際狀態與 state 的差異再決定要不要同步(舊版 terraform refresh 會不經審查直接改 state,自 Terraform 0.15.4 起已不建議使用)
查看流程與節點文字

箭頭表示流程方向;方括號與引號內是節點名稱,可搭配下方圖解閱讀。

flowchart TD
  M["有人在 Console/gcloud<br/>手動修改受管資源"] --> P["下一次 terraform plan<br/>讀取真實狀態"]
  P --> D["顯示 Configuration、State<br/>與 Real Resource 的差異"]
  D --> I{"這次手動修改<br/>是否應成為正式設定?"}
  I -->|"否"| R["審查 Plan 後 Apply<br/>恢復 HCL 宣告的狀態"]
  I -->|"是"| H["先把變更寫回 HCL"]
  H --> F["以 refresh-only Plan/Apply<br/>審查 State 同步"]
  F --> P2["重新 Plan,確認無意外變更"]
  R --> P2
不要直接編輯 tfstate。先判斷手動變更是否有意,再讓 HCL 與經審查的 State 同步,最後重新 Plan 驗證。

Q: 如何管理多個環境(Dev/Staging/Prod)?

兩種主流做法:

方法 1:Terraform Workspaces

# 建立不同環境的 Workspace
terraform workspace new dev
terraform workspace new prod

# 切換到 prod
terraform workspace select prod
terraform apply -var-file=prod.tfvars

方法 2:獨立目錄(推薦)

environments/
├── dev/
│   ├── main.tf
│   └── terraform.tfvars
└── prod/
    ├── main.tf
    └── terraform.tfvars

每個環境有獨立的 State,降低誤操作風險。

Q: terraform destroy 很危險,如何防止誤刪生產資源?

在重要資源上加入保護機制:

resource "google_sql_database_instance" "main" {
  # ...
  deletion_protection = true  # 啟用後需先設為 false 才能 destroy
}

resource "google_storage_bucket" "critical" {
  # ...
  force_destroy = false  # Bucket 非空時無法刪除
}

十、ACE 考試重點

IaC 在 ACE 考綱的 Section 2.4(Planning and implementing resources using tooling)明列 Terraform、Config Connector 等工具:

類型 1:工具選擇

題目:你需要用程式碼管理 GCP 基礎設施,且同時也要管理 AWS 資源。最適合的工具是?

  • ❌ Cloud Deployment Manager(只支援 GCP)
  • ❌ Config Connector(需要 Kubernetes 環境)
  • ✅ Terraform(多雲支援)

類型 2:State 管理

題目:你的團隊有 5 位工程師都需要執行 Terraform。如何確保 State 的一致性?

  • ❌ 把 terraform.tfstate 放進 git 的私有 Repo
  • ✅ 使用 GCS 作為 Terraform Remote Backend(內建 State 鎖定)

📝 考場提點

如果題目提到多人維護同一套 Terraform 設定,重點是讓團隊共用 state,並避免同時寫入。GCS remote backend 提供鎖定機制,適合用在這類情境。

不要把 state 放進 git,即使是私人倉庫也一樣:它可能含有敏感資訊,git 也無法處理多人同時修改 state 的鎖定問題。如果選項另外要求 DynamoDB 鎖定表,要留意那是舊版 AWS S3 backend 的做法(DynamoDB 鎖定現已棄用);GCS backend 不需要這張表。

類型 3:認證方式

題目:在 Cloud Build 中執行 Terraform,最安全的認證方式是?

  • ❌ 下載 Service Account JSON 金鑰,存為 Secret
  • ✅ 使用 Service Account Impersonation(透過 Cloud Build 的 SA Impersonate terraform-runner SA)

📝 考場提點

選工具時先看需求:跨雲管理可考慮 Terraform;想在 Google Cloud 使用託管的 Terraform 工作流程,可看 Infra Manager;團隊已用 Kubernetes CRD 管理資源,則可評估 Config Connector。Deployment Manager 已於 2026/3/31 結束支援,不適合拿來規劃新部署。

自動化流程應盡量避免下載並長期保存 Service Account JSON 金鑰。Cloud Build 可依執行身分與權限需求評估 Service Account Impersonation;從外部 CI 系統連到 Google Cloud,則可評估 Workload Identity Federation。選哪一種方式,還要看流程在哪裡執行、能取得什麼身分,以及需要哪些最小權限。

類型 4:核心指令

題目:執行 terraform plan 的目的是?

  • ✅ 預覽 Terraform 即將建立/修改/刪除的資源,不實際執行任何操作

十一、總結

Terraform 四大核心:

概念說明
Provider定義與 GCP 的連線方式,鎖定 ~> 8.0
Resource你要建立的 GCP 資源(VM、VPC、Bucket)
StateTerraform 的「記憶」,存放在 GCS
Module可重用的資源組合,減少重複程式碼

表格超出欄寬時,可左右捲動;鍵盤可聚焦表格後用左右方向鍵查看。

核心工作流程:

terraform init     # 初始化
terraform fmt      # 格式化
terraform validate # 驗證
terraform plan     # 預覽
terraform apply    # 套用

最重要的安全原則:

  • State File 存 GCS(加上 versioning),不放 git
  • 使用 ADC 或 Impersonation,不用 JSON 金鑰
  • 生產資源啟用 deletion_protection = true

系列文章連結


延伸閱讀


🎓 本文是「GCP 精通之路」系列的 ACE-207 篇(進階篇),掌握 Terraform on GCP 後,建議繼續學習企業上雲遷移策略。

下一課 GCP-107:Cloud Storage 入門,接著看物件位置、儲存類別與存取權限。

ACE 服務實戰 — 第 2 篇/共 11 篇 查看系列全覽 →

讀完後,留一個學習紀錄

試著用自己的話說出一個重點,以及你會如何運用。實作文章請先核對結果與清理資源,再標記為讀完。

文章進度以你確認讀完的標記為準,可隨時取消。舊版造訪紀錄保留,但不計入讀完;這份自評不代表已掌握內容。

留言討論

文章目錄與系列

徽章解鎖!