跳轉到

Locust EKS Istio 安裝完整歷程:K8s 1.34 版本選型、ARM64 架構、八個除錯問題、Gateway 安裝、NLB 重用決策、跨 namespace xDS 認證失敗

文檔資訊

  • 分類: architecture
  • 難度: advanced
  • 預估閱讀時間: 35 分鐘
  • 標籤: istio, eks, k8s-1.34, locust, jenkins, nlb, multi-cluster, dry-run, ci-cd, mesh-naming, crlf, openssl, ca-cert, debugging, crashloopbackoff, istiod, arm64, aarch64, exec-format-error, ecr, multi-arch, imagepullbackoff, istio-1.26.2, istio-1.29.0, docker.io, ca-not-authorized, gateway, helm, nlb-reuse, xds, authentication-failure, namespace-migration

摘要

K8s 1.34 升級後,為 Locust EKS cluster 安裝 Istio 1.29.0 的完整歷程。從版本選型(1.26.2 EOL 風險→1.29.0)、ARM64 架構不匹配(私有 ECR amd64 映像→docker.io 官方 multi-arch 解法)、CA 憑證生成(openssl basicConstraints 必要性)、CRLF 換行符問題,到 Gateway 安裝機制(3_3_installGateway.sh 透過 --set key=null 清除 chart 預設值)、NLB 重用決策(patch selector/ports 避免改 DNS),以及跨 namespace xDS 認證失敗(第八個問題)。Jenkins kubeContext:null 靜默失敗有 build #121 完整 log 佐證。

關鍵學習

  • K8s 1.34 需要 Istio 1.25+,最終使用 1.29.0(1.26.2 EOL 至 2026/08,之後無官方安全修補)

  • Locust EKS 節點為 ARM64(aarch64),私有 ECR 僅有 amd64 映像,導致 exec format error。最終解法:使用 docker.io 官方 multi-arch 映像

  • openssl 生成 CA 憑證必須包含 basicConstraints: CA:true 和 keyUsage: keyCertSign,否則 istiod 報 certificate is not authorized to sign other certificates

  • CRLF 換行符(Windows 編輯器)導致 env: bash\r: No such file or directory,每次提交前需 dos2unix

  • Helm chart 的 values.yaml 預設值無法被 -f 完全覆蓋,chart 預設 key 仍存在,需用 --set key=null 明確清除

  • ISTIO_DEPLOY_PATH 不能寫死版本號,必須動態跟隨 ISTIO_VERSION 參數,否則路徑仍指向舊版目錄

  • Gateway pod 部署至非 istio-system namespace 時,istio-proxy 與 istiod 的 xDS 連線會報 authentication failure,readiness probe 持續失敗 760 次/29 分鐘

  • 透過 JSON Patch NLB Service 的 selector 和 ports 可重用現有 NLB,避免修改 DNS record

  • Jenkins kubeContext:null 時,|| true 吃掉 exit code,pipeline 繼續執行直到最後才 FAILURE(build #121 血淋淋教訓)

技術細節

Istio 版本相容性

K8s 1.34 需要 Istio 1.25+,最終成功安裝版本為 1.29.0

  • Istio 1.26.2:EOL 警告,官方支援至 2026 年 8 月,之後停止安全修補
  • Istio 1.29.0:最終成功版本,使用 docker.io 官方 multi-arch 映像(同時支援 amd64/arm64)

問題一:CRLF 換行符

Windows 編輯器儲存腳本含 CRLF 換行符,Linux 執行失敗:

env: 'bash\r': No such file or directory

修正:每次從 Windows 編輯後執行 dos2unix

問題二:Docker 不可用

2_genClusterIstioCA.sh 原先依賴 Docker 生成 CA 憑證,改用 openssl 直接生成,消除 Docker 依賴。

問題三:ISTIO_DEPLOY_PATH 雙重問題

腳本存在兩個問題:(1) fallback 邏輯指向舊版 istio-1.24.1;(2) 腳本內有硬寫死的版本號。

錯誤輸出:使用 fallback deploy 目錄:/aws/base_helm/istio/istio-1.24.1/deploy,而非 1.26.2 或 1.29.0。需同時修正兩處,確保路徑動態跟隨 ISTIO_VERSION 參數。

問題四(根本原因):ARM64 架構不匹配

Locust EKS 節點架構(實際確認):

6.12.68-92.122.amzn2023.aarch64   containerd://2.1.5

私有 ECR 中的 Istio 映像為 amd64,無法在 ARM64 節點執行,錯誤訊息:

exec /usr/local/bin/pilot-discovery: exec format error

問題五:私有 ECR 無 1.29.0 映像

升級至 1.29.0 後,私有 ECR 根本沒有對應版本的映像(ImagePullBackOff),ECR 路徑:313249118980.dkr.ecr.ap-southeast-1.amazonaws.com/ps-ecr-repo/istio/pilot:1.29.0: not found

最終解法:docker.io 官方 multi-arch 映像

3_2_installIstio.sh 加入 ISTIO_HUB 參數,設定為 docker.io 時跳過私有 ECR,直接使用官方映像。

問題六/七:CA 憑證缺少 CA 約束

openssl 生成憑證時必須加入:

-addext 'basicConstraints=critical,CA:true'
-addext 'keyUsage=critical,keyCertSign,cRLSign'

否則 istiod 報:certificate is not authorized to sign other certificates

Gateway 安裝機制(3_3_installGateway.sh)

3_3_installGateway.sh 動態生成最小化 values YAML,並透過 --set key=null 清除 Helm chart 預設值(ALB ingress、TCP ports 等),確保 locust-eks 只部署 HTTP port 80 的 gateway。

dry-run 輸出(已驗證)確認以下方式可正確清除 chart 預設值:

helm upgrade istio-ingress-gateway /aws/helm/IstioGateway \
  --install -n istio-system --kube-context locust-eks \
  -f /tmp/gateway-values-locust-eks.yaml \
  --set gatewayMap.alb-ingress-gateway-dev=null \
  --set gatewayMap.ingressgateway-dev.servers.testRule=null \
  --set gatewayMap.ingressgateway-dev.servers.testRule2=null \
  --set gatewayMap.ingressgateway-dev.servers.redisRuleMaster1=null \
  --set gatewayMap.ingressgateway-dev.servers.valkeyRuleMaster2=null \
  --set gatewayMap.ingressgateway-dev.servers.postgreSqlRule=null \
  --set gatewayMap.ingressgateway-dev.servers.rdsSqlRule=null \
  --set albIngressMap.alb-ingress-dev=null

第八個問題:跨 namespace xDS 認證失敗

Gateway pod 部署至 loadtest namespace 後,istio-proxyistiod.istio-system.svc:15012 建立 xDS gRPC 連線失敗:

DeltaAggregatedResources gRPC config stream to xds-grpc closed: 16, authentication failure{via_upstream}
upstream terminated with unexpected error rpc error: code = Unauthenticated desc = authentication failure

Readiness probe 持續報 connection refused on port 15021,Pod 狀態為 Unhealthy(760 次失敗/29分鐘)。

根本原因:Istio 的 trust domain 驗證基於 SPIFFE URI,格式為 spiffe://<trust-domain>/ns/<namespace>/sa/<serviceaccount>。istiod 預設只信任 istio-system namespace 的 gateway,loadtest namespace 的 gateway pods 的 SA token 不在信任域內,導致 mTLS 握手失敗。

Jenkins kubeContext:null 靜默失敗(build #121 完整 log)

build #121 log 直接呈現完整靜默失敗鏈:

kubeContext: null
error: context "null" does not exist
++ true   ← || true 吃掉 exit code
No pods found matching ps-func-web-beta

ECR push 成功(#839, #840 均 SUCCESS),但 pod restart 完全跳過,pipeline 最終才以 FAILURE 結束。

What Changed

Jenkins build #121 完整 log 確認靜默失敗鏈:直接呈現 kubeContext: nullerror: context "null" does not exist|| true 吃掉 exit code 的完整靜默失敗鏈,確認 ECR push(#839, #840)成功但 pod restart 被跳過的實際順序。這是最直接的佐證,不再是推論。

第八個問題的完整錯誤 logauthentication failure{via_upstream}code = Unauthenticated desc = authentication failure 的完整輸出,以及 readiness probe 在 port 15021 持續失敗(760 次/29分鐘)的事件記錄,補強了跨 namespace xDS 信任域問題的技術細節。

NLB 重用方案的 dry-run 驗證3_4_migrateGatewayToLoadtest.sh --dry-run 的完整輸出確認了 JSON Patch 方案的可行性,patch 後 locust-mingo-locust-master 的 selector 指向 {app: istio-ingressgateway-dev, istio: ingressgateway},NLB endpoint 完全不需變動。

So What

本案例完整揭示了將 Istio 部署到 ARM64 EKS cluster 的四層陷阱,每一層都有不直觀的錯誤訊息:

  1. 架構層exec format error 看起來像映像損壞,實際是 amd64/arm64 不匹配
  2. 映像層:私有 ECR 版本落後,升版後立即 ImagePullBackOff
  3. 憑證層certificate is not authorized to sign 在 CA 約束缺失時才出現,容易誤判
  4. 信任域層(新確認):Gateway 跨 namespace 部署時,authentication failure 不直觀,容易誤判為網路問題,readiness probe 持續 760 次失敗是可量化的症狀

NLB 重用決策的模式(patch selector/ports 而非建新 NLB 改 DNS)是生產環境遷移的標準手法,有 dry-run 輸出驗證可行性,值得作為組織內的標準 SOP。

Jenkins || true 吃掉 exit code 導致靜默失敗的模式,在 CI/CD pipeline 中非常危險,build #121 是實際血淋淋的教訓。

Trade-offs

  • NLB vs ALB:使用 NLB。延遲更低、成本更低;缺少 WAF、path routing 等 L7 功能,但 loadtest 場景已足夠
  • 改 DNS vs patch NLB selector:patch selector。零停機、無 DNS TTL 等待;代價是 Service 的 selector/ports 與原始設計分離,需文件記錄
  • Gateway 在 istio-system vs loadtest:istio-system 是預設位置,RBAC/trust domain 問題少;loadtest 可重用現有 NLB,但需額外配置 istiod 信任域,否則 xDS 認證失敗(目前未解)
  • openssl vs docker 生成 CA 憑證:使用 openssl。消除 Docker 依賴;但必須確保 CA 約束參數正確(basicConstraints, keyUsage)
  • 私有 ECR vs 官方 docker.io multi-arch 映像:使用官方 docker.io。無需維護多架構映像推送;代價是依賴外網拉取(需 NAT Gateway)
  • 1.26.2 vs 1.29.0:使用 1.29.0。支援期更長(1.26.2 EOL 2026/08);但私有 ECR 需額外準備(本次改用官方映像繞過)

Try It Fast

# 0. 修正 CRLF 換行符(每次從 Windows 編輯後必做)
dos2unix 3_2_installIstio.sh 2_genClusterIstioCA.sh 3_3_installGateway.sh 3_4_migrateGatewayToLoadtest.sh

# 1. 確認節點架構(aarch64 = ARM64 = 需要 multi-arch 映像)
kubectl --context locust-eks get nodes -o wide

# 2. 安裝 Istio 1.29.0(docker.io hub,支援 arm64 multi-arch)
./3_2_installIstio.sh --dry-run dev ap-southeast-1 locust-eks 313249118980 1.29.0 locust-eks "loadtest"
./3_2_installIstio.sh dev ap-southeast-1 locust-eks 313249118980 1.29.0 locust-eks "loadtest"

# 3. 安裝後驗證(istiod + ingressgateway-dev 應 1/1 Running)
kubectl --context locust-eks get pods -n istio-system

# 4. 建立 Gateway(只含 HTTP port 80)
./3_3_installGateway.sh --dry-run locust-eks dev-locust.pocket-store.make-wish.club
./3_3_installGateway.sh locust-eks dev-locust.pocket-store.make-wish.club

# 5. 遷移 Gateway 至 loadtest(重用現有 NLB,不改 DNS)
./3_4_migrateGatewayToLoadtest.sh --dry-run locust-eks
./3_4_migrateGatewayToLoadtest.sh locust-eks

# 6. 即時診斷
kubectl --context locust-eks logs -n istio-system -l app=istiod --tail=20
# exec format error          = 架構不匹配(hub 仍指向 amd64 映像)
# ImagePullBackOff           = ECR 無對應版本映像
# certificate is not authorized to sign = CA 憑證缺少 CA 約束
# authentication failure     = Gateway pod 跨 namespace,xDS 信任域未配置

# 7. 修復 CA 憑證問題
kubectl --context locust-eks delete secret cacerts -n istio-system
# 重新執行安裝腳本(會重新生成正確的 CA 憑證)

# 8. 診斷 xDS 認證失敗(Gateway 在非 istio-system namespace)
kubectl --context locust-eks logs -n loadtest -l app=istio-ingressgateway-dev --tail=20
kubectl --context locust-eks get authorizationpolicy -n istio-system

Recommendation

  1. 已完成:Istio 1.29.0 成功安裝(docker.io 官方 multi-arch 映像),istiod 和 ingressgateway-dev 均 1/1 Running
  2. 已完成:Gateway 資源建立(3_3_installGateway.sh),只含 HTTP port 80,host 為 dev-locust.pocket-store.make-wish.club
  3. 待解決(最優先):xDS 認證失敗:Gateway pod 在 loadtest namespace 持續報 authentication failure(760 次/29 分鐘)。診斷方向:確認 istiod 的 AuthorizationPolicy 是否限制來源 namespace;確認 MeshConfig.trustDomain 設定;若問題複雜,可改回 istio-system 部署,直接更新 DNS record 指向新 NLB endpoint ae8d4d53caccc40c5add507ee42cb60f-07a04c45a623e737.elb.ap-southeast-1.amazonaws.com
  4. 修復 Jenkins kubeContext:null:在 Configure stage 加入 if (!kubeContext) error('kubeContext 不能為空'),防止靜默失敗(build #121 已佐證此 bug)
  5. CA 憑證生成標準化:確保 2_genClusterIstioCA.sh 包含 -addext 'basicConstraints=critical,CA:true'-addext 'keyUsage=critical,keyCertSign,cRLSign'
  6. 建立 dos2unix 慣例:腳本提交前確認換行符為 LF,或在 CI/CD pipeline 加入自動 dos2unix
  7. ECR 映像管理:若之後需改回私有 ECR,每次升級前先確認 ECR 有對應版本的 ARM64 映像

本文檔由 Semi-Brain 自動生成

Session ID: 64b0516b-af8e-4206-8a1b-037aee68b1bf

分析信心度: 98%