helm diff?我裝個 plugin 連環踩了 4 個坑
今天的學習任務本來很單純:裝 helm-diff plugin,體驗一次 helm diff upgrade,理解為什麼 production 上要用它。
結果從 helm plugin install 那一刻起,連環踩了 4 個坑——而最後一個讓我真的見識到「diff 顯示無變化,但實際部署會改東西」是怎麼發生的,把過程完整記下來。
Pitfall 1:plugin 裝不起來,要 --verify=false
第一步就卡:
helm plugin install https://github.com/databus23/helm-diff
# Error: plugin source does not support verification. Use --verify=false to skip verification
原因是 Helm v3.18+ 開始預設要求 plugin 有 GPG provenance 簽章驗證,但大多數社群 plugin(包含 helm-diff)的 release 根本沒附簽章檔,驗證就一定失敗。照提示加上 flag 即可:
helm plugin install https://github.com/databus23/helm-diff --verify=false
--verify 在做的是供應鏈防護——確認你下載的 plugin 沒被竄改、確實出自作者。在本機 lab、來源又是知名官方 repo 的情況下,--verify=false 是合理的。但要建立的正確直覺是:production / CI 自動裝 plugin 時,「跳過驗證」不該是隨手帶過的習慣。較穩的做法是先 clone、檢視內容、鎖定特定 tag/commit,再從本機路徑安裝。供應鏈攻擊很多就是從「反正只是裝個工具」開始的。
Pitfall 2:schema 把 image tag 擋下來
裝好後第一次 diff,吐出這個:
Error: at '/image/tag': got number, want string
我前一天的練習幫 chart 加了 values.schema.json,裡面規定 image.tag 必須是 string。問題出在 values.yaml:
image:
tag: 1.27
沒加引號的 1.27,YAML 會解析成數字,schema 一比對就擋下來。加上引號就過了:
image:
tag: "1.27"
這其實是 schema validation 替我抓到的隱性 bug:image tag 永遠該加引號。像 1.20、1.0 這種值若被當數字,1.20 會被截成 1.2、1.0 變 1,部署時就抓錯 image。一個看起來無害的引號,避免的是 production 抓錯版本。
Pitfall 3:helm diff 沒有任何輸出
過了 schema 之後,diff 的輸出讓我愣住——有時印出 -/+,有時完全空白。釐清後記下兩個關鍵:
- 是 cluster 現存 release 的狀態(live),+ 是套用後會變成的狀態。 不是「檔案 vs 檔案」,是「現況 vs 套用後」。
值的優先序(高到低):--set > -f/--values 檔案 > chart 的 values.yaml > 子 chart values。我一度在 values.yaml 改半天 diff 沒反應,其實是被命令列的 --set 蓋掉了——這是最常見的「改了沒生效」陷阱。
排查時最有用的手法,是手動把 helm-diff 底層做的事拆開來看:
# live:cluster 上 release 實際存的 manifest
helm get manifest demo -n demo | grep -E "^kind:|replicas:"
# new:用 values.yaml 重新渲染的結果
helm template demo ~/helm-lab/myfirst-chart | grep -E "^kind:|replicas:"
helm get manifest 是「現況」,helm template 是「用檔案重算」,兩邊一比就知道哪個物件不一樣。理解這一層之後,helm-diff 對我就不再是黑盒子。
Pitfall 4:diff 顯示「無變化」,但 helm upgrade 其實會改東西
這是今天最重要、也最該寫進筆記的一個。
當時的狀態是這樣:values.yaml 裡 replicaCount: 1,但 cluster 上的 release 是當初用 replicaCount: 2 部署存進去的。我跑:
helm diff upgrade demo ~/helm-lab/myfirst-chart -n demo
# (沒有任何輸出)
diff 顯示「無變化」。但我手動比對 live 和 template,明明 Deployment 的 replicas 一個是 2、一個是 1,不應該會沒有差別?
加上 --reset-values 再跑一次,真相就出來了:
helm diff upgrade demo ~/helm-lab/myfirst-chart -n demo --reset-values
demo, demo-myfirst-chart, Deployment (apps) has changed:
spec:
- replicas: 2
+ replicas: 1
問題的根源是兩個指令的預設行為不一致:
helm diff upgrade預設會沿用 release 裡存的舊值(reuse),所以它拿replicaCount: 2去算,跟 live 一比當然「無變化」。- 但 Helm 3 的
helm upgrade預設是 reset——改用 chart 的values.yaml(也就是 1)加上你給的 override。
換句話說:diff 騙了我。它說「無變化」,但我若真的去跑 helm upgrade demo .,replicas 會從 2 被改成 1。diff 與實際部署不符,這正是真實事故的來源——你看 diff 沒變化就安心 merge,實際 apply 卻動了資源。
由此得到一條鐵則:在 CI 用 helm-diff,它的 value 解析模式必須跟你真正部署的指令一致。 三個相關 flag 要記住:
--reuse-values:沿用舊 release 的值,只 merge 這次的 override--reset-values:丟掉舊值,完全用 chart 的values.yaml--reset-then-reuse-values(v3.14+):先 reset 再把舊 override 疊回來,通常最安全
附帶一個小發現:hook(像我 Day 7 加的 pre-install Job、helm create 預設的 test-connection Pod)預設不會進 diff,因為它們不是常駐的 desired state,拿來比對沒有意義。所以 helm template 看得到、diff 卻不提它們,是正常的。
小結
一個 plugin 的安裝,意外變成今天收穫最多的一課。四個坑串起來其實是同一個主題:工具的預設值,不一定等於你真正想要的行為。
helm plugin install預設要驗章 → 不一定裝得起來- YAML 預設把
1.27當數字 → schema 擋下來 --set預設優先序最高 → 蓋掉你改的檔案helm diff預設 reuse、helm upgrade預設 reset → diff 會騙你
DevOps 工具用久了會發現,真正會咬人的往往不是「不會用」,而是「以為它會 A,其實它預設做 B」。下一篇針對 Helm chart 收尾,我會把 Helm 跟 Kustomize 的取捨整理成一篇深度文,順便附上我這兩週寫的 chart。
