GCP帳號購買 GCP 伺服器自動化維運:使用 Terraform 快速建置與擴展 VM
前言:把伺服器維運從手工變成可複製的流程
多數團隊在 GCP 建 VM 的第一步是手動點選,接著用腳本安裝程式、開防火牆、調整磁碟與監控。當服務變多、環境擴張,手工做法會迅速失控:設定漂移、版本不一致、跨環境差異、回滾困難。把這些步驟收斂在 Terraform 中,以宣告式、可審查、可回溯的方式管理,能把維運變成可複製的工程能力,讓建置、擴展與異動都可預期且安全。
本文從設計原則出發,示範最小可用範本(Minimum Viable VM)、模組化、CI/CD、彈性擴展(MIG + Autoscaler)、監控告警與成本控管,最後給出上線前檢核清單,讓你能直接落地。
為什麼用 Terraform 管理 GCP VM
Terraform 能把基礎設施描述成程式碼:檔案可版本化、審查、重用,並透過 Plan 先看差異、再 Apply 套用變更。這套流程把風險移到開發階段,降低線上操作的不確定性,並讓團隊可藉由代碼審查建立一致與安全的規範。
在 GCP,VM 維運往往牽涉網路(VPC、子網、路由)、身份與權限(IAM、Service Account)、資料磁碟、開機映像、健康檢查與監控。把這些都寫進 Terraform,可同時解決跨環境一致性與自動化部署兩大難題。
設計原則與整體架構
落地 Terraform 的關鍵不是工具本身,而是設計方式。以下原則能讓代碼可長期維護:
分層與目錄結構
把「環境」與「功能」分層。範例結構:
infra/
modules/
network/
vm/
mig/
envs/
dev/
main.tf
terraform.tfvars
prod/
main.tf
terraform.tfvars
modules 由可重用的模組組成;envs 代表具體的部署場景(dev、staging、prod),只做參數化,避免在環境層寫太多邏輯。
變數、輸出與約束
為模組設計清楚的介面:必要變數加上型別與驗證、合理的預設值、輸出(outputs)回傳重要資訊(如 IP、SelfLink、Service Account)。在介面上做約束,比在使用時補救來得可靠。
狀態檔與鎖定
Terraform 狀態檔是事實來源。使用 GCS 作為遠端 state 並開啟鎖定,避免多人同時 Apply 導致競態。搭配版本控管與 PR 审核,形成「代碼審查 + 計畫差異 + 鎖定」的三重保護。
不可變基礎設施
盡量追求不可變:更新改用新的 Instance Template 或映像,讓 VM 用滾動更新替換,減少在機器上「手改」。這是降低漂移與不可解錯誤的核心策略。
GCP帳號購買 最小可用 VM 範本
先建立最小可用 VM:具備網路、基本防火牆、服務帳戶、啟動指令,並把狀態存到 GCS。以下示範單個環境 main.tf 筆記式範本:
terraform {
required_version = ">= 1.5.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
backend "gcs" {
bucket = "tf-state-prod"
prefix = "vm/base"
}
}
provider "google" {
project = var.project_id
region = var.region
zone = var.zone
}
variable "project_id" {
type = string
}
variable "region" {
type = string
default = "asia-east1"
}
variable "zone" {
type = string
default = "asia-east1-a"
}
resource "google_compute_network" "vpc" {
name = "app-vpc"
auto_create_subnetworks = false
}
resource "google_compute_subnetwork" "subnet" {
name = "app-subnet"
network = google_compute_network.vpc.id
ip_cidr_range = "10.10.0.0/24"
region = var.region
}
resource "google_service_account" "vm_sa" {
account_id = "vm-runtime-sa"
display_name = "VM Runtime SA"
}
resource "google_compute_firewall" "allow_ssh_http" {
name = "allow-ssh-http"
network = google_compute_network.vpc.name
allow {
protocol = "tcp"
ports = ["22", "80"]
}
source_ranges = ["0.0.0.0/0"]
}
resource "google_compute_instance" "vm" {
name = "app-vm-01"
machine_type = "e2-medium"
zone = var.zone
boot_disk {
initialize_params {
image = "projects/debian-cloud/global/images/family/debian-12"
size = 20
type = "pd-balanced"
}
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
access_config {}
}
service_account {
email = google_service_account.vm_sa.email
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
}
metadata_startup_script = <<EOT
#!/bin/bash
set -euo pipefail
apt-get update -y
apt-get install -y nginx
systemctl enable nginx
systemctl start nginx
EOT
}
output "vm_external_ip" {
value = google_compute_instance.vm.network_interface[0].access_config[0].nat_ip
}
這份最小範本確保 VM 可運作、有基本網路與權限、能啟動服務。下一步是把它抽象成模組,讓多環境重用且易於擴展。
GCP帳號購買 模組化擴展:可重用 VM 模組
把 VM 抽成 modules/vm,暴露必要參數與輸出,並避免把環境特定的值寫死在模組裡。模組的目標:清楚、穩定、可測試、可長期維護。
模組介面設計
module "web_vm" {
source = "../modules/vm"
name = "web"
machine_type = "e2-standard-2"
image_family = "debian-12"
disk_size_gb = 20
network_id = google_compute_network.vpc.id
subnetwork = google_compute_subnetwork.subnet.id
service_account_email = google_service_account.vm_sa.email
startup_script = file("./scripts/install_web.sh")
tags = ["web", "http"]
}
在模組內,提供合理預設與型別檢查;同時輸出如外部 IP、內部 IP、SelfLink 供其他資源引用。避免在模組內進行環境判斷(如 if env==prod),改由環境層提供變數差異。
環境差異的處理
dev 可用較小機型與開放更寬鬆的防火牆;prod 使用固定映像、較嚴格 IAM、二次確認的 Plan。把差異留在 envs/dev、envs/prod 的 tfvars,搭配同一個模組,讓一致的結構承載不同的策略。
自動化部署:把 Terraform 納入 CI/CD
把 Terraform 流程從本機移到 CI/CD,讓每次變更都留痕、可審查、可回滾。基本步驟:
Pipeline 範例
steps:
- run: terraform fmt -check
- run: terraform init -backend-config=bucket=tf-state-prod -backend-config=prefix=vm/base
- run: terraform validate
- run: terraform plan -out=tfplan
- run: terraform show -no-color tfplan > plan.txt
- hold: Manual approval for prod
- run: terraform apply tfplan
關鍵點:Plan/Apply 分離;prod 要有人為核准;將 plan 輸出存檔,便於審查與追溯。把敏感參數(如密鑰、密碼)從 CI 的秘密管理注入,避免寫死在代碼或 tfvars 中。
變更審核與漂移檢測
把 plan.txt 當成審核檔,若出現 destroy 或大規模 replace,必須二次確認。定期跑 terraform plan(只讀),抓出漂移:手工改防火牆或機型可能導致狀態不一致,提早發現就能避免線上故障。
彈性擴展:Managed Instance Group 與 Autoscaler
單台 VM 只是開始;要應付流量高峰與更新,就該轉成 Managed Instance Group(MIG)與自動擴縮。作法是用 Instance Template 定義 VM,MIG 管理多副本,Autoscaler 根據指標擴容。
核心資源範例
resource "google_compute_instance_template" "web_tpl" {
name_prefix = "web-tpl-"
machine_type = "e2-standard-2"
disk {
source_image = "projects/debian-cloud/global/images/family/debian-12"
auto_delete = true
boot = true
disk_type = "pd-balanced"
disk_size_gb = 20
}
network_interface {
subnetwork = google_compute_subnetwork.subnet.id
access_config {}
}
service_account {
email = google_service_account.vm_sa.email
scopes = ["https://www.googleapis.com/auth/cloud-platform"]
}
metadata_startup_script = file("./scripts/install_web.sh")
tags = ["web", "http"]
}
resource "google_compute_health_check" "web_hc" {
name = "web-hc"
http_health_check {
port = 80
request_path = "/"
}
}
resource "google_compute_region_instance_group_manager" "web_mig" {
name = "web-mig"
base_instance_name = "web"
region = var.region
version {
instance_template = google_compute_instance_template.web_tpl.self_link
}
target_size = 2
auto_healing_policies {
health_check = google_compute_health_check.web_hc.id
initial_delay_sec = 60
}
}
resource "google_compute_region_autoscaler" "web_as" {
name = "web-as"
region = var.region
target = google_compute_region_instance_group_manager.web_mig.id
autoscaling_policy {
min_replicas = 2
max_replicas = 10
cpu_utilization {
target = 0.6
}
cooldown_period = 60
}
}
這組資源讓你的服務可自動擴縮。更新時改用新的 Instance Template,MIG 滾動替換,不必手改線上機器。健康檢查確保只把健康節點納入負載。
無中斷部署策略
把版本引入 Instance Template 名稱或標籤,用 MIG 的 version 區塊做滾動更新。設定合理的最大不可用數量(max surge / max unavailable)與健康檢查延遲,讓更新過程對使用者透明。
網路、身份與映像:把風險前移
網路與 IAM 是最常見的風險源。建議策略:
IAM 最小權限
為 VM 創建專用 Service Account,賦予最小角色(如讀取 Storage、Pub/Sub Publisher 等)。把對整專案的 Owner 角色移除,改以工作流程授權。CI 執行 Terraform 的身分也應使用最小權限、並限制範圍。
秘密管理與映像硬化
敏感資訊用秘密管理服務保存與注入;在映像層做硬化:關閉不必要的服務、更新套件、設定檔案權限與 SSH 原則。最好以映像管線(Packer 或建置映像流程)產出可版本化的基礎映像,再由 Terraform 參照。
監控、日誌與告警:讓擴展有憑有據
GCP帳號購買 把監控與告警也寫進 Terraform:建立指標、告警策略與通知管道。至少監控 CPU、記憶體、磁碟 I/O、HTTP 成功率與延遲;告警門檻應分層:預警(可觀察)與致命(需介入)。
指標選擇與門檻區分
Autoscaler 常用 CPU 平均作為指標,但對 I/O 重的服務應改用負載或自訂指標。門檻設計要考慮冷啟成本與波動,避免抖動。搭配降噪策略(抑制、聚合),讓告警可行動而非吵雜。
成本控管:把擴展與預算綁在一起
擴展如果沒有預算約束,很容易超支。做法:為不同環境或服務設置配額與上限;選擇合適機型(e2、c3、t2a 等)與磁碟(pd-balanced、pd-ssd);善用承諾使用折扣與自動關機策略(非峰時段)。在 Terraform 中暴露上限(max_replicas),並以 Policy 驗證變更不會突破預算。
GCP帳號購買 常見陷阱與排障心法
幾個在 GCP + Terraform 維運上經常遇到的問題與處理心得:
狀態檔競態
多人同時 Apply 導致資源互相覆蓋。解法:遠端 state + 鎖定、在 CI 統一入口、禁止直接在本機對 prod Apply。
不一致的手工設定
有人在 Console 上改防火牆或 IAM,導致 plan 有大量漂移。解法:把所有資源都落進 Terraform,並定期跑只讀 plan 做漂移掃描。
啟動腳本失敗
metadata_startup_script 是常見故障點。解法:腳本前置 set -euo pipefail;把安裝日誌輸出到 /var/log;以映像管線把依賴前移,減少啟動時安裝。
滾動更新中斷
健康檢查門檻過嚴或延遲過短,導致新節點未準備好就被標示不健康。解法:調整 initial_delay、health check path 與超時,並檢查服務啟動時間。
Autoscaler 抖動
指標噪音造成頻繁擴縮,帶來成本與不穩定。解法:提高冷卻時間、採移動平均或以自訂指標控制,並限制最小增長單位。
演進路線圖:從單 VM 到自動化集群
實務上的演進步驟可分三段:
階段一:固定版位、最小可用
建立最小可用 VM 範本與模組;使用遠端 state;把網路與防火牆納入代碼;導入基本 CI(fmt、validate、plan)。
階段二:可擴展與可觀察
導入 MIG + Autoscaler;健康檢查、滾動更新;監控與告警策略;把敏感資訊改用秘密管理;開始做 Policy 驗證與成本門檻。
階段三:規模化與治理
把所有環境與專案統一規範;模組版本管理與發佈;PR 驗證與變更審核制度;自動漂移檢測與修復;持續優化映像與安全基線。
實用範本與檢核清單
最後給一份上線前檢核清單,確保基礎設施到位、可觀察、可回滾:
上線前檢核清單
- 代碼:所有資源均納入 Terraform;模組介面清楚,變數型別與驗證完整。
- 狀態:使用 GCS 遠端 state,鎖定有效;plan.txt 存檔並審查。
- 網路:VPC、子網、路由、DNS 與防火牆規則一致;無手工例外。
- 身份:VM 有專用 Service Account;CI 身分最小權限;角色與範圍明確。
- 映像:啟動腳本可重入、具日誌;基礎映像經硬化與版本化。
- MIG:健康檢查通過;滾動更新策略測試;Autoscaler 門檻合理且不抖動。
- 監控:CPU、延遲、錯誤率、磁碟 I/O 指標已建立;告警分層且通知管道有效。
- 成本:機型選型合理;設定最大副本數與配額;有預算監控與警示。
- 安全:敏感資訊不進代碼;SSH 政策與防火牆最小曝光;審計日誌保留。
- GCP帳號購買 流程:CI/CD 有手動核准門檻;回滾程序清楚;變更紀錄與標籤完善。
結語:把複雜事用簡單方法重複做好
把 GCP VM 的建置與維運寫成 Terraform,不只是在追趕自動化潮流,而是用工程方法處理複雜性:讓每次部署可預期、每次修改可審查、每次擴展有依據。先從最小可用開始,逐步模組化與導入 MIG + Autoscaler,再把監控、成本與安全納入治理。當流程與代碼成熟,你的基礎設施會像產品一樣進化,而不是一次性的配置。
團隊文化也會隨之改變:用 PR 討論變更、用指標衡量穩定、用回滾保證安全。最終,你會擁有一套可複製、可伸縮、可審查的維運系統,支撐快速交付與長期成長。

