前言
隨著 GitOps 在 Kubernetes 生態系中越來越普及,像是 ArgoCD、Flux 等工具已經幫助許多團隊解決了持續部署(CD)的痛點。不過「GitOps」這個詞聽起來簡單,實際落地的時候,光是 Git Repository 的架構規劃就有不少眉角。
今天這篇文章,我想聊聊在實務上常見的幾種 Git Repo 組織方式,以及搭配不同 K8s Manifest 管理工具時各自的優缺點。沒有所謂的標準答案,重點還是要依據團隊規模、流程成熟度來做取捨。
GitOps 的基本流程與挑戰
在透過 GitOps 將應用程式部署到 Kubernetes 時,典型的工作流程大致如下:

整個流程涵蓋了:
- 開發者撰寫應用程式原始碼
- 透過 CI 建置容器映像檔
- 將映像檔推送到 Container Registry
- 同步更新 K8s YAML 描述檔
- GitOps 工具(透過 Webhook 或 Polling)偵測到 YAML 變更
- 將變更套用到目標 Kubernetes 叢集
- Kubernetes 從 Registry 拉取最新版本的映像檔
看起來很直覺,但實際執行時經常會遇到以下幾個問題:
| 常見問題 | 說明 |
|---|---|
| K8s YAML 管理工具選擇 | 要用 Helm、Kustomize、Jsonnet 還是原生 YAML? |
| 原始碼與 K8s YAML 的歸屬 | 放同一個 Repo 還是分開管理? |
| 映像檔版本更新的責任歸屬 | 新版容器產生後,由誰來更新 K8s YAML 中的 image tag? |
K8s Manifest 管理工具比較
先來快速回顧一下常見的四種 K8s 資源描述管理方式。
原生 YAML
最直覺的方式,直接用 YAML 描述所有 Kubernetes 物件。
| 面向 | 說明 |
|---|---|
| 優點 | 入門門檻低、不需額外工具、可直接搭配 kubectl 使用 |
| 缺點 | 缺乏彈性、多環境維護成本高、沒有版本控制概念 |
| 適用場景 | 學習用途、小型專案、第三方工具的安裝範例 |
簡單來說,每個環境都要維護一組幾乎一模一樣的檔案,環境一多就會崩潰。
Helm
Helm 應該是目前最廣為人知的 K8s 應用定義工具了。透過 Helm Chart 搭配 Go Template,可以根據不同環境動態產生最終的 K8s 資源。
| 面向 | 說明 |
|---|---|
| 優點 | Go Template 動態產生資源、支援打包發布與版本控制、Dependency 機制可組合 Umbrella Chart、生態系豐富 |
| 缺點 | 學習曲線較陡、Template 語法偶爾讓人抓狂、需額外安裝 Helm CLI、可能需要維護 Helm Chart Server |
Helm 的運作模式是:團隊維護一份主要的 Chart,再針對不同部署環境準備對應的 values.yaml,動態產生符合各環境需求的 K8s 物件。
另外值得一提的是 Umbrella Chart 的概念——當你交付的不是單一應用而是一整套服務時,可以透過 Helm dependency 將多個 Chart 串在一起,使用者只需要準備一份 values.yaml 就能一次部署所有相依的 Chart。
Kustomize
跟 Helm 的模板化思路不同,Kustomize 提供了一種更簡潔的方式來客製化 K8s 資源。所有檔案都維持原生 K8s 格式,透過 overlay 和 patch 機制來做動態修改。
| 面向 | 說明 |
|---|---|
| 優點 | 基於原生 YAML 格式、不需學額外 Template 語法、已整合進 kubectl(kubectl apply -k) |
| 缺點 | 生態系不如 Helm 豐富、缺乏版本概念不利於分發、整體架構仍需花時間理解 |
基本用法是在 base 資料夾放共用的基礎物件,各環境資料夾則放客製化的內容,全部透過 kustomization.yaml 串接。
Jsonnet
Jsonnet 是一個基於 JSON 的程式語言,利用程式邏輯(if/else、迴圈、函式等)來產生 K8s 物件描述檔。
| 面向 | 說明 |
|---|---|
| 優點 | 支援程式邏輯運算、支援 Library 概念減少重複程式碼 |
| 缺點 | 需要學習新語言、文件和生態系相對較少 |
搭配 k8s-libsonnet 等函式庫,可以快速產生對應不同 K8s 版本的資源物件。整體流程就是撰寫 jsonnet 檔案 → 用 jsonnet 指令產生 YAML/JSON → 用 kubectl 套用到叢集。
工具選擇小結
這四種工具沒有絕對的好壞,ArgoCD 全部都支援。實務上更常見的是混合使用——畢竟很多開源專案是用 Helm 來發布,但團隊內部可能偏好 Kustomize 或 Jsonnet 來管理自己的應用,這些不同的方式可以共存。
Git Repository 架構策略
搞定了 Manifest 工具的選擇,接下來就是重頭戲:Source Code 和 K8s Manifest 到底要怎麼放?

方案一:程式碼與 YAML 放在同一個 Repo
也就是每個應用程式的 Git Repo 同時包含 Source Code、Dockerfile 和 K8s Manifest。
| 特性 | 說明 |
|---|---|
| 一站式管理 | 從開發到部署的所有資源都在同一處,方便交叉參照 |
| 同步修改 | 應用需要新增環境變數等變更時,可以連同部署 YAML 一起改 |
| CI/CD 整合 | Pipeline 可以一條龍處理,甚至用 KIND 測試 K8s 部署 |
| Helm 友善 | 可在 CI/CD 中打包並發布 Helm Chart |
| 共用困難 | 使用 Kustomize/Jsonnet 時,跨應用共用檔案比較麻煩 |
| 全局視角不足 | 維運人員要了解整體部署狀況,得逐個 Repo 去翻 |
這個模式還有一個常見的痛點:Image Tag 的更新時機。開發者開 PR 新增功能時,通常還不知道最終的 Container Image Tag 是什麼,所以無法同步更新 K8s YAML。常見的解法包括使用 latest tag、開第二個 PR 更新、或是建立 GitHub App 動態更新 PR 內容。
方案二:程式碼與 YAML 分開不同 Repo
這是目前比較主流的做法——職責分離。開發者專注在應用程式開發和容器化,另外用一個專門的 Git Repo 來處理所有 GitOps 的管理與部署。
| 特性 | 說明 |
|---|---|
| 全局可見 | 所有部署物件集中管理,快速掌握各環境部署差異 |
| 職責分離 | 開發人員和維運人員各司其職 |
| 共用友善 | Kustomize/Jsonnet 的共用概念更容易實現 |
| 環境區分 | 可透過 Branch 或 Folder 來區分不同環境的部署資源 |
| 專屬 CI/CD | 可以針對整體服務部署做驗證,而非只驗證單一應用 |
| 同步成本 | 應用的新版本若需要 YAML 變更,得另外到這個 Repo 處理 |
以 Kustomize 為例,常見的目錄結構如下:
├── base
│ ├── app-foo
│ │ ├── deployment.yaml
│ │ ├── kustomization.yaml
│ │ └── service.yaml
│ └── app-bar
│ ├── deployment.yaml
│ ├── kustomization.yaml
│ └── service.yaml
└── overlays
├── dev
│ ├── app-foo/
│ └── app-bar/
└── prod
├── app-foo/
└── app-bar/
另外,因為 Kustomize 目前也支援使用 Helm Chart,所以實務上也會看到 Kustomize + Helm 混合使用的目錄結構。
方案三:混合模式(搭配 Helm Chart Server)
既然 Helm Chart 可以打包並推送到 Chart Server,那就可以把前兩種方案的優點結合起來:
| 步驟 | 說明 |
|---|---|
| 應用 Repo | 專注維護 Helm Chart 的發布與設定 |
| CI/CD 打包 | 在 Pipeline 中打包 Helm Chart 並推送到 Chart Server |
| K8s YAML Repo | 從 Chart Server 取得打包好的 Chart,用不同的 values 部署到各環境 |
| 職責保留 | 維持分離 Repo 的特性,各自有獨立的 Git 工作流程 |
這種架構通常需要額外維護一個 Helm Chart Server。好消息是 Helm v3 支援 OCI 格式,所以可以直接使用支援 OCI 的 Container Registry(如 ECR、Harbor)來存放,不一定要另外架設 Chart Museum。
Image Tag 自動更新
在方案二和方案三的架構下,很多團隊會進一步思考:當 Container Image 有新版本 tag 時,如何自動更新部署 Repo 中的描述檔?
常見的做法包括:
- 使用 Argo Image Updater 自動偵測並更新
- 自建 CI/CD 流程,在映像檔推送成功後自動觸發 YAML 更新
總結
回顧一下今天聊到的重點:
- K8s Manifest 工具:原生 YAML、Helm、Kustomize、Jsonnet 各有特色與適用情境,實務上經常混合使用。
- Git Repo 架構:同 Repo vs 分 Repo vs 混合模式,沒有標準答案,取決於團隊規模、流程成熟度和工作負荷。
- Image Tag 更新:分 Repo 架構下,可搭配 Argo Image Updater 或自建流程來自動化。
最終選擇什麼方案,還是得回到團隊實際的需求和能力來評估。希望這篇整理能幫助你在規劃 GitOps 架構時有更清楚的方向。

發佈留言