解決 GKE 升級卡住的隱形殺手:Admission Webhook
在管理 Google Kubernetes Engine (GKE) 叢集的日常中,定期升級版本是維持安全性、修補漏洞與取得新功能的必要工作。但實際上可能會在 Logs Explorer 裡看到讓人摸不著頭緒的錯誤訊息 (例如 Internal error 或 DeployPatch failed)1,升級流程就這樣卡住,遲遲無法完成。
這類錯誤的根本原因,通常是由 GKE 中安裝的第三方或自訂 Admission Webhook (例如 Gatekeeper、Kyverno 等) 無意間攔截了系統層級的資源變更,進而中斷整個升級流程。
本文可作為〈管理 Kubernetes Webhook 故障:從診斷到解決方案〉的延伸案例研究,說明為什麼 Webhook 不當設定會成為 GKE 升級的潛在問題,並依照對生產環境干擾程度由低到高,提供三種實際可行的解法。
為什麼 Webhook 會導致 GKE 升級失敗?
GKE 在升級控制平面 (UpdateMaster) 時,會建立、更新一系列系統專用的資源 (例如 ClusterRoles 或 ClusterRoleBindings),同時也會確保新版本的控制平面能正常運作。
如果你的 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),ValidatingWebhookConfiguration 與 MutatingWebhookConfiguration 支援 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 時可以考慮:
- 主動排除 Google 託管的命名空間 (例如
kube-system、kube-node-lease),避免 Webhook 干擾系統元件。3 - 利用 CEL
matchConditions排除system:前綴的資源,確保升級期間必要的操作不會被錯誤攔截。 - 謹慎設定
failurePolicy:當策略為Fail時,務必確保 Webhook 服務具備高可用性,否則一次中斷就可能阻擋關鍵操作。
希望本文能為你提供有價值的觀點與實用工具,協助你更有效地管理 GKE 環境中的必要工作。
📧 訂閱 EasonTechTalk:獲得技術洞察與實戰分享
如果你對了解雲端技術和相關趨勢有興趣,歡迎訂閱 EasonTechTalk 電子報以取得更新,讓我們一起在技術路上持續精進!
參考資源