Concepts - cluster-administration - node-shutdown
在 Kubernetes (K8s) 叢集的生命週期中,節點 (Node) 停機是不可避免的常態。無論是計畫性的核心升級、硬體維護,還是突發性的斷電、硬體故障,我們都必須有一套成熟的應對策略,以確保叢集上的應用程式能盡可能地不受影響。
本篇文章將從「計畫性」和「非計畫性」兩個維度,探討 K8s 中處理節點關閉的各種機制。
場景一:計畫性維護 (手動優雅關機)
當您需要對某個節點進行可預期的維護時(例如:升級作業系統、更換硬體),最推薦、也最安全的方式是使用 kubectl drain
指令。
drain
指令會優雅地將節點上的 Pod 驅逐,它的工作流程如下:
graph TD A[開始: `kubectl drain <node-name>`] --> B{1. Cordon Node}; B --> C{2. Evict Pods}; C --> D[等待所有 Pod <br> 在其他節點上重建完成]; D --> E[完成: 節點已清空,可以安全關機]; subgraph "B: Cordon Node" B1["將節點標記為 `unschedulable`"] B2["(不再接受新的 Pod 調度)"] end subgraph "C: Evict Pods" C1["遵循 PodDisruptionBudgets (PDB)"] C2["優雅地終止 (graceful termination) Pod"] C3["(尊重 `terminationGracePeriodSeconds`)"] end B --> B1 & B2 C --> C1 & C2 & C3
操作指令:
|
|
關於
drain
的更詳細介紹,可以參考 節點維護 (Maintaining a Node) 一文。
場景二:預期內關機 (自動優雅關機)
有些關機事件雖然是自動觸發,但系統有機會提前通知 kubelet
。例如:
- UPS 偵測到斷電,發送關機訊號。
- 雲端上的 Spot 實例即將被回收。
在這種情況下,我們可以設定 kubelet
,讓它在收到系統的關機訊號後,執行一個優雅的 Pod 終止流程。
Kubelet 優雅關機設定
這個功能預設是關閉的。您需要修改 kubelet
的設定檔來啟用它。
設定檔範例 (/etc/kubernetes/kubelet.conf
):
|
|
這個設定的運作流程如下:
kubelet
偵測到節點即將關機。- 它會給予一個總共
30s
的寬限期。 - 在前
20s
(30s - 10s
),kubelet
會嘗試終止所有非關鍵的普通 Pod。 - 在最後的
10s
,kubelet
會嘗試終止被標記為關鍵的 Pod (Critical Pods),例如系統自帶的 CNI、CSI 等插件。
場景三:突發性故障 (非優雅關機)
最糟糕的情況是節點在沒有任何預警下直接「失聯」,例如:硬體故障、網路中斷。
在這種情況下,kubelet
完全沒有機會去優雅地終止 Pod。這會導致一些問題,特別是對於有狀態的應用 (StatefulSet
):
- Pod 卡在
Terminating
狀態:Control Plane 因為無法從失聯的kubelet
收到 Pod 已終止的確認,所以會一直等待。 - Volume 無法分離:由於 Pod 未被正常刪除,它所掛載的持久化儲存 (PV) 也會一直處於
Attached
狀態,導致新的 Pod 無法在其他節點上掛載同一個 PV。
手動介入:out-of-service
Taint
為了解決這個僵局,K8s 提供了一個「最終手段」。如果叢集管理者確認一個節點已經永久性地無法恢復,可以手動為該節點加上一個特殊的 Taint:
|
|
當 kube-controller-manager
偵測到這個 Taint 後,它會理解為「這個節點上的 Pod 可以被強制刪除了」。此時,它會:
- 強制刪除卡在
Terminating
狀態的 Pod。 - 強制分離 (detach) 與該節點關聯的 VolumeAttachments。
這使得 StatefulSet 的 Pod 能夠在其他健康的節點上被重新建立,並重新掛載其所需的 PV,從而恢復服務。
總結來說,熟悉 K8s 處理節點停機的各種機制,並為您的叢集做好適當的設定(例如啟用 kubelet
優雅關機、為重要應用設定 PDB),是保障叢集穩定性和應用高可用性的重要一環。