把声明式管理延伸到集群之外:用 GitOps 管理 Cloudflare 资源的实录

Image

原始來源與檔名:2026-07-28T095951+0800-把声明式管理延伸到集群之外用 GitOps 管理 Cloudflare 资源的实录.md


SOURCE | 資訊源評估

NAPKIN | 餐巾紙

餐巾紙公式

Infrastructure as Code = Terraform (快照/低頻) + Crossplane CRs (常駐調和/高頻) + Helm Hooks (過程性任務) 不要迷信單一工具,系統狀態的邊界劃分應基於「變更頻率」與「失誤波及面」。

一句話

作者透過整合 Terraform 與 Crossplane,將 Cloudflare 邊緣網路的設定(DNS、Worker、Tunnel)全數納入 GitOps 體系,徹底消滅了 Web 控制台的手動操作與不可追溯的狀態迷霧。

餐巾紙草圖

┌───────────────────────
│ 流量路徑
│ 邊緣(Worker) ──[不中]──> Tunnel ──> K8s (cloudflared) ──> Ingress
├───────────────────────
│ 管理路徑 (Git 倉庫分層)
│ ├── Terraform (快照): Zone, Tunnel, D1 (變更少/影響大)
│ ├── Crossplane (常駐控制器): DNS, Worker 腳本 (高頻/防手賤)
│ ├── Helm Hook Job (過程): SQL 遷移 (必須順序執行)
│ └── Burrito Operator (可見性): 只跑 Plan 告警漂移,不自動 Apply
└──

ROUND 1: SKELETON | 骨架掃描

章節骨架(條列)

ROUND 2: DISSECTION | 血肉解剖

論證鏈

┌── 痛點:狀態一旦橫跨兩套管理體系(Git vs 控制台),故障排查成本極高,半年後無人記得某條 DNS 紀錄為何存在。

├── 原則:將「調和循環 (reconcile loop)」引入邊緣網路。宣告與現實一旦偏離,控制器自動拉回。

├── 設計:基於資源特性解耦。不常動的(Zone/Tunnel)交給 Terraform (快照);常改且易遭人手動破壞的(DNS/Worker)交給 Crossplane (控制器);有順序依賴的(SQL 遷移)交給 Helm Hook (Job)。

└── 成果:手動操作降為 1 次(改 Nameserver),實現基礎設施代碼化、無入站暴露、零停機。

3 個關鍵證據

  1. 棄用 Wrangler 的原因:Wrangler 是一種命令式工具,deploy 成功那一瞬間的狀態,在 git 裡沒有對應物,缺乏控制器不斷對齊現實的「調和循環」。
  2. HCL 字符地雷 (Bug 解析):Crossplane 的 upjet 架構底層仍是 Terraform。當 Worker 的 JS 壓縮代碼中出現 ${ 時,會觸發 HCL 模板解析崩潰。這證明了「將代碼字串硬塞入聲明式 CR」潛在的封裝滲透風險。
  3. DNS 零停機策略:先在 Cloudflare 建 Zone,以 CR 複製所有紀錄為 DNS only (不代理),最後才在註冊商切換 Nameserver。證明了基礎設施遷移的核心原則:「先備份/並行,最後切換,切換後不動」。

隱形假設與邊界

ROUND 3: SOUL | 靈魂提取

留白提問(2 題)

  1. 在大規模團隊中,如何防止開發人員為了圖方便,直接在 Cloudflare 控制台手動覆寫 Crossplane 的 CR 狀態,引發頻繁的「狀態拉鋸戰」?
  2. 將 Worker 的 JS 構建產物直接存入 K8s 的 Script CR 中,當腳本體積逼近 K8s etcd 的 1MB 限制時,這套部署管線是否會面臨崩潰?

跨域映射

這就像是把城市的外圍城牆(邊緣網路)與市中心(K8s 集群)交由同一套都市計畫委員會(Git 倉庫)管理。以前城牆是民兵(控制台)隨意修補,現在全部改為標準化藍圖,城牆只要被人敲掉一塊,建築機器人(控制器)就會立刻按圖紙補好。

DEEP READ | 精讀指引

STRUCTURE MAP | 全書結構圖

┌── 動機:消滅「集權 K8s」與「混沌邊緣 (控制台)」的狀態撕裂

├── 最終架構全景
│   ├── 流量:Cloudflare 邊緣 (Worker) → Tunnel → K8s Ingress
│   └── 管理:Git (SSOT) → Terraform/Crossplane → Cloudflare API

├── 技術選型與邊界劃分 (架構師決策)
│   ├── Terraform:建置 Zone/Tunnel (低頻、快照式)
│   ├── Crossplane CR:DNS/Worker 腳本 (高頻、常駐調和防手動破壞)
│   └── Helm Hook Job:SQL 資料庫遷移 (必須依序執行的過程性任務)

├── 實戰踩坑紀錄
│   ├── DNS 遷移:複製數據 → 關閉代理並行 → 切換 NS (零停機)
│   ├── 命名限制:K8s 名稱不容許底線與點號 (範本層處理)
│   ├── HCL 地雷:JS 的 `${` 導致 upjet 解析崩潰 (關閉變數壓縮解決)
│   └── 狀態漂移:不可妥協的「永久 Diff」必須根除

└── 系統觀收斂
    ├── 工具層疊:自動復原交給機器 (CR) + 影響範圍大的交給人確認 (TF 卡片)
    └── 核心哲學:狀態在哪裡,運維成本就在哪裡。

把声明式管理延伸到集群之外:用 GitOps 管理 Cloudflare 资源的实录 (Architectural Deep Dive)

前言/背景

當 Kubernetes 內部已實現高度的 GitOps (如一切依賴 Helm, ArgoCD),外部的雲端基礎設施(如 DNS、邊緣網路)卻往往仍依賴控制台點擊或命令列工具,這導致了「真相」的割裂。本文作者分享了如何耗費一週時間,透過整合 Terraform 與 Crossplane,將 Cloudflare 的所有資源納入單一 Git 倉庫進行聲明式管理,徹底消除運維黑洞。

章節詳細總結

動機與系統邊界設計 (架構哲學)

DNS 遷移與零入站集群

Image

踩坑實錄:HCL 崩潰與永久 Diff

閉合迴路的可見性 (Burrito Operator)

總結與結論

  1. 單一真相來源 (SSOT) 是運維的底線:系統狀態在哪裡,運維成本就在哪裡。把邊緣網路和集群內部的配置收束於同一個 Git 倉庫,能將災難恢復簡化為一次 Apply。
  2. 工具選型取決於「變更頻率」與「影響範圍」:Terraform 的快照特性適合低頻、高風險的底層資源;Crossplane 的常駐調和特性適合高頻、易遭人為破壞的配置。
  3. 基礎設施代碼化 (IaC) 的附帶價值是「強制文檔化」:當所有的 DNS 紀錄都必須以代碼提交時,每一次變更都必須寫下 Context 與註解,這徹底解決了「半年後沒人知道這條 TXT 紀錄為何存在」的組織記憶流失問題。
  4. 警惕框架封裝滲透 (Leaky Abstraction):Crossplane 透過 upjet 包裝 Terraform 所引發的 HCL 解析崩潰,提醒工程師在享受自動生成框架便利的同時,必須深諳其底層運作機制。