解決 GKE 升級卡住的隱形殺手:Admission Webhook

解決 GKE 升級卡住的隱形殺手:Admission Webhook

在管理 Google Kubernetes Engine (GKE) 叢集的日常中,定期升級版本是維持安全性、修補漏洞與取得新功能的必要工作。但實際上可能會在 Logs Explorer 裡看到讓人摸不著頭緒的錯誤訊息 (例如 Internal errorDeployPatch failed)1,升級流程就這樣卡住,遲遲無法完成。

這類錯誤的根本原因,通常是由 GKE 中安裝的第三方或自訂 Admission Webhook (例如 Gatekeeper、Kyverno 等) 無意間攔截了系統層級的資源變更,進而中斷整個升級流程。

本文可作為〈管理 Kubernetes Webhook 故障:從診斷到解決方案〉的延伸案例研究,說明為什麼 Webhook 不當設定會成為 GKE 升級的潛在問題,並依照對生產環境干擾程度由低到高,提供三種實際可行的解法。

為什麼 Webhook 會導致 GKE 升級失敗?

GKE 在升級控制平面 (UpdateMaster) 時,會建立、更新一系列系統專用的資源 (例如 ClusterRolesClusterRoleBindings),同時也會確保新版本的控制平面能正常運作。

如果你的 Webhook 設定了攔截這些資源的規則,API Server 在每次變更系統資源時,都會試圖呼叫對應的 Webhook 服務進行驗證。但在升級過程中,下列情況都可能發生:

  • 控制平面正在啟動和初始化,網路連線狀態並不穩定
  • 負責運行 Webhook 的 Pod 可能因節點重啟而暫時無法回應
  • 若影響到 konnectivity-agent 的運行與排程,API Server 與 Webhook 服務之間的通訊可能因此中斷,產生類似 No agent available 的錯誤

當升級過程遇到嚴格的 Webhook 檢查 (例如 failurePolicy 設定為 Fail,失敗時拒絕請求),API Server 如果無法成功呼叫 Webhook,就會直接拒絕該次資源變更,於是整個升級流程就此中斷。

解決方案

針對這個問題,可以嘗試以下步驟進行修復,該順序以對生產環境的干擾程度由低到高排序。

方案一:使用 CEL 匹配條件排除系統前綴

從 Kubernetes 1.27 開始 (在 1.30 正式 GA),ValidatingWebhookConfigurationMutatingWebhookConfiguration 支援 matchConditions 欄位。這個欄位允許使用通用表達式語言 (Common Expression Language, CEL),依據資源屬性進行更精細的過濾。2

這也是排除系統資源最優雅、影響面最小的方法。你可以在現有的 Webhook 設定中 (例如 gatekeeper-validating-webhook-configuration 或其他自訂的 Webhook Configuration),加入下方規則:

webhooks:
  - name: validate.your-webhook-name
    # 既有的其他 Webhook 設定 ...
    matchConditions:
      - name: "exclude-system-prefixes"
        expression: "!request.name.startsWith('system:')"

這條規則會在 API Server 層直接過濾請求,只要變更的資源名稱以 system: 開頭,就排除呼叫 Webhook,確保 GKE 核心元件在任何時候都不會被攔截。

這個做法保留:

  • 不需要犧牲 failurePolicy: Fail 帶來的嚴格檢查
  • 只排除系統層級資源,使用者層級的資源仍然受到完整規範

但如果你有既有的 Kubernetes CI/CD 部署流程,並透過 ArgoCD 或 Helm 等自動化工具部署 Webhook 服務,務必留意這條規則可能會在後續部署時被覆寫。

方案二:暫時將 failurePolicy 調整為 Ignore

如果你的環境暫時無法導入 CEL 匹配條件 (例如 Kubernetes 版本較舊,或來不及完整測試 CEL 規則),可以採取折衷做法:把該 Webhook 規則的 failurePolicy 暫時從 Fail 改為 Ignore

webhooks:
  - name: validate.your-webhook-name
    failurePolicy: Ignore   # 升級期間暫時改為 Ignore

設定 Ignore 後,API Server 在 Webhook 呼叫失敗或無法連線時會直接跳過驗證,不會拒絕原本的請求。這讓 GKE 在升級過程中能順利完成系統資源的變更。

⚠️ 重要提醒:升級完成且確認 GKE 狀態穩定後,務必把 failurePolicy 改回 Fail,以恢復原本的安全限制。長期使用 Ignore 會讓 Webhook 形同虛設。

方案三:暫時刪除干擾的 Webhook 配置

如果升級情況非常緊急、且沒有時間逐步調整 Webhook 規則,最後的手段是直接刪除阻擋升級的 Webhook 配置:

# 備份並刪除 MutatingWebhookConfiguration
kubectl get MutatingWebhookConfiguration [NAME] -o yaml > mutating-webhook-config.yaml
kubectl delete MutatingWebhookConfiguration [NAME]

# 備份並刪除 ValidatingWebhookConfiguration
kubectl get ValidatingWebhookConfiguration [NAME] -o yaml > validating-webhook-config.yaml
kubectl delete ValidatingWebhookConfiguration [NAME]

刪除通常可以解決 GKE 無法正常升級的問題。但該方法較具破壞性,在 Webhook 被刪除的這段時間內,叢集會失去原本的 Webhook 功能。

升級成功後,需手動把 Webhook 配置重新套用回去,否則 Webhook 基本上形同虛設。

簡易比較

方案 破壞程度 附註
CEL matchConditions 排除 保留 Webhook 設定的最佳實踐,但如果你有既有的 Kubernetes CI/CD 部署流程,須留意避免規則在後續自動化部署時被覆寫
failurePolicy: Ignore 中等 無法立刻導入 CEL 時升級期間暫時降級
刪除 Webhook 配置 完全移除 Webhook 設定,屬於最後手段

總結

Admission Webhook 是維護叢集安全的重要屏障,但設計不當時也很容易造成 GKE 升級阻塞。要避免日後再次踩坑,在撰寫與套用 Webhook 時可以考慮:

  1. 主動排除 Google 託管的命名空間 (例如 kube-systemkube-node-lease),避免 Webhook 干擾系統元件。3
  2. 利用 CEL matchConditions 排除 system: 前綴的資源,確保升級期間必要的操作不會被錯誤攔截。
  3. 謹慎設定 failurePolicy:當策略為 Fail 時,務必確保 Webhook 服務具備高可用性,否則一次中斷就可能阻擋關鍵操作。

希望本文能為你提供有價值的觀點與實用工具,協助你更有效地管理 GKE 環境中的必要工作。

📧 訂閱 EasonTechTalk:獲得技術洞察與實戰分享

如果你對了解雲端技術和相關趨勢有興趣,歡迎訂閱 EasonTechTalk 電子報以取得更新,讓我們一起在技術路上持續精進!

參考資源

Eason Cao
Eason Cao Eason is an engineer working at FANNG and living in Europe. He was accredited as AWS Professional Solution Architect, AWS Professional DevOps Engineer and CNCF Certified Kubernetes Administrator. He started his Kubernetes journey in 2017 and enjoys solving real-world business problems.
comments powered by Disqus