iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
IT Operation

寫完微服務然後呢?走向平台工程的黃金路徑系列 第 6

Day 06 - GitOps 怎麼用 Git 管理部署狀態

  • 分享至 

  • xImage
  •  

前言

前面 Day 02 到 Day 05 我們先簡單地介紹了 Kubernetes 想解決的幾個基本問題與其作法,如 controller 會以控制迴路(Control Loop)持續讓實際狀態靠近宣告的 specDeploymentServiceIngress 分別負責工作負載、服務發現與 HTTP 路由;Kustomize 讓共用設定和環境差異不必混在同一份 YAML;CRD 則讓團隊能用 Microservice 這類自定義資源表達服務意圖。

不過,這些資源回答的是「叢集應該維持什麼狀態」,還沒有回答另一個交付問題:哪一份宣告才是某個環境現在應該採用的版本?

假設 Todo 團隊在週五晚上修正了建立待辦事項偶爾逾時的問題,並直接在 Production 執行 kubectl set image。修正當下生效了,但 Git 裡仍是舊 image。下次重建環境、處理事故,或有人想知道這個版本為什麼進入 Production 時,團隊該相信終端機歷史、CI log,還是叢集裡目前的資源?

GitOps 要處理的正是這件事:把環境的期望狀態放進可審查、可追溯且可重建的 Git History 內,並由叢集內的 controller 依照這份宣告維持狀態。

Git 裡有 YAML,還不算 GitOps

把 Kubernetes YAML 放進 Git 是好習慣,但它可能只是一份備份。GitOps 至少有三個條件:

  1. Git repository 保存的是環境的期望狀態,而且是部署流程實際採用的來源。
  2. 環境變更透過 commit 與 review 進入這份期望狀態。
  3. 叢集內的 controller 持續比對 Git 與叢集,並依同步政策處理差異。

這裡的「單一真實來源(Single Source of Truth)」是指環境應該變成什麼樣子,不是 Git 和 Kubernetes 在每一個瞬間都完全相同。Kubernetes 保存觀察到的狀態;GitOps controller 讀取 Git 的宣告、比對叢集現況,再執行 reconcile

Git:環境的期望狀態
Kubernetes:環境的觀察結果
GitOps controller:比對兩者,依政策處理差異

因此,GitOps 不是用 Git 取代 Kubernetes。Git 提供可審查的變更歷史,Kubernetes controller 仍負責讓資源狀態收斂;GitOps controller 則把兩者接起來。

Push-based 與 Pull-based 的差別:權限與信任邊界

傳統部署常採用 Push-based 流程:CI 完成 build 與測試後,使用 kubeconfig 或 cloud credential 直接呼叫 Kubernetes API。

Push-based 部署:CI Runner 持有 Kubernetes 憑證並直接呼叫 API Server

這種方式可以運作,但 CI runner 必須取得能改動目標叢集的憑證。若多條 pipeline 都能部署到 Production,就必須分別管理它們的權限、憑證輪替與稽核紀錄。

GitOps 常採用 Pull-based 流程。CI 仍負責驗證原始碼並產出 container image,但部署端不再由 CI 直接操作叢集。CI 將要部署的版本更新為 Git 的一筆 commit 或 Pull Request;常駐在叢集內的 controller 主動拉取已核准的設定,再用自己受限的 Kubernetes 權限同步資源。

Pull-based GitOps:CI 更新環境設定,GitOps controller 讀取期望狀態並在叢集內執行 reconcile

兩種模式的差異不只是誰先發出請求,而是信任邊界的位置:

  • CI 可以有推送 image 與更新設定 repository 的權限,不必持有 Production 的廣泛叢集憑證。
  • GitOps controller 只需要讀取已核准的設定 repository(通常只需 Git Read 權限),並依其責任範圍存取叢集內的 Kubernetes API。
  • 人員檢查部署時,先看設定變更的 commit 與 review,而不是到各台 runner 尋找曾經執行的指令。

這不代表 Pull-based 天生安全。controller 若擁有過大的 Kubernetes 權限,或設定 repository 沒有保護分支與 review,風險仍然存在。GitOps 是把權限拆開,讓團隊能分別治理,而不是自動消除權限問題。

原始碼與環境設定要能分開追蹤

先把兩種 commit 的責任分清楚。原始碼變更描述的是應用程式如何運作;環境設定變更描述的是哪個已知版本要在哪個環境執行,以及要維持哪些 Kubernetes 資源。

以 Todo 系統為例,可以把它們視為兩個邏輯範圍:

應用程式原始碼
  Account、Todo、BFF、Web 的程式碼、測試與 Dockerfile

環境設定
  各環境的 Kubernetes manifest、Kustomize overlay 與 GitOps controller 的部署宣告

這不強制要求一定要拆成兩個 repository。mono-repo 同樣可以做到,前提是 review、目錄邊界與權限能分辨兩種變更。重點是不要讓「程式碼已通過測試」自動等同於「這個 image 已被批准進入某個環境」。

假設 Staging 要從 0.1.0 升級到 0.1.1,設定變更應該明確指出 image reference 的變化。reviewer 能直接判斷升級範圍;若部署造成問題,也能回到這一筆 commit 還原或追查。部署版本不該由 CI 在執行當下隱含決定。

環境設定也不應保存明文 password、token 或 private URL。Git 可以保存 Secret 的名稱、External Secret 的 reference,或經團隊核准的加密資料;真正的敏感值仍應交給專門的 Secret 管理機制處理。

Drift 不是例外,而是要先決定的治理問題

GitOps 最容易看見的情況是設定漂移(drift)。例如 Git 宣告 todo-api 在 Production 應維持三個副本,但有人為了排查問題,手動把它調成五個,就會變成:

Git 的期望副本數:3
叢集觀察到的副本數:5
-> 發生 drift

controller 可以偵測這個差異,但如何處理不是技術自動能替團隊決定的事。自動回復能維持一致性,卻也可能覆蓋事故處理中的臨時操作。團隊至少要先定義:

  • 哪些環境允許 controller 自動修正 drift。
  • 緊急操作完成後,誰負責把必要變更寫回 Git。
  • 誰能暫停同步,以及暫停期間如何留下紀錄。

若手動調整是暫時的,最後仍應回到 Git,或明確撤銷它。否則下一次同步、重建或部署時,環境很可能在沒有人察覺的情況下回到舊宣告。

GitOps 帶來的是可重建的部署過程

把期望狀態留在 Git,最大的價值不只是「可以看 diff」。當環境需要重建,團隊不必依賴某位工程師記得最後執行過哪些命令;當部署異常,也能沿著設定的 commit、review 與 controller 事件追查。

不過,Git 本身不會讀取 commit,更不會將 YAML 套用到 Kubernetes。下一篇會使用 Argo CD 作為 GitOps controller,讓 Git 的環境宣告能持續同步到叢集,並區分資源已同步與服務真正健康這兩種狀態。


上一篇
Day 05 - CRD 是什麼:讓 Kubernetes 認識自訂資源
下一篇
Day 07 - 用 Argo CD 將 Git 的 YAML 同步到 Kubernetes
系列文
寫完微服務然後呢?走向平台工程的黃金路徑7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言