iT邦幫忙

2024 iThome 鐵人賽

DAY 23
2

Kubernetes 的部署邏輯 (⁎⁍̴̛ᴗ⁍̴̛⁎)


當使用者透過 kubectl 在 Kubernetes Cluster 中建立 Pod 時,要將 Pod 部署在哪一個 Node 上會經過不少判斷邏輯,負責執行篩選的元件就是 Scheduler

Scheduler 會透過監測機制(Watch)來發現 Cluster 中已經建立,但尚未調度到 Node 上的 Pod,並會判斷部署相關設定和現有資源,選擇最適合的 Node 來運行。

  • 如果 scheduler 發生異常或無法作業,Pod 會停留在 pending 狀態
  • 已經建立的 Pod 不可修改 Node,需刪除並在其他 Node 重啟

https://ithelp.ithome.com.tw/upload/images/20240924/20168437BndQrWia8v.png

kube-scheduler

kube-scheduler 是 Kubernetes 預設的 Scheduler,屬於 Control Plane 的一部分,在設計上允許自訂。
(可自行編寫一個組件去替換原有的 kube-scheduler )

運作機制:
由於 Containter/Pod 本身的需求不同,kube-scheduler 會過濾掉不滿足條件的 Node,其中滿足使用條件的 Node 稱為 feasible nodes,再從中擇優去運行 Pod。雖然也可以使用 API 為 Pod 指定要運行的 Node(*註1),但實務上並不常這樣應用,多半是特殊情況。

如何透過 API 指定 Pod 要部署的 Node

curl --header "Content-Type:application/json" --request POST --data '{"apiVerison":"v1","kind":"Binding","metadata":{"name":"nginx"},"target":{"apiVersion":"v1","kind":"Node","name":"<nodeName>"}}' http://$SERVER/api/v1/namespaces/<space_name>/pods/$PODNAME/binding

yaml format

apiVerison: v1 
kind: Binding 
metadata: 
  name: nginx 
target: 
  apiVersion: v1 
  kind: Node 
  name: <nodeName>

kube-scheduler 的決策方式大概分為兩階段:

篩選 (Filtering)

Predicates :條件,kube-scheduler 會對 Node 進行篩選,可以理解為過濾條件。

  • PodFitsResources
    檢查 Node 是否符合 Pod 的 資源需求,如:是否有足夠的 CPU、Memory 等資源。當過路之後會產出一個可用列表,若列表空的,則代表目前的 Pod 無法建立。
  • PodFitsHostPorts
    確認 Pod 指定的 port 在 Node 上是否可用,若是已被佔用則過濾掉此 Node
  • PodFitsHost
    檢查 Pod 是否已設定 nodeName,若有指定要部署的 Node 則過濾掉名稱不符者
  • NoVolumeZoneConflict
    當 Pod 有綁定到持久儲存(PersistentVolume)的時候,會確保 Pod 被部署到該儲存所在的可用區,避免跨區存取產生的效能問題。
  • MatchNodeSelector
    判斷 Node 上的標籤(Label)是否與 Pod 設定的 nodeSelector 相符。
  • Taint Toleration
    檢查 Pod 是否能被部署到有 Taints屬性的 Node 上。
  • CheckNodeMemoryPressure
    如果 Node 內部的記憶體幾乎都已經使用掉,Scheduler 會避免將 Pod 部署在該 Node 上。
  • CheckNodeDiskPressure
    CheckNodeMemoryPressure 類似,檢查磁碟使用量,若已經趨近滿載則會避免使用這個 Node 來做部署。

擇優 (Scoring)

Priorities:優先度,kube-scheduler 會對預選階段篩選出的 Node 進行評分,根據優先級來選擇最合適的節點。

  • LeastRequestedPriority
    優先選擇資源充足的 Node,剩餘資源越多,得分愈高。
    這個方式可以使 Pod 在 Cluster 中的分佈較為平均,也避免部分 Node 資源過載。
  • BalancedResourceAllocation
    優先選擇資源分配較為平衡的 Node,避免資源浪費。
    (如果 Node 上部署了很多需要 CPU 但不消耗 Memory 的 Pod,就是容易形成資源浪費)
  • NodeAffinityPriority
    依據 NodeAffinity,相符的 Node 加分(優先度提高)。
  • Taint Toleration
    Predicates 為過濾條件,但在Priorities是加分項。如 Node 上有與 Pod (Toleration) 對應的 Taint,優先度提高。
  • InterPodAffinityPriority
    若 Node 符合 Pod 的 nodeAffinity 設定,會優先部署。
  • SpreadPriority
    當有多個 Pod 相同時,Scheduler 會盡量將其分散,使相同的 Pod 在 Cluster 中可以分佈得相渡均勻。
  • ImageLocalityPriority
    優先選擇已經有暫存 image 的 Node,可減少下載時間提升部署效率。
    這個策略只考慮「是否有暫存」,而不考慮實際的下載時間和資源,所以在其他條件都一致的情況下,可能會使相同的 Pod 都被部署在同一個 Node 上。
    如要避免這個情況,可以考慮幾種做法:
    - 關閉 kube-scheduler 的 ImageLocalityPriority
    - 調低 ImageLocalityPriority 的權重

上述只列出比較常見的規則,詳細內容可參考官方文件:Scheduling, Preemption and Eviction

Binding

Scheduler 在 Cluster 中找到所有的 feasible nodes,然後根據一連串的運算判斷出最適合運行的 Node,最後終於選定要部署的 Node,就會將這個結果發送給 kube-apiserver

這個行為就稱為綁定。

最後,當 Pod 部署完成後會由 kubelet 持續監控 Pod 狀態,並回報給 kube-apiserver。
如果 Pod 屬於 Service 的一部分,則會由 kube-proxy 更新 Node 轉送規則,才得以將服務對外提供。

(續上圖,從 kube-apiserver 收到 Node 資訊開始)
https://ithelp.ithome.com.tw/upload/images/20240924/20168437ErxDACnMUc.png

小結

Scheduler 做決策時需要考慮各項因素,除了資源需求、策略限制,還要考慮 Cluster 的整體平衡。有時可能會見到邏輯衝突的判斷標準,但它們在 Kubernetes 中的權重可能不相同,反之,也可以透過修改這些權重,調整出符合實際情況需要的部署策略。


*註1

使用 nodeName 指定 Pod 要運行的 Node

設定方式如下:

apiVersion: v1  
kind: Pod  
metadata:   
  namespace: <namespace-name>  
  name: <pod-name>
spec:  
  nodeName: <要指定的 Node 名稱> 
  containers:  
    - name: nginx-pod
      image: nginx:1.11.9

使用這個設定需要特別留意,一旦指定了 nodeName,就等於不做 Scheduler 的調度策略, Kubernetes 會直接嘗試將 Pod 部署在指定的 Node 上。
此時一旦 Node 資源不足,就很容易出現 out of CPU 或者 out of Memory 錯誤。


上一篇
Day-22 ExternalName Service
下一篇
Day-24 Taints & Tolerations
系列文
Kubernetes圖解筆記26
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言