前言
正常維護工作節點的流程
當我們要進行 K8S 節點維護時往往需要執行 kubectl drain
, 等待節點上的 Pod 被驅逐後再進行維護動作。
命令列如下:
kubectl drain NODE
待節點排空後再進行維護操作, 核心升級等。
存在問題嗎?
drain
命令有一個問題, 他不會考慮資源所定義的 UpdateStrategy, 而直接強制驅逐或刪除 Pod, 這樣就會導致 Deployment 或 StatefulSet 資源的 Pod 達不到所設定的策略數.
思考一個案例
- 有一個 Deployment 資源, 它使用瞭如下配置
副本數為 3, 採用了滾動更新, 並且先啟動完成一個 Pod 後再進行舊 Pod 的刪除(最大不可用為0,最小可用為2).replicas: 2 strategy: rollingUpdate: maxSurge: 1 maxUnavailable: 0 type: RollingUpdate
- 當下叢集有 2 個 worker 節點
意味著, 其中一個節點被排程了 2 個 Pod, 其中一個節點被排程了 1 個 Pod.
假設 node1 執行著 pod1 和 pod3, node2 執行著 pod2. - 這時候 drain node1, 會出現 Deployment 只有一個 Pod 可用
更糟糕的情況
Deployment 的 Pod 全部執行在需要維護的節點上, 這時候執行 drain
那將是一個災難, 這個 Deployment 在新的Pod啟動之前它無法在對外提供服務了, 恢復的時間取決於新 Pod 的啟動速度。
kubectl-safe-drain 專案
GitHub: https://github.com/majian159/kubectl-safe-drain
一個 kubectl 外掛, 用於更為安全的排空節點。
對於 Deployment 和 StatefulSet 資源會根據其配置的更新策略先將Pod排程到其它可用節點。
邏輯和原理
- 先將需要排空的節點標記為不可排程 (kubectl cordon)
- 在找到該節點上的 Deployment 和 StatefulSet 資源
- 修改 Deployment 和 StatefulSet 的 PodTemplate, 讓K8S根據對應的更新策略重新部署Pod, 這時候需要排空的節點不可被排程, 從而達到先將排空節點中的Pod安全重建到其它節點的邏輯。
目前支援安全遷移的資源
- Deployment
- StatefulSet
效果
首先我們有一個 Deployment 配置如下
spec:
replicas: 2
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1
maxUnavailable: 0
操作前有兩個可用 Pod
執行 safe-drain
後
檢視 Deployment 變化過程
檢視 Pod 變化過程
流程簡述
從 Deployment watch 的資訊中可見最小 Ready 數沒有小於 2, 從 Pod watch 的資訊中可見 kind-worker2 上承載了 2 個準備就緒的 nginx Pod, 也就是說 nginx 從 kind-worker 安全的移動到了 kind-worker2 節點上。
與 PDB (Pod Disruption Budget) 有什麼區別?
PDB 只會保障 Pod 不被驅逐, 而不會幫助它在其它可用節點上重建。
使用了 PDB 後能防止服務不可用的尷尬情況,但它還是需要人工手動遷移 Pod。
理想的情況是搭配 PDB 使用, 防止嚴苛情況下服務不可用的問題。
安裝
二進位制檔案
Linux
curl -sLo sdrain.tgz https://github.com/majian159/kubectl-safe-drain/releases/download/v0.0.1-preview1/kubectl-safe-drain_0.0.1-preview1_linux_amd64.tar.gz \
&& tar xf sdrain.tgz \
&& rm -f sdrain.tgz \
&& mv kubectl-safe-drain /usr/local/bin/kubectl-safe_drain
macOS
curl -sLo sdrain.tgz https://github.com/majian159/kubectl-safe-drain/releases/download/v0.0.1-preview1/kubectl-safe-drain_0.0.1-preview1_darwin_amd64.tar.gz \
&& tar xf sdrain.tgz \
&& rm -f sdrain.tgz \
&& mv kubectl-safe-drain /usr/local/bin/kubectl-safe_drain
Windows
基於 Krew
curl -O https://raw.githubusercontent.com/majian159/kubectl-safe-drain/master/krew.yaml \
&& kubectl krew install --manifest=krew.yaml \
&& rm -f krew.yaml
使用
kubectl safe-drain NODE
# safe-drain並沒有呼叫 drain命令, 而是利用了 SchedulingDisabled 機制
# 所以如有需要可以繼續使用 drain 命令來確保節點被驅逐
kubectl drain NODE
TODO
- 考慮節點親和力和節點選擇器的情況
- 輸出更為友好的提示資訊
寫在最後
該專案部分程式碼源於 kubectl 專案。