GitOps 入門指南:寫給 Kubernetes 使用者

談到 GitOps,許多團隊常把它簡化為「把 YAML 丟進 Git」或「在 CI Pipeline 裡面跑 kubectl apply」;更有團隊過早引入複雜的內部自研平台,結果交付流程沒變快,維運負擔反而翻倍。

要真正發揮 GitOps 的效益,關鍵在於貫徹 KISS(Keep It Simple, Stupid)、YAGNI(You Aren’t Gonna Need It) 與 Boring Technology(無聊技術) 原則,回歸交付流程的本質。


什麼是 GitOps

GitOps 一詞最早由 Weaveworks 於 2017 年提出,隨後在 CNCF OpenGitOps 工作小組中確立為四項核心原則。

簡單說,GitOps 要求團隊以宣告式描述系統的期望狀態,把 Git 當作唯一的事實來源。叢集內部常駐的代理人(如 Argo CD)會自動拉取最新設定,並透過控制迴圈持續比對、修正,確保線上狀態永遠與 Git 一致。

這套持續校正的迴圈機制,能為日常開發體驗帶來實質改善:


常見誤區:你以為的 GitOps 可能不是 GitOps

最常見的混淆,是將「基礎設施即程式碼(IaC)版本化」誤認為 GitOps。把 Dockerfile 與 Kubernetes YAML 存進版本庫只是第一步。

若線上出事時依然允許工程師直接使用 kubectl edit 手動修改,或在雲端控制台調整環境變數,系統的實際運作狀態就已經與 Git 脫鉤。只要 Git 不是狀態變更的唯一合法途徑,它就只是一份靜態的歷史備份。

另一種常見做法,是在 CI 腳本中執行 kubectl apply -f k8s/。這本質上仍是 Push 模式的外部自動化部署,CI 腳本執行完畢即離線,無法持續感知線上發生的手動變更,也未形成自動修正狀態漂移的迴圈。


架構機制:Push 模式痛點與 Pull 模式的防禦力

要理解 GitOps 的工程價值,必須深入對比傳統 CI 推播模式(Push-based)與代理人拉取模式(Pull-based)的底層架構差異。

Push 模式在安全與維運上的缺陷

在 Push 模式中,CI 工具扮演主動發起者。當程式碼合併後,CI 伺服器打包映像檔,最後讀取儲存在 CI 變數中的 kubeconfig,直接呼叫遠端 Kubernetes API Server。

這種架構存在難以規避的安全與維運缺陷:

  1. 憑證外洩風險極高:CI 系統必須握有生產叢集的高權限憑證。一旦第三方 Action 或 Runner 出現漏洞,攻擊者便能竊取憑證並掌控生產叢集。
  2. 網路邊界穿透成本:企業 Kubernetes API Server 通常部署於封閉的 VPC 私有子網內。若要讓雲端 SaaS CI 進行 Push,就必須在防火牆打洞開通對外存取,或維護昂貴的私有 Runner。
  3. 無法感知狀態漂移:CI 只是觸發型任務,執行完指令後任務隨即結束。假若維運人員隨後手動修改了線上環境,CI 毫無察覺,直到下一次發布引發意外覆蓋或衝突。

Pull 模式的架構優勢與安全防線

Pull 模式在 Kubernetes 叢集內部常駐一個具備控制迴圈的 Operator(如 Argo CD 或 Flux),定期比對 Git 與現場狀態。

這種模式帶來了顯著的架構改進:


主流工具評析:Argo CD 與 Flux v2 直球對決

在 CNCF 的 GitOps 生態系中,Argo CD 與 Flux(Flux v2) 是最受矚目的兩大 Graduated 畢業級專案。兩者在架構哲學上有鮮明的取向差異。

架構哲學的對比

Argo CD 走的是視覺化控制台與協作中心路線。它具備直觀的 Web 介面與即時資源關係樹,原生整合各類 SSO 單點登入,並能直接在介面比對 Diff 與檢視 Log,大幅降低跨職能團隊的溝通門檻。

Flux v2 則全面擁抱 Kubernetes 原生 API 與 Unix 哲學。它沒有單一龐大的控制台,而是拆分為一組專注的微控制器(Source、Kustomize、Helm 等),記憶體佔用極低,適合邊緣運算或偏好純 CLI 工作流的資深團隊。

特性對比與務實選型

評比面向Argo CDFlux v2務實評析
視覺化 Web 控制台完整強大,支援即時 Diff 與 Log無原生 UI,依賴社群第三方工具Argo CD 顯著降低值班與跨職能溝通成本
架構與 CRD 設計自訂 Application 與 AppProject 模型原生貼合 K8s API,高度模組化Flux v2 輕量彈性:微控制器架構便於客製裁減
上手門檻平緩直觀,所見即所得中等,需熟悉多個 Controller 與 CLIArgo CD 較易推廣,業務工程師可自主檢視同步狀態
記憶體資源開銷中等(約 500MB 至 1.5GB)極低(約 100MB 至 300MB)在一般雲端叢集中,此開銷差距通常可忽略
多租戶與 RBAC原生整合 SSO,支援細緻 UI/API 權限依賴 K8s 原生 RBAC 與 ServiceAccountArgo CD 更適合中大型團隊與複雜權限劃分

依據 Boring Technology 原則,推薦 90% 的常規研發團隊優先選擇 Argo CD。視覺化介面能讓開發、測試與維運在同一個畫面上溝通,省下的協作成本遠高於微小的資源開銷。僅在資源極端受限的單節點邊緣環境,或全體成員皆具備深度 Kubernetes 經驗的情境下,才優先採用 Flux v2。


組態架構與環境劃分:Kustomize 的單一主幹實務

許多團隊在導入 GitOps 時,最嚴重的挫敗往往不是出在工具安裝,而是出在儲存庫結構劃分與分支策略錯誤。

核心原則:App Repo 與 Config Repo 徹底分離

將應用程式原始碼與 Kubernetes 部署組態拆分至獨立儲存庫,是避免流程踩雷的第一道防線:

別用 Git 分支區分環境

早年許多團隊習慣維護 dev、staging、prod 三個長期分支,並讓 GitOps 工具分別監聽不同分支。這是一個極度危險的反模式。

各環境必定存在設定差異(例如副本數量或特定網域)。當團隊嘗試跨分支合併時,這些特異設定會引發頻繁的衝突。

若依賴分支隔離環境,一旦線上緊急熱修復遺漏了跨分支 cherry-pick,各分支的設定基準便會逐漸分歧,最終失去一致性。

最佳做法:單一主幹配合 Kustomize 目錄隔離

務實的解法是:組態庫僅保留單一主幹 main 分支,利用 Kustomize 的 base/ 與 overlays/ 結構,在實體目錄上劃分環境。

Kustomize 的優勢在於遵循 KISS 原則,沒有複雜的模板語法,純粹透過補丁覆蓋特定欄位,且 kubectl 原生支援,無須架設額外的套件儲存庫。

標準目錄結構如下所示:

 k8s-config-repo/
 +-- apps/
   +-- payment-service/
     +-- base/
     |   +-- deployment.yaml     # 通用基礎定義
     |   +-- service.yaml        # 通用 Service 定義
     |   +-- kustomization.yaml  # 宣告基礎資源
     +-- overlays/
       +-- dev/
       |   +-- kustomization.yaml  # 覆蓋副本數與標籤
       +-- staging/
       |   +-- kustomization.yaml  # 指定測試設定
       +-- prod/
           +-- kustomization.yaml  # 鎖定正式標籤與資源限額
           +-- patches/
               +-- replicas.yaml   # 覆蓋副本數為生產規格

當 CI 完成映像檔建構後,可在工作流中透過 kustomize edit set image 更新對應環境目錄下的標籤。

為兼顧自動化與安全審查,實務上通常為 CI 配發受限的 GitHub App 或 Deploy Key,自動開立變更 PR 或在通過預檢後合併至 main 分支,叢集代理人隨後便會偵測並同步新版本。

機密資訊(密碼、金鑰、憑證)則絕不能以明文進入 Git——Kubernetes 原生 Secret 只是 Base64 編碼,並非加密。

實務上建議將機密存放在雲端託管服務(如 AWS Secrets Manager、HashiCorp Vault),再透過 External Secrets Operator(ESO) 同步至叢集,Git 裡只留路徑參照,不留敏感數值。


避開陷阱:五大常見反模式

在實踐 GitOps 的過程中,許多團隊容易陷入看似美好但實則致命的陷阱。

  1. 緊急破窗後未及時回補:線上故障時工程師手動修改資源,卻因 Auto-sync 覆蓋而引發循環故障;或關閉 Auto-sync 後遺忘重啟。正解:建立緊急破窗 SOP,手動介入後必須在 30 分鐘內於 Git 補上對應 PR 並合併。
  2. 頻繁將動態資料寫入 Git:將 HPA 計算的副本數寫回 Git,引發無窮迴圈。正解:Git 僅記期望狀態。若用 HPA 應自清單移除 replicas,或在 Argo CD 設定 ignoreDifferences 配合 RespectIgnoreDifferences=true。
  3. 建構過於複雜的相依鏈條:在單一應用中同時部署 CRD、基礎設施元件與商業應用,導致載入順序混亂。正解:基礎設施與商業負載分層治理,保持相依關係簡單線性。
  4. 過早引入全自動金絲雀與回退:在業務規模尚小、流量不足時強推複雜的漸進式發布工具,常因微小波動導致發布卡死。正解:貫徹 YAGNI 原則,善用 Kubernetes 原生 RollingUpdate 搭配完善的就緒探針(readinessProbe),足以解決絕大多數業務需求。
  5. 跟風平台工程:強行引入複雜的自製介面或內部開發者平台。正解:Git 本身就是最佳介面,善用成熟的 Pull Request 審查機制即可獲得極高可靠度。

結語:讓生產發布變得無聊且可靠

持續交付的核心追求,是讓生產發布變得足夠平凡且可預期。變更不再依賴工程師在半夜手敲指令,而是化為常規上班時間內的一張 PR,經程式碼審查後由叢集代理人平穩完成狀態同步。

實踐 GitOps 不需要一開始就鋪設全套平台工程。先從一個無狀態服務著手,把組態儲存庫獨立出來、理清 Kustomize 環境目錄,讓交付流程在透明且可逆的軌道上運轉,便已經達成了八成的核心價值。回歸常識,堅守 KISS、YAGNI 與 Boring Technology,系統將比任何過度設計的架構都更加穩固長青。