跳轉到

Jenkins Helm 部署到 EKS QA 專屬 Node Group:NoExecute Taint + Annotation 格式問題排查(融合演化版 v8)

文檔資訊

  • 分類: debugging
  • 難度: intermediate
  • 預估閱讀時間: 16 分鐘
  • 標籤: helm, eks, jenkins, taint, toleration, nodeSelector, annotation, scheduling, qa-test, AutoRemoveDeploySite, groovy, pipeline, valkey, redis, istio, virtual-service, ssl, istio-gateway

摘要

Jenkins Pipeline 部署 Helm Chart 到 EKS QA 專屬 Node Group 的完整除錯記錄。涵蓋 Helm annotation unmarshal 失敗(Groovy→Shell→Helm 三層轉義,build #1672 log 佐證)、Pod 因 NoExecute taint 無法調度(需同時加 nodeSelector + toleration)、AutoRemoveDeploySite 完整清空機制(含 DB/Kafka)為長期設計意圖、Valkey Serverless vs 非 Serverless 連線設定差異(SSL Host 陷阱),以及 IstioGateway 新增 port 16381 對外暴露 Serverless Valkey 的完整流程(含 Container 內 helm chart 路徑問題解法、dry-run 驗證、實際部署成功 REVISION: 31)。v8 新增:IstioGateway 部署已實際執行成功,UpdateVirtualService #1004 已重新生成含 port 16381 的 tcpValues,UpgradeServer 參數於 2025/08/07 已棄用。

關鍵學習

  • EKS Node Group 設 NoExecute taint 時,Pod 必須同時有 nodeSelector + toleration 才能調度,缺一不可

  • NoExecute 比 NoSchedule 更嚴格:不只阻止新 Pod 調度,還會驅逐已在運行的 Pod

  • Helm --set 傳遞含 / 或 . 的 annotation key 時,Groovy→Shell→Helm 三層轉義極易出錯,建議改用 values file 或 --set-string

  • AutoRemoveDeploySite 執行後等同環境完整 reset(含 DB/Kafka/ConfigMap),qa-test 資料不具持久性,且為長期設計意圖

  • skipProcDBMQ: false 是長期設計(備份檔案與 git 歷史雙重確認),非近期引入的變更

  • Valkey Serverless 連線必須啟用 TLS,且 SSL Host 欄位要填入 Serverless hostname(不可留空,否則 TLS SNI 驗證失敗)

  • 非 Serverless Valkey 走 Virtual Service 代理(service.pocket-store.make-wish.club:16380),SSL Host 填 AWS 內部 master endpoint

  • IstioGateway chart 使用 /aws/helm/IstioGateway 路徑,該路徑來自 devops/helm.git repo 的 volume mount,修改後需 push 到該 repo 或直接 cp 進 container 才能生效

  • UpdateVirtualService tcpValues 由 genVirtualServiceRecord.py 從 baseInfo_Def.py 的 ConnectInfos 動態生成,OutClusterPort != 0 才會產生對應路由

  • UpgradeServer 參數於 2025/08/07 已棄用,AutoBuildSiteDeploy 觸發時不需勾選

技術細節

錯誤一:Helm Annotation Unmarshal 失敗(build #1672 實際 log 佐證)

錯誤訊息:json: cannot unmarshal object into Go struct field ObjectMeta.spec.template.metadata.annotations of type string

build #1672 log 直接佐證:--set 'podAnnotations.ps\.version/server=0.14.0-qa-test' 在 Groovy → Shell → Helm 三層轉義後,Helm 解析 ps\.version/server 時將 / 後的部分解析為 object 結構,導致 unmarshal 失敗。

解法:改用 writeFile 生成 dataversion-values.yaml,再以 -f dataversion-values.yaml 傳給 Helm;含特殊字符的 annotation key 改用 --set-string


錯誤二:Pod 無法調度到 QA 專屬 Node

0/3 nodes are available:
  1 node(s) had untolerated taint(s)
  2 node(s) didn't match Pod's node affinity/selector

kubectl 實際確認 QA Node taint:Taints: site=qa-test:NoExecute

NoExecute 不只阻止新 Pod 調度,還會驅逐已存在的 Pod。僅設 nodeSelector.site=qa-test 不足,必須同時加 toleration。本地版本 deploySite == 'qa-test' 區塊中,nodeSelector 被 Lupin 暫時 comment 掉(2026.04.08 備註),需重新啟用並補上 toleration。

同樣修正套用到 DeployWebBackend.groovy,避免 web pod 跑到非 QA 專屬 node。


AutoRemoveDeploySite 行為(build #449 完整流程)

build #449(2026-04-08 02:27)依序執行:UpdateVirtualService #998(uninstall)→ DeployAllServers #933(uninstall)→ DeployConfigMap #954(uninstall)→ GenGlobal #1146(skipProcDBMQ: false,連 DB/MQ 也清)→ ResetKafkaOffset #264

skipProcDBMQ: false 在 commit caf4a06 及更早的備份檔案 D:\trident\jenkins-pipeline-files 中均已存在,是長期設計意圖。


Valkey 連線設定(Serverless vs 非 Serverless)

Serverless(qa-test): - Hostname:ps-svrless-valkey-dev-fazxeu.serverless.apse1.cache.amazonaws.com - Port: 6379,TLS: 必須啟用 - SSL Host 欄位:需填入上述 hostname(不可留空,否則 TLS SNI 驗證失敗)

非 Serverless(如 charles 站點): - 連線走 Virtual Service 代理:service.pocket-store.make-wish.club:16380 - TLS: 啟用,SSL Host 填 master.eks-dev-valkey.fazxeu.apse1.cache.amazonaws.com - Host 與 SSL Host 不同是刻意設計(Virtual Service TLS 透通)


IstioGateway 新增 port 16381(v8 新增:實際部署成功)

目前無獨立 Jenkins Pipeline,新增 port 需手動執行 helm upgrade。腳本位置:/mnt/d/trident/base_helm/AWS-EKS/3_3_installGateway.sh

重要:腳本內部使用 /aws/helm/IstioGateway 路徑,這是來自 devops/helm.git 的 volume mount,與本地 trident-jenkins/helm/ 路徑不同。修改 IstioGateway/values.yaml 後必須 push 到 devops/helm.git(或直接 cp 進 container),才能讓腳本讀到新版本。

實際執行結果:dry-run 確認 port 16381 出現後,執行正式部署,REVISION: 31,STATUS: deployed。

UpdateVirtualService tcpValues 生成機制

genVirtualServiceRecord.py 中的 gen_vs_tcp_settings_file_v1() 讀取 baseInfo_Def.pyConnectInfos,對每個 OutClusterPort != 0 的服務生成 TCP route。valkey-dev-1-serverlessOutClusterPort 已從 6379 改為 16381OutClusterConnectStr 改為 service.pocket-store.make-wish.club,使 UpdateVirtualService pipeline 能自動生成 port 16381 的路由規則。UpdateVirtualService #1004 已成功執行(runMode=upgrade, siteName=qa-test)。

What Changed

v8 相較 v7 有三大新增確認內容。

第一,IstioGateway port 16381 已實際部署成功。先透過 dry-run 確認 valkeyServerlessRule(port 16381)正確出現在 COMPUTED VALUES 和 MANIFEST 中,然後執行正式 helm upgrade,結果 REVISION: 31,STATUS: deployed。關鍵障礙是 container 內使用的 helm chart 路徑 /aws/helm/IstioGateway 來自 devops/helm.git volume mount,必須先將修改 push 到該 repo(或直接 cp 進 container)才能生效。

第二,UpdateVirtualService #1004 已成功執行(runMode=upgrade, siteName=qa-test),Python 腳本重新生成了含 port 16381 的 tcpValues。至此 Serverless Valkey 外部連線架構全部到位:IstioGateway 暴露 port 16381 → VirtualService 路由到 AWS Serverless endpoint。

第三,確認 UpgradeServer 參數於 2025/08/07 已棄用,AutoBuildSiteDeploy 觸發 DeployServer 時不需要勾選此參數。

So What

IstioGateway 的 helm chart 路徑問題(/aws/helm/IstioGateway vs 本地路徑)是個容易踩坑的地方:本地修改了 values.yaml 但 dry-run 仍顯示舊版本,原因是腳本讀的是 container 內 volume mount 的路徑,必須 push 到 devops/helm.git 或手動 cp 才能讓腳本讀到新版本。若不了解這個路徑對應關係,會在「為什麼 dry-run 結果沒有更新」這個問題上白費時間。

Serverless Valkey 外部連線需要三個組件同時到位:IstioGateway 暴露 port、VirtualService 路由規則、baseInfo_Def.py 的 OutClusterPort 設定。其中 VirtualService 是由 Python 腳本動態生成的,不是手動設定,所以只要 baseInfo_Def.py 設定正確,UpdateVirtualService pipeline 重跑後會自動產生正確路由。

AutoRemoveDeploySite 的設計意圖有 git 歷史與備份檔案雙重佐證,QA 回報資料遺失時不應懷疑部署問題,應優先查此 job 的 build history。

Trade-offs

  • NoExecute vs NoSchedule:NoExecute 更嚴格,會驅逐已運行 Pod,適合強隔離但要求所有 Pod 聲明 toleration
  • annotation 用 --set vs --set-string vs values file:含特殊字符的 annotation key 用 --set 三層轉義易出錯;--set-string 可避免型別問題;values file 最穩定但需動態生成
  • AutoRemoveDeploySite 的破壞性:完整重置適合 CI 自動化,但對持續測試不友好;如需保護資料應加白名單或備份步驟
  • Valkey Serverless vs 非 Serverless:Serverless 無固定 IP,連線工具需使用 hostname;非 Serverless 走 Virtual Service 有額外網路層,SSL Host 設定更複雜
  • IstioGateway 無 Pipeline:手動 helm upgrade 靈活但容易遺漏,未來如需頻繁修改應考慮建立 Pipeline
  • helm chart 路徑雙份問題:本地 trident-jenkins/helm/ 和 container 內 /aws/helm/(devops/helm.git)是兩個不同 repo,修改需同步到正確 repo 才能生效

Try It Fast

# 確認 Node 的 taint 設定
kubectl --context gamania-ps-dev describe node <node-name> | grep -A5 Taint

# 確認 Pod 調度失敗原因
kubectl --context gamania-ps-dev describe pod <pod-name> -n ps | grep -A10 Events

# 手動渲染確認 toleration 正確生成(不實際部署)
helm template PSServer --debug \
  --set nodeSelector.site=qa-test \
  --set tolerations[0].key=site \
  --set tolerations[0].value=qa-test \
  --set tolerations[0].effect=NoExecute \
  --set tolerations[0].operator=Equal \
  | grep -A20 'tolerations\|nodeSelector'

# IstioGateway dry-run 確認 port 16381 是否出現
cd /mnt/d/trident/base_helm/AWS-EKS
./3_3_installGateway.sh --dry-run gamania-ps-dev
# 確認 MANIFEST 中有 valkeyServerlessPort1 (16381)

# 正式執行 IstioGateway helm upgrade
./3_3_installGateway.sh gamania-ps-dev
# 應看到 STATUS: deployed, REVISION 遞增

# Another Redis Desktop Manager 連線 Valkey Serverless
# Host: ps-svrless-valkey-dev-fazxeu.serverless.apse1.cache.amazonaws.com
# Port: 6379  |  SSL: ON
# SSL Host(SNI): ps-svrless-valkey-dev-fazxeu.serverless.apse1.cache.amazonaws.com  ← 不可留空!

# Another Redis Desktop Manager 連線非 Serverless(Virtual Service 代理)
# Host: service.pocket-store.make-wish.club  |  Port: 16380  |  SSL: ON
# SSL Host(SNI): master.eks-dev-valkey.fazxeu.apse1.cache.amazonaws.com  ← 填 AWS master endpoint

# 透過 Istio 連接 Serverless Valkey(外部工具,port 16381)
# Host: service.pocket-store.make-wish.club  |  Port: 16381  |  SSL: ON
# SSL Host(SNI): ps-svrless-valkey-dev-fazxeu.serverless.apse1.cache.amazonaws.com

Recommendation

  1. 重新啟用本地 Jenkinsfile 中 qa-test 區塊被 comment 掉的 nodeSelector,並同時補上 toleration(key=site, value=qa-test, effect=NoExecute)
  2. 每次新增 dedicated Node Group 後,第一次部署前先用 helm template 渲染並 grep tolerations 確認生成正確
  3. Helm --set 傳遞含 /、. 等特殊字符的值時,優先改用 --set-stringwriteFile 生成 values yaml
  4. Valkey 連線工具(Another Redis Desktop Manager 等)設定時,SSL Host 欄位必須填入:Serverless 填 hostname 本身;非 Serverless 走 Virtual Service 時填 AWS master endpoint
  5. AutoRemoveDeploySite 觸發後會完整清空 DB/Kafka/ConfigMap,QA 回報資料遺失應優先查此 job 的 build history
  6. 修改 IstioGateway values.yaml 後,需 push 到 devops/helm.git repo(container 內路徑 /aws/helm/IstioGateway 是從此 repo mount),才能讓 3_3_installGateway.sh 讀到新版本
  7. 新增 Serverless Valkey 外部連線路由後,必須重跑 UpdateVirtualService pipeline(runMode=upgrade)讓 Python 腳本重新生成 tcpValues,port 16381 路由才會生效
  8. UpgradeServer 參數於 2025/08/07 已棄用,觸發 DeployServer 相關 pipeline 時不需勾選
  9. 確認歷史設計意圖時,git log + 備份檔案雙管齊下,避免僅憑最近一筆 commit 誤判

本文檔由 Semi-Brain 自動生成

Session ID: 4704b57e-d74e-48ab-811d-8bf398552c49

分析信心度: 96%