如何快速重新平衡Pod所在的Worker Node - 使用 PowerShell Core

如何快速重新平衡Pod所在的Worker Node - 使用 PowerShell Core

在一個標準 3 台 Node (1 Control Plane + 2 Worker Node)的 Kubernetes 叢集上,在進行維護(drain)之後很容易出現 Pods 集中在某一台 Worker Node 的情況。這在測試區還好,測試區更新極快,通常沒幾天就能回到平衡(Balance)的狀態。正式區就比較麻煩,正式區更新速度不比測試區,因此,Pods 集中在某一台 Worker Node 情況容易時間不短,這會造成特定 Worker Node 資源吃重的情況。針對維護過後,Pods 會集中在某一台 Worker 上,我想改進這一點。

研究過後,方向大致有二種:

  • 增加一台 Worker Node 的 VM,目前只有 Node 1, Node 2,增加 Node 3,這樣在某一台 Node 維護時,能保持複數 Node 是運作中,這樣就不會有集中問題。
  • kubernetes-sigs/descheduler 導入自動分配 Pod 的功能。好處當然就是自動化,也不用再增加 Node。

上面對於我們需求而言都太過複雜,我想要更簡單的方式,我快速手刻了一版 PowerShell (疑,你不知道 PowerShell 現在跨平台嗎?)

# 請先執行 pwsh 進入 PowerShell
# 1. 找出所有非 1/1 的 Deployments
kubectl get deployments.apps

# 2. 整理為 Data Array
$deploys = @('prd-a-deployment','prd-b-deployment','prd-c-deployment','prd-d-deployment','prd-e-deployment','prd-f-app','prd-g-deployment','prd-h-deployment','prd-i-deployment','prd-j-deployment','prd-k-deployment','prd-l-deployment','prd-m-deployment','prd-n-deployment','prd-o-deployment','prd-p-deployment')

# 3. 進行 Re-scaling
foreach ($deploy in $deploys){
    Write-Host "Re-scaling $deploy"
    kubectl scale --replicas 1 deployment/$deploy
    Start-Sleep -s 1
    kubectl scale --replicas 2 deployment/$deploy
    Start-Sleep -s 1
}

透過 kubectl scale 我們快速去觸發重新分配 Pods 的工作。當然,上面程式還是很難看的 v1,離我心目中的自動化還有一段。例如:

$ kubectl get deployments.apps
NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
# ...
prd-z-deployment                     2/2     1            1           1d

我們取得 Deployments 清單裡包含了兩個重要的資訊 NAMEREADY,可以讓我上面的 foreach 更完美。進一步的 v2 版,可請參考 如何對Docker Swarm叢集特定服務所有複本容器執行命令裡面提到的技巧。

例如,我能極快把指令的 std-out 轉換為物件來工作:

PS /home/brucechen> $data = ConvertFrom-Csv $(kubectl get deployments.apps)
PS /home/brucechen> $data

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
-------------------------------------------------------------------------
prd-a-deployment                2/2     2            2           75d
prd-b-deployment                2/2     2            2           7d19h
prd-c-deployment                2/2     2            2           13h
prd-d-deployment                2/2     2            2           9d

PS /home/brucechen> $data[0]

NAME                                 READY   UP-TO-DATE   AVAILABLE   AGE
-------------------------------------------------------------------------
doc-a-deployment               1/1     1            1           12d

這裡還需要一些其他 kubectl 的 Output(-o) 技巧來做事先資訊的整理,因為上面轉換出來的物件還只是一行一行文字物件。例如:

# 透過 jsonpath 來整理 Output
kubectl get deployments.apps -o jsonpath="{range .items[*]}{.metadata.name},{.spec.replicas}{'\n'}{end}"
# 透過 Go Template 來整理 Output
kubectl get deployments.apps -o go-template='{{range .items}}{{.metadata.name}}{{printf ","}}{{.spec.replicas}}{{printf "\n"}}{{end}}'
# 透過 custom-columns 來整理 Output
kubectl get deployments.apps -o custom-columns=Name:.metadata.name,Replicas:.spec.replicas

這裡和參考文章一樣會碰到到沒有 Title 的問題,沒有抬頭會造成 ConvertFrom-Csv 轉換後的物件不正確。

我以 Go Template 為例:

PS /home/brucechen> $data = ConvertFrom-Csv $(kubectl get deployments.apps -o go-template='{{printf "Name,Replicas\n"}}{{range .items}}{{.metadata.name}}{{printf ","}}{{.spec.replicas}}{{printf "\n"}}{{end}}')
PS /home/brucechen> $data[0]

Name                   Replicas
----                   --------
doc-a-deployment       1

PS /home/brucechen> $data[0].Name
doc-a-deployment
PS /home/brucechen> $data[0].Replicas
2

這裡因為我們抬頭很簡單,我快速利用 {{printf "Name,Replicas\n"}} 來製作我們所需要的 CSV 抬頭,接下來就能正常進行物件操作了。其實到這裡,V2 應該已經完成 80% 了。

$data = ConvertFrom-Csv $(kubectl get deployments.apps -o go-template='{{printf "Name,Replicas\n"}}{{range .items}}{{.metadata.name}}{{printf ","}}{{.spec.replicas}}{{printf "\n"}}{{end}}')

foreach ($deploy in $data) {
    if ($deploy.Replicas -gt 1) {
        Write-Host "Re-scaling $($deploy.Name)"
        kubectl scale --replicas 1 deployment/$($deploy.Name)
        Start-Sleep -s 1
        kubectl scale --replicas $deploy.Replicas deployment/$($deploy.Name)
        Start-Sleep -s 1
    }
}

Start-Sleep 是怕指令跑太快,減速一下。

你要改寫成 Bash Shell 也不是不行,但當我手上就有個物件式PowerShell 這把好武器(工商連結一下),實在不想碰偏文字式的 Bash Shell。

回到主題,我們用了幾行 Script 來完成我們的重新分配 Pod 到 Node 的工作,並且由於 kubectl scale 過程還是保有運作中的 Pod(--replicas 1),使用者是完全無感系統有任何異動,雖然沒 descheduler 那麼功能強大,但我們僅僅只有維護後有這樣的需求,這個自製的半自動的指令碼已經非常滿足我們的情境了。

沒有留言:

張貼留言

感謝您的留言,如果我的文章你喜歡或對你有幫助,按個「讚」或「分享」它,我會很高興的。