題目與適用場景
叢集節點啟動後,kubelet 可能已回報 Ready,但 GPU 驅動、CNI、儲存外掛或本地代理尚未可用。若排程器過早放置 Pod,工作負載會反覆失敗或隱性降級。請設計 Node Readiness Controller:根據節點條件宣告額外前置要求,在滿足要求前阻止排程,並支援節點生命週期中的持續失效。
這道題適合平台工程、SRE 與 Kubernetes 控制器職位。公開的 Kubernetes 面試資料把節點 NotReady、污點/容忍和 Pending Pod 排查列為情境題;官方 Node Readiness Controller 專案則將 NodeReadinessRule、自動污點管理、bootstrap-only/continuous 模式和 dry run 定義為目前的實作方向。本文討論一套可稽核的設計推導,不聲稱它是公司真題。
面試官考察重點
面試官關注你能否把「節點 Ready」與「節點適合某類工作負載」分開。強回答會定義條件來源、規則範圍、污點冪等、控制器重啟復原、狀態可觀測性和誤封鎖保護。
普通回答只會寫一個 DaemonSet 檢查腳本。強回答會解釋為何條件回報與決策控制解耦,如何區分 bootstrap-only 和 continuous,如何在 dry run 中估算影響,並處理條件過期、控制器分區和多個規則互相衝突。
回答前需要釐清的問題
- 目標是只保護新節點啟動,還是節點運行中驅動失效也要停止新排程?這決定 enforcement mode 和復原動作。
- 條件由誰產生:Node Problem Detector、設備外掛、CNI Agent 還是自訂 DaemonSet?來源不可信時需要身分與時間戳驗證。
- 規則要求全部條件 AND,還是允許任一條件通過?GPU、網路和儲存通常需要不同節點池與規則。
- 誤判時是阻止新 Pod,還是驅逐既有 Pod?前者可回滾,後者需要更高證據與獨立的驅逐策略。
30 秒回答框架
「我會把節點就緒拆成條件回報、規則評估和污點執行三層。NodeReadinessRule 選擇節點並宣告必須為 True 的條件,控制器根據 bootstrap-only 或 continuous 模式新增或移除 NoSchedule 污點。所有寫入都要冪等、可觀測並支援 dry run;規則和條件狀態保存於 API Server,重啟後可重建。發布時先只記錄影響,再小範圍啟用;故障時停止寫入或回滾規則,避免一個控制器問題擴散成全域不可排程。」
分步驟深入解答
先定義邊界。控制器不主動探測 GPU 或網路,它消費 Node Condition;現有 Node Problem Detector、設備外掛或自訂 Agent 負責回報事實。這能重用既有探針,也能把「檢查失敗」與「是否允許排程」分開。條件至少包含類型、狀態、更新時間、來源和觀測代次,過期條件不能繼續授權。
規則模型包含節點選擇器、條件集合、目標污點和 enforcement mode。官方專案要求所有指定條件滿足時才解除污點,並支援按節點標籤選擇異質節點。bootstrap-only 在初始化條件滿足後停止該規則的重新評估;continuous 則在運行期間任一關鍵條件轉為 False 時重新加上污點。前者適合預拉映像或硬體初始化,後者適合持續依賴的設備或網路健康。
控制迴圈讀取規則、節點和條件,計算期望污點,再用資源版本執行條件更新。寫入必須使用冪等鍵和衝突重試:只管理自己宣告的污點,不刪除其他控制器或管理員添加的污點。多個規則若寫入相同污點鍵但語意不同,應由准入驗證拒絕;否則一個規則恢復會錯誤解除另一個規則的保護。
故障路徑需要明確。條件回報者停止工作時,預設拒絕還是預設允許是產品選擇:關鍵安全依賴可採用 fail-closed,低風險初始化可採用帶過期時間的 fail-open。控制器失聯時不應自動清空既有污點;恢復後重新對帳。節點被刪除或標籤改變時,規則狀態要標記為不適用,避免舊狀態阻塞新節點。
可觀測性至少包含每條規則的匹配節點數、條件缺失/過期數、期望與實際污點差異、從條件變為 True 到可排程的延遲,以及被 gate 的 Pod 數。狀態要給出失敗條件和最後一次評估時間,事件中避免列印憑證或設備敏感資訊。控制面負載可按節點和規則建立佇列,合併短時間內的條件變化,避免每個心跳都寫 API Server。
發布策略從 dry run 開始。官方專案的 dry run 只記錄計畫動作並更新規則狀態,不實際新增污點;透過觀察受影響節點與 Pending Pod 數量後,再對一個節點池啟用。回滾順序是暫停新規則評估、保留既有保護污點、修復條件來源,最後按規則重新對帳;不能直接批次刪除所有 NoSchedule 污點。
替代方案是給每個工作負載加 nodeSelector、使用 Pod schedulingGates,或由啟動腳本手動加污點。工作負載選擇器適合少量明確消費者,但難以涵蓋未來 Pod;Pod gate 保護的是 Pod,而本題要保護節點;手動腳本缺乏統一狀態與復原。控制器適合異質節點和多團隊共用叢集,代價是引入 CRD、控制迴圈和新的故障域。
高品質示範回答
我會把它設計成只負責「是否允許新排程」的宣告式控制器。條件由 Node Problem Detector、設備外掛或 CNI Agent 寫入節點狀態,控制器不重複探測。規則選擇節點,列出必須為 True 的條件、目標 NoSchedule 污點和模式。啟動階段用 bootstrap-only,例如 GPU 驅動和網路代理都準備好後解除污點;持續依賴用 continuous,條件變壞就重新加上污點,但不自動驅逐既有 Pod。
控制器只管理自己帶 owner 標記的污點,使用資源版本和衝突重試保證冪等;同一污點鍵的衝突規則由驗證拒絕。規則狀態顯示匹配節點、缺失或過期條件、實際污點差異和最後評估時間。部署先 dry run,比較預計受影響節點與 Pending Pod,再對一個節點池灰度。控制器失聯時保留既有保護,恢復後重新對帳;回滾暫停評估並修復條件來源,避免用一個命令清空全叢集污點。
常見錯誤
- 錯誤表現 → 讓控制器自己 SSH 節點檢測所有元件;失敗原因 → 失去 Kubernetes 條件生態和統一權限邊界;修正方法 → 讓專用 Agent 回報條件,控制器只負責規則評估和污點。
- 錯誤表現 → 用
continuous處理一次性初始化;失敗原因 → 初始化完成後仍持續抖動,造成不必要的不可排程;修正方法 → 明確選擇bootstrap-only,記錄完成狀態。 - 錯誤表現 → 看到規則就刪除同鍵污點;失敗原因 → 可能刪除管理員或其他控制器的安全保護;修正方法 → 使用 owner 標記、衝突驗證和只更新自有欄位。
- 錯誤表現 → 控制器重啟後清空全部污點;失敗原因 → 故障窗口會把工作負載放到未就緒節點;修正方法 → 保留現況,恢復後執行有版本控制的對帳。
追問及應對
如果條件回報者停止更新,你選擇 fail-open 還是 fail-closed?
按依賴風險分級。GPU 驅動、加密模組或跨區域網路等關鍵依賴採用帶過期時間的 fail-closed,寧可暫時少排程;低風險的一次性初始化可在已有成功記錄和短 TTL 下 fail-open。無論選哪種,都要把「條件未知」與「條件為 False」分開計量,避免把監控缺失偽裝成健康。
如果一個節點同時匹配兩個規則,而兩個規則使用相同污點鍵怎麼辦?
在准入或規則編譯階段拒絕語意衝突,要求不同規則使用不同鍵,或明確一個聚合規則擁有該鍵。控制器保存每個規則的期望狀態,只有所有擁有者都滿足解除條件時才允許移除聚合污點;不能由最後一次成功評估的規則單獨刪除它。
如何證明 dry run 沒有把叢集容量打穿?
把規則匹配節點、現有可排程容量、Pod 資源請求和拓撲分布放到同一份影響報告。先在一個節點池模擬,觀察被 gate 的 Pod、自動擴容佇列和排程延遲,再逐步擴大。若報告顯示關鍵工作負載沒有可用餘量,先調整節點池或規則,不進入強制模式。
規則要持續監控節點時,為什麼不直接驅逐既有 Pod?
節點不可接收新 Pod 與既有 Pod 是否安全繼續運行是兩個判斷。NoSchedule 只阻止新增放置,保留業務連續性;驅逐需要獨立的 PDB、優雅終止和資料安全策略。只有條件明確表示現有工作負載也不安全時,才由專門的驅逐控制器在另一套門檻下處理。