前兩天說了 Kustomize 和 Helm,兩者都能產生 Kubernetes YAML。產生之後,還有兩個問題:誰負責部署?如果叢集裡的設定被改掉,誰會發現並處理?
今天要說的 kapp、kapp-controller 與 ytt,剛好分別處理這幾件事。它們可以單獨使用,也可以串成一套流程,Carvel Package 則是其中一種應用。
App 宣告來源與部署方式,定期重新取得內容、產生 YAML,再交給 kapp 部署。App 的流程可以記成 fetch → template → deploy:

例如有人直接修改受管理的 Deployment,下次同步時,kapp-controller 可能依來源內容把受管理欄位調回來。
它校正的是目前宣告的期望狀態,不會自己判斷哪個歷史版本比較正確;kapp 也會依欄位合併與忽略規則處理差異,並非每次都重寫整個物件。
如果共用 YAML 或套件的 values 已經提供我要調的欄位,直接填 values 最容易維護。但有時我要增加一段 volume 設定,原本的模板卻沒有開放這個欄位。
這時可以把上游原稿保留,另外用 ytt overlay 描述「找到哪個資源、修改哪個欄位」。ytt 會依 YAML 結構匹配,能增加、替換或移除內容,也可以要求匹配數量符合預期。之後上游更新時,再用同一份 overlay 產生新結果。ytt Data Values 與 Overlays
名稱雖然也叫 overlay,但它和 Day 23 的 Kustomize overlay 是不同機制。
Kustomize 在 kustomization.yaml 引用資源與 patch;ytt overlay 則在 YAML 中寫匹配與修改規則。兩者最後都產生 Kubernetes YAML,ytt 也不需要安裝 kapp-controller 才能單獨使用。
overlay 需要依賴上游結構,如果新版把 container 改名,原本的匹配可能失敗,而條件寫得太寬,也可能改到別的資源,因此升級時要重新 render,檢查最後產生的 YAML。
我處理過一個由 Carvel Package 管理的 logging DaemonSet,需要增加 volume 與 volumeMount,但套件的 values 沒提供對應欄位。
但直接修改叢集裡的 DaemonSet,後續又會被套件的宣告狀態還原回去,所以改用 ytt overlay 保存這項客製設定。
當時容易漏掉的一步是:建立 overlay Secret 後,還要在 PackageInstall 加上引用它的 annotation,例如 ext.packaging.carvel.dev/ytt-paths-from-secret-name.0: log-overlay。Secret 與 PackageInstall 要在同一個 Namespace;只建立 Secret,套件不會自行讀取。套件產生的 App 會在 template 階段使用這份 overlay,再由 kapp 部署結果。
驗證時不能只看 Secret 或 annotation 存在,還要看 PackageInstall/App 的 reconcile 結果,最後確認 DaemonSet 確實有 volume、volumeMount,Pod 也能正常使用。
這個例子讓我記住:先找出資源是由誰產生,再回到那個流程的輸入修改。
假設團隊已用 GitLab Repo 管 YAML,由 CI 檢查,CD 在發布時連到叢集執行 apply。這樣就能部署服務,不需要為了每次發布再裝一套 kapp-controller。
CI/CD 也可以安排定期檢查與修復漂移,只是要自己建立這項流程。
兩種方式主要差在誰負責部署,以及兩次發布之間怎麼處理:
| GitLab Pipeline 執行 CD | kapp-controller 讀取 GitLab Repo | |
|---|---|---|
| 何時部署 | Pipeline 被觸發時執行;也可以另外設定排程 | Controller 依 App 的同步設定定期取得來源、比對差異 |
| 誰連叢集 | CD 執行端需要部署權限 | Controller 使用叢集內指定的 ServiceAccount |
| 叢集端被手動修改 | 要靠下一次 CD,或另設漂移檢查與修復 | 後續同步可能把受管理欄位調回來源宣告 |
| GitLab 的工作 | Repo、CI 與 CD 都由 Pipeline 串接 | Repo 仍保存期望狀態;CI 仍可測試、建 image、檢查 YAML,部署交給 Controller |
這就是 Carvel GitOps 的做法:先在叢集建立一個 App,讓它追蹤 GitLab Repo 的指定分支或版本。
變更通過審查並進入追蹤的來源後,Controller 會自行 fetch、template、deploy;Pipeline 不一定要直接對叢集 apply。
不過,合併進被監看的分支,可能就等於開始部署。
正式環境若要另外核准發布,得先設計分支、固定版本或變更 App 來源的晉版流程。
Git 合併成功也不代表叢集部署成功,還要看 App status 與 workload。
前面提過的版本衝突也可能會發生:如果 GitLab CD 直接把同一個 Deployment 改成 v2,但 kapp-controller 仍讀到 v1,下次同步可能把它調回 v1。要讓兩者合作,可以由 CI 負責驗證並更新 Controller 讀取的期望版本,讓 kapp-controller 成為這批資源的部署入口。同一批資源要有明確的管理者。
如果現有部署檔是 Kustomize overlays,還有一個選型限制:Carvel 官方目前將 App.spec.template.kustomize 標為尚未實作。
可以讓 CI 先 render 成最終 YAML,交給 Controller 讀取;但若現有 GitLab CD 已能穩定部署,也可以繼續沿用。
App。PackageInstall 選擇套件與版本,kapp-controller 產生並管理 App。我會把這三個工具看成不同層次的選擇:ytt 處理 YAML,kapp 處理一組資源的部署,kapp-controller 才加入叢集內持續同步。弄清楚當前缺的是哪一層,再決定是否導入。