天天看點

如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後

前言

正常維護工作節點的流程

當我們要進行 K8S 節點維護時往往需要執行

kubectl drain

, 等待節點上的 Pod 被驅逐後再進行維護動作。

指令行如下:

kubectl drain NODE           

待節點排空後再進行維護操作, 核心更新等。

存在問題嗎?

drain

指令有一個問題, 他不會考慮資源所定義的 UpdateStrategy, 而直接強制驅逐或删除 Pod, 這樣就會導緻 Deployment 或 StatefulSet 資源的 Pod 達不到所設定的政策數.

思考一個案例

  1. 有一個 Deployment 資源, 它使用了如下配置
    replicas: 2
     strategy:
         rollingUpdate:
         maxSurge: 1
         maxUnavailable: 0
     type: RollingUpdate           
    副本數為 3, 采用了滾動更新, 并且先啟動完成一個 Pod 後再進行舊 Pod 的删除(最大不可用為0,最小可用為2).
  2. 當下叢集有 2 個 worker 節點

    意味着, 其中一個節點被排程了 2 個 Pod, 其中一個節點被排程了 1 個 Pod.

假設 node1 運作着 pod1 和 pod3, node2 運作着 pod2.

  1. 這時候 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排程到其它可用節點。

邏輯和原理

  1. 先将需要排空的節點标記為不可排程 (kubectl cordon)
  2. 在找到該節點上的 Deployment 和 StatefulSet 資源
  3. 修改 Deployment 和 StatefulSet 的 PodTemplate, 讓K8S根據對應的更新政策重新部署Pod, 這時候需要排空的節點不可被排程, 進而達到先将排空節點中的Pod安全重建到其它節點的邏輯。

目前支援安全遷移的資源

  1. Deployment
  2. StatefulSet

效果

首先我們有一個 Deployment 配置如下

spec:
    replicas: 2
strategy:
    type: RollingUpdate
    rollingUpdate:
        maxSurge: 1
        maxUnavailable: 0           

操作前有兩個可用 Pod

如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後
如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後

執行

safe-drain

如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後

檢視 Deployment 變化過程

如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後

檢視 Pod 變化過程

如何優雅的維護 K8S Worker 節點前言kubectl-safe-drain 項目安裝使用TODO寫在最後

流程簡述

從 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

https://github.com/majian159/kubectl-safe-drain/releases/download/v0.0.1-preview1/kubectl-safe-drain_0.0.1-preview1_windows_amd64.tar.gz

基于 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

  1. 考慮節點親和力和節點選擇器的情況
  2. 輸出更為友好的提示資訊

寫在最後

該項目部分代碼源于 kubectl 項目。