打通從 Commit 到 K8S 生產環境的最後一哩路。
GitOps 世界裡,Git 寫什麼叢集就長什麼樣。所以如果 Helm values 寫死 tag: latest,就算 GHCR 上的 latest 更新了一百次,ArgoCD 也一動不動——因為 Git 裡的那行字串沒變。
解法:CI 每次 build 完,把新的 Git SHA「回填」進 helm/wafer-bi/values.yaml,再 commit 回 repo。
.github/workflows/deploy.yml 的最後一個 job:
- name: Bump image tags in Helm values
run: |
# 逐一更新每個服務的 image tag,ArgoCD 偵測到 commit 後自動 Rollout
for key in waferBackend waferFrontend apiGateway userService aiMcpService licenseService; do
yq -i ".${key}.image.tag = \"${{ github.sha }}\"" helm/wafer-bi/values.yaml
done
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
git add helm/wafer-bi/values.yaml
git commit -m "deploy: bump image tags to ${GITHUB_SHA:0:7} [skip ci]"
git pull --rebase origin main
git push
這段有以下兩個地方,少了會出事:
[skip ci]:這個 commit 又動了 repo,不加這個標籤就會觸發下一輪 build,無限輪迴燒光額度git pull --rebase 再 push:六個 build job 平行跑完才收斂到這步,中間若有人推了新 commit,直接 push 會被拒流程圖大家都會畫,我直接拿真實跑過的結果來對照:

▲ GitOps 閉環的三段證據:機器人自動推的部署 commit、ArgoCD 同步回報 Succeeded、Pod 用 GHCR 的正式 image 跑起來
三段證據串起整條鏈路:
git log 裡一排 github-actions[bot] 的 commit——這些「deploy: ...」提交全是機器人自動推的,人類下班之後它們照常上工Succeeded: successfully synced (all tasks run)
於是整條閉環串起來了:
開發者 push code
→ GitHub Actions build 六個 image(tag = Git SHA)
→ CI 回填 SHA 到 helm values([skip ci] commit)
→ ArgoCD 偵測 Git 變化 → 自動 Sync → 新版上線
開發者唯一要做的事:git push。剩下全是機器的事。
這條鏈路最可怕的地方是——斷了也不會有任何報錯。我們就真實發生過:Helm 化之後,CI 的回填腳本還在改舊的 k8s/base/ 目錄,但 ArgoCD 看的是 helm/wafer-bi/。CI 綠燈、commit 照推、ArgoCD 也顯示 Synced,每個環節都「正常」,只是 production 的版本永遠停在 Helm 化那天,哭啊。
發現之後我們做了兩件事:把回填目標改成 helm values(就是上面那段),以及寫了一支 check-config-sync.py 在 CI 強制檢查「CI 改的檔案」與「ArgoCD 看的檔案」是同一份。自動化的鏈路,就要用自動化來守。
閉環完成,push 即部署。但這條鏈路現在只會往前跑——如果推上去的是壞版本呢? 而且在 GitOps 底下,你熟悉的那些急救指令(kubectl rollout undo、helm rollback)會被 ArgoCD 的 selfHeal 兩秒打臉——這句話明天有實測截圖。明天來把「往前」跟「往後」一次講完:滾動更新的旋鈕、回滾的三層樓,以及 Argo Rollouts 的金絲雀發布。