系統設計面試:如何設計 Kubernetes Pod 級資源伸縮控制器?
題幹與適用場景
一個多容器 Pod 包含 API 代理、快取 sidecar 和批次 worker。團隊想根據延遲與佇列長度動態調整 Pod 級 CPU/記憶體預算,避免刪除 Pod 帶來中斷。請設計控制器,說明觀測、決策、/resize 子資源寫入、狀態追蹤、並發保護、不可行請求和回滾。
面試官考察點
- 能否區分期望資源、實際資源和容器重啟策略。
- 能否設計冪等 reconcile、狀態條件和 deferred/infeasible 重試。
- 能否處理 Pod 級預算與容器級請求的邊界及安全護欄。
- 能否把指標、權限、故障恢復和漸進式發布納入系統設計。
回答前需要釐清的問題
- 叢集版本是否支援 Pod-level resize,feature gates 和 kubectl 版本是多少?
- 控制器調整的是 CPU、記憶體,還是同時調整 Pod 與容器資源?
- 哪些容器允許重啟,哪些容器有不可中斷的連線或狀態?
- 目標是節省成本、維持延遲 SLO,還是應對突發佇列?
30 秒回答
我會把控制器做成事件驅動的冪等 reconcile:讀取指標與 Pod 當前狀態,按預算、SLO、節點容量和變更冷卻時間計算目標,然後透過 /resize 子資源提交小步變更。狀態中記錄 observedGeneration、PodResizePending、PodResizeInProgress、Infeasible 或 Deferred 原因;重試使用指數退避並受優先級和最大次數限制。CPU 與記憶體分開評估,尊重容器 resizePolicy,並在記憶體風險或指標回歸時恢復上一個已驗證預算。所有寫入都帶 owner、審計和權限邊界。
分步驟深入解答
定義資源模型與安全邊界
Pod 級 spec.resources 是聚合預算,容器級 requests/limits 仍影響最低保障和重啟行為。控制器維護每個工作負載的最小、最大、步長、冷卻時間和 SLO 護欄,拒絕超出命名空間配額或節點容量的請求。
採集指標並計算目標
使用延遲、佇列長度、CPU throttling、記憶體工作集和 OOM 事件。採用視窗聚合與滯後,避免單次尖峰造成抖動;目標值必須同時滿足 Pod 級預算與容器請求總和約束。
透過 resize 子資源提交冪等更新
控制器只更新期望狀態,並攜帶資源版本和 owner。示例請求:
spec:
resources:
requests:
cpu: "300m"
memory: "512Mi"
limits:
cpu: "1"
memory: "1Gi"實際 API 呼叫使用 /resize 子資源並檢查 resourceVersion;衝突時重新讀取後再 reconcile,不能覆蓋使用者或其他控制器的更新。
追蹤條件與重試優先級
讀取 PodResizePending、PodResizeInProgress 等條件和 observedGeneration。Infeasible 表示節點或約束無法滿足,Deferred 表示暫時延後;控制器應保留原因、下次時間和嘗試次數。重試按工作負載優先級、QoS 和等待時長排序,避免低優先級請求餓死。
處理容器重啟策略
Pod 級調整可能觸發容器級 resizePolicy。CPU 變化通常可不重啟,記憶體變化可能要求重啟;控制器必須逐容器檢查策略、連線和狀態。不可重啟容器的請求進入保護佇列,不能把 Pod 級成功誤報成業務無中斷。
觀測、回滾與高可用
記錄目標值、實際值、條件轉移、重啟次數、延遲 SLO、記憶體峰值和失敗原因。控制器多副本透過 leader election 工作,佇列按 Pod key 去重。發現錯誤預算、OOM 或 SLO 回歸時,回滾到最後一個穩定目標,並暫停自動伸縮等待人工確認。
高品質示範回答
我會設計一個冪等 reconcile 控制器:讀取延遲、佇列、throttling、工作集和 OOM 指標,結合最小/最大預算、步長、冷卻時間、節點容量和命名空間配額計算目標。透過 /resize 子資源提交帶 resourceVersion 的小步更新,衝突則重新讀取。狀態記錄 observedGeneration、Pending、InProgress、Infeasible、Deferred 原因和重試時間;重試按優先級和等待時長排程。逐容器檢查 resizePolicy,記憶體變更可能重啟時先驗證連線與狀態。控制器多副本 leader election,指標和審計可追蹤;SLO 回歸或 OOM 就恢復最後穩定預算並暫停自動化。
常見錯誤
- 直接修改 Pod spec 並假設 kubelet 會按預期套用,忽略
/resize子資源。 - 只看期望資源,不讀取實際資源和狀態條件。
- 無冷卻和滯後,導致資源抖動和頻繁重啟。
- 把 Deferred 當作失敗永久丟棄,或無限重試 Infeasible。
- 忽略容器級
resizePolicy和記憶體重啟風險。 - 沒有 resourceVersion、owner 和 RBAC,覆蓋其他控制器的更新。
追問及應對
如何避免兩個控制器互相覆蓋?
使用明確 owner、resourceVersion、欄位管理和單一寫入責任;衝突時重新讀取並合併意圖,不做無條件覆蓋。
Infeasible 與 Deferred 如何區分?
Infeasible 表示目前約束無法滿足,應調整目標或等待容量;Deferred 表示暫時延遲,應按條件和優先級重試並保留原因。
什麼時候暫停自動伸縮?
出現 OOM、SLO 連續回歸、條件長期不變、重啟超限或觀測資料失真時暫停,並保留人工恢復入口。
如何證明控制器沒有造成中斷?
關聯 resize 條件、容器 restartCount、連線錯誤、延遲和佇列指標,按容器策略分層比較;不能只看 Pod phase 仍為 Running。