10.2 治理與擴展:IaC、多環境與團隊協作#
本節目標#
個人專案可以「在手動 dashboard 點一點」過日子,但只要專案要活超過一年、或團隊超過一個人,手動設定就會變成不可理解的黑盒。本節引進三個治理工具:基礎設施即程式碼(IaC) 把設定變成可版本控制的程式碼、多環境(dev/staging/prod) 把風險與實驗隔離、Cloudflare Access 把管理介面鎖在身分驗證之後。
IaC:設定即程式碼#
基礎設施即程式碼(Infrastructure as Code)的核心主張是一條公式:
你宣告「我想要一條 DNS 記錄、一條 WAF 規則、一個 Worker」,工具負責計算從現在狀態到目標狀態的差異(diff)並執行。這把 dashboard 的黑盒操作轉成三個工程屬性:
| 屬性 | 意義 |
|---|---|
| 版本控制 | 每一次設定變更都有 git commit 與作者 |
| 可重現 | 新環境或新公司 = 重新 apply 同一組檔案 |
| 可審查 | 設定變更走 PR review,就像程式碼 |
反面教材是「dashboard 治理」:三年後沒有人記得那條看似無用的 WAF 規則是誰為何建的;離職工程師把 production zone 的記錄刪掉,只是因為「看起來沒在用」。
Terraform 與 Cloudflare Provider#
Terraform 是業界最主流的 IaC 工具,Cloudflare 官方維護 provider(cloudflare/cloudflare)。一個典型的最小化設定:
# main.tf
terraform {
required_providers {
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 5.0"
}
}
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
# DNS 記錄:宣告想要的狀態
resource "cloudflare_dns_record" "www" {
zone_id = var.zone_id
name = "www.example.com"
type = "CNAME"
content = "example.pages.dev"
proxied = true
}
# 安全標頭改寫規則
resource "cloudflare_ruleset" "security_headers" {
zone_id = var.zone_id
name = "security headers"
kind = "zone"
phase = "http_response_headers_transform"
rules {
action = "rewrite"
action_parameters {
headers {
name = "Strict-Transport-Security"
operation = "set"
value = "max-age=31536000; includeSubDomains"
}
}
expression = "true"
}
}
工作流程是三個動詞:
terraform init # 安裝 provider、初始化 state
terraform plan # 顯示「將執行的差異」——永遠先看這個
terraform apply # 經確認後執行
State 是 Terraform 記住「現在真實世界長什麼樣」的資料結構。實務鐵律:
1. state 是機密(含資源 ID),放遠端 backend(如 R2 一個指定前綴的 bucket),
不要只留在本機。
2. state 一旦漂移(人工改了 dashboard),plan 就會失準——先再 import 回來。
3. 永遠先 plan 後 apply;plan 輸出直接貼進 PR 作審查依據。
覆蓋範圍與限制#
Cloudflare provider 幾乎涵蓋 zone、DNS、WAF、Workers、R2、D1、Access;但 Pages 的 deployments 通常仍走 wrangler/CI(IaC 管「配置」,CI 管「建置產物」),兩者分工。
多環境:dev / staging / prod#
多環境的意義#
程式碼變更是可逆的(git revert),資料與設定變更不可逆:prod 的 D1 少一行 schema migration、一走查 index 就回不去。多環境的用意是把「危險的自由」限制在非 prod 環境:
dev → `*.dev.example.com` 本地 wrangler dev +workers,隨手改
staging → `staging.example.com` 與 prod 同配置、測試資料、PR 部署自動進
prod → `example.com` 只有 main 分支 merge 後可手動/自動部署
用 wrangler 的 environments#
wrangler 內建環境概念:同一個 wrangler.toml 裡對同一個 Worker 宣告多個部署目標。
name = "my-api"
main = "src/index.ts"
[env.staging]
name = "my-api-staging"
route = { pattern = "staging.example.com/*", zone_name = "example.com" }
d1_databases = [{ binding = "DB", database_name = "my-db-staging", database_id = "..." }]
[env.production]
name = "my-api"
route = { pattern = "api.example.com/*", zone_name = "example.com" }
d1_databases = [{ binding = "DB", database_name = "my-db", database_id = "..." }]
npx wrangler deploy --env staging
npx wrangler deploy --env production
注意每個環境都有自己的 D1 資料庫——多環境不只是「多個 URL」,而是整組資源隔離。連 staging 的測試資料永遠污染不到 prod。
分支策略#
一條簡單就夠用的規則(GitHub Flow 變體):
feature branch → PR → 自動部署到 staging(preview)→ review → merge to main → 自動部 deploy prod
Cloudflare Pages 原生支援 Preview deployments(每個 PR 一個 *.pages.dev 預覽網址),把 staging 的性質「策略內建」在 PR 流程中;Workers 則可用 versions upload 得到一次性的 preview URL 讓人肉眼驗收。
基律理論:CI 負責「易變的部署」,IaC 負責「持久的設定」。建置產物(每天在變)走 pipeline,環境組態(數月不變)走 Terraform——這就是治理的分界線。
Cloudflare Access:鎖住 dashboard 與內部工具#
DevOps 最常忽視的攻擊面是管理介面本身:Cloudflare dashboard 若只靠一組帳號密碼,就只是一道薄薄的門檻。Cloudflare Access(Zero Trust 產品線)用反向代理 + 身分識別把 dashboard、外部管理控制台、甚至內部 preview URL 全部鎖起來:
使用者 → 經 Access 代理的 URL → IdP 驗證(Google/GitHub/OKTA…)→ 檢查 policy → 才准內容
設定策略的一句話版本:dashboard 存取必須綁定公司網域或 MFA 群組——就算有人拿到密碼也進不來。內部工具(如長期存在的 admin 頁)建議也一律套上 Access——把「內網」的隱性信任,轉為「邊緣上的零信任顯式驗證」。
Drift 檢測:地球不會照你的 plan 走#
IaC 完成的第一週,現實就會開始背離你的 state——有人手動 dashboard 加了一條記錄、另一個團隊用 CLI 建了 Worker。這叫 configuration drift。治理的最後一塊:偵測並修正漂移。
三個層次:
| 層次 | 做法 |
|---|---|
| 偵測 | 每日 CI 跑 terraform plan -detailed-exitcode;exit 2 = 有差異 |
| 告警 | 差異出現即 open 一個 issue 並 Slack 通知,見 10.1 的告警法則 |
| 治本 | 收緊 dashboard 權限(Access + 最小權限 API Token),讓「繞過 IaC 的改動」變成例外而非日常 |
# .github/workflows/drift.yml 的核心步驟
- run: terraform plan -detailed-exitcode -no-color
id: plan
# exit code 2:有未計畫的變更 → 開 issue
更深一層的理論:單一真相來源(Single Source of Truth)。當同一件事可以有兩個真相(dashboard vs Terraform),提供出來的寬鬆性必被用掉;治理就是讓「唯一的改動渠道」成本最低、其他渠道最麻煩。
小結與練習#
回顧#
- IaC 把 dashboard 黑盒轉成可版本控制、可審查、可重現的程式碼;Terraform + Cloudflare provider 是標準武器。
- plan → apply 的工作流,配合遠端 state 與 plan 貼進 PR 是兩條鐵律。
- 多環境(wrangler
env.*)的本質是整組資源隔離:連資料庫都分開。 - 分支策略:feature PR → staging preview → merge main → prod。
- Access 把管理面鎖在身分驗證之後;Drift 檢測讓「手動改動」變成會被抓到的例外。
- 治理的本體是「單一真相來源」:讓正確的事變成最容易的事。
練習#
- 為你目前專案挑 5 項在 dashboard 建的設定,用 Terraform import 進 state,然後
terraform plan應顯示無差異。 - 寫含
staging與production兩個 environment 的wrangler.toml,且各自的 D1 資料庫分開,驗證 staging 寫壞的資料不會出現在 prod。 - 設定一條 Access policy:只有你的 Gmail 網域 + MFA 才能進
staging.example.com。 - 故意在 dashboard 手動改一條 DNS 記錄,執行
terraform plan -detailed-exitcode,觀察 drift 如何被抓出,然後用 import 或覆寫修正。