首頁>技術>

本文永久連結: https://www.xtplayer.cn/kubernetes/scheduler/influencing-kubernetes-scheduler-decisions/

哪個節點具有可用資源?

選擇適當的節點時,排程程式會檢查每個節點是否有足夠的資源滿足 Pod 排程。如果您已經宣告 Pod 所需的 CPU 和記憶體量(透過請求和限制),排程程式將使用以下公式來計算給定節點上的可用記憶體:

排程可用記憶體 = 節點總記憶體 - 已預留記憶體

保留記憶體是指:

Kubernetes 守護程序使用的記憶體,例如:kubeletcontainerd(一種容器執行時)。節點作業系統使用的記憶體,例如:核心守護程式。

透過使用此方程式,排程程式可確保由於過多 Pod 競爭消耗節點所有可用資源,從而導致節點資源耗盡引起其他系統異常,比如系統觸發 oom。

影響排程過程

在不受使用者影響的情況下,排程程式在將 Pod 排程到節點時執行以下步驟:

排程程式檢測到已建立新的 Pod,但尚未將其分配給節點;它檢查 Pod 需求,並相應地篩選出所有不合適的節點;根據權重將剩下的節點進行排序,權重最高的排在第一位;排程程式選擇排序列表中的第一個節點,然後將 Pod 分配給它。

通常,我們會讓排程程式自動選擇合適的節點(前提是 Pod 配置了資源請求和限制)。但是,有時可能需要透過強制排程程式選擇特定節點或手動向多個節點新增權重來影響此決策,以使其比其他節點更適合 Pod 排程。

讓我們看看我們如何做到這一點:

節點名稱

在最簡單的節點選擇配置中,您只需在 .spec.nodeName 中指定其名稱,就可以強制 Pod 在指定節點上執行。例如,以下 YAML 定義 Pod 強制在 app-prod01 上進行排程:

apiVersion: v1kind: Podmetadata: name: nginxspec: containers: - name: nginx   image: nginx nodeName: app-prod01

請注意,由於以下原因,此方法是最簡單但最不推薦的節點選擇方法:

如果由於某種原因無法找到指定名稱的節點(例如,更改了主機名),則 Pod 將不會執行。如果該節點沒有 Pod 執行所需的資源,則 Pod 會執行失敗,並且也不會將該 Pod 排程到其他節點。這會導致 Pods 與它們的節點緊密耦合,這是一種糟糕的設計實踐。節點選擇器

覆蓋排程程式決策的第一個最簡單的方法是使用 Pod 定義或 Pod 模板(如果使用的是 Deployments 之類的控制器)中的 .spec.nodeSelector 引數。nodeSelector 接受 一個或多個 鍵-值對標籤,這些 鍵-值對 標籤必須在節點設定才能正常的排程 Pod。假設您最近購買了兩臺配備 SSD 磁碟的計算機,您希望資料庫相關所有的 Pod 在 SSD 支援的節點上進行排程,以獲得最佳的資料庫效能。DB Pod 的 Pod YAML 可能如下所示:

apiVersion: v1kind: Podmetadata: name: dbspec: containers: - name: mongodb   image: mongo nodeSelector:   disktype: ssd

根據該定義,當排程程式選擇合適的 Pod 分配節點時,將僅考慮具有 disktype=ssd 標籤的節點。

此外,您可以使用自動分配給節點的任何內建標籤來操縱選擇決策。例如,節點的主機名(kubernetes.io/hostname),體系結構(kubernetes.io/arch),作業系統(kubernetes.io/os)等均可用於節點選擇。

節點親和性

當您需要選擇特定的節點來執行我們的 Pod 時,節點選擇非常有用。但是選擇節點的方式是有限的,只有與所有定義的標籤匹配的節點才被考慮用於 Pod 放置。Node Affinity 透過允許您定義硬節點和軟節點需求,為您提供了更大的靈活性。硬性要求必須在要選擇的節點上匹配。另一方面,軟條件允許您為具有特定標籤的節點增加更多權重,以使它們在列表中的位置比對等節點更高。沒有軟需求標籤的節點將不被忽略,但它們權重更小。

讓我們舉個例子:我們的資料庫是 I/O 密集型的。我們需要資料庫 Pods 始終在 SSD 支援的節點上執行。此外,如果 Pod 部署在區域 zone1 或 zone2 中的節點上,因為它們在物理上更靠近應用程式節點,那麼它們的延遲會更短。滿足我們需求的 Pod 定義可能如下所示:

apiVersion: v1kind: Podmetadata: name: dbspec: affinity:   nodeAffinity:     requiredDuringSchedulingIgnoredDuringExecution:       nodeSelectorTerms:       - matchExpressions:         - key: disk-type           operator: In           values:           - ssd     preferredDuringSchedulingIgnoredDuringExecution:     - weight: 1       preference:         matchExpressions:         - key: zone           operator: In           values:           - zone1           - zone2 containers: - name: db   image: mongo

nodeAffinity 使用以下引數來定義硬性要求和軟性要求:

requiredDuringSchedulingIgnoredDuringExecution:部署 DB Pod 時,節點必須具有 disk-type=ssd。preferredDuringSchedulingIgnoredDuringExecution: 當對節點進行排序時,排程器會給予標籤為zone=zone1zone=zone2的節點更高的權重。如果有disk-type=ssdzone=zone1的節點,則優先選擇 disk-type=ssd 且無 zone 標籤的節點或指向其他 zone 的節點。權重可以是 1 到 100 之間的任意值,權重號賦予匹配節點相對於其他節點更高的權重。數字越大,權值越高。

注意,在進行選擇時,節點親和性允許您在選擇目標節點上應該存在(或不存在)哪些標籤時擁有更多的自由。在本例中,我們使用 In 運算子定義了多個標籤,目標節點上存在任何一個標籤即可。其他運算子是 NotIn、Exists、doesnoexistists、Lt(小於)和 Gt(大於)。值得注意的是,NotIn 和 doesnot existist 實現了所謂的節點反親和性。

節點親和性和節點選擇器不是互斥的,它們可以共存於同一個定義檔案中。但是,在這種情況下,節點選擇器和節點親和性硬要求必須匹配。

Pod 親和性

節點選擇器和節點親和性(以及反親和性)幫助我們影響排程器關於在何處放置 Pods 的決策。但是,它只允許您基於節點上的標籤進行選擇。它不關心 Pod 本身的標籤。您可能需要在以下情況下根據 Pod 標籤進行選擇:

需要將所有中介軟體 Pod 放在同一個物理節點上,與那些具有 role=front 標籤的 Pod 一起,以減少它們之間的網路延遲。作為一種安全最佳實踐,我們不希望中介軟體 Pod 與處理使用者身份驗證的 Pod 共存(role=auth)。這不是一個嚴格的要求。

如您所見,這些要求不能用節點選擇器或親和性來滿足,因為在選擇過程中不考慮 Pod 標籤——只考慮節點標籤。

為了滿足這些需求,我們使用 Pod 親和性和反親和性。本質上,它們的工作方式與節點親和性和反親和性相同。必須滿足硬性要求來選擇目標節點,而軟條件增加了擁有所選節點的機會(權重),但不是嚴格要求。讓我們舉個例子:

apiVersion: v1kind: Podmetadata: name: middlewarespec: affinity:   podAffinity:     requiredDuringSchedulingIgnoredDuringExecution:     - labelSelector:         matchExpressions:         - key: role           operator: In           values:           - frontend       topologyKey: kubernetes.io/hostname   podAntiAffinity:     preferredDuringSchedulingIgnoredDuringExecution:     - weight: 100       podAffinityTerm:         labelSelector:           matchExpressions:           - key: role             operator: In             values:             - auth         topologyKey: kubernetes.io/hostname containers: - name: middleware   image: redis

在上面的 Pod 定義檔案中,我們對硬性要求和軟性要求進行了如下設定:

requiredDuringSchedulingIgnoredDuringExecution:我們的 Pod 必須在具有標籤為 app-front 的 Pod 節點上排程。

preferredDuringSchedulingIgnoredDuringExecution:我們的 Pod 不應該(但它可以)被排程到執行帶有標籤為 role=auth 的 Pod 的節點上。與節點親和性一樣,soft requirement 將權重從 1 設定為 100,以增加節點相對於其他節點的機率。在我們的示例中,軟需求被放置在 poantiaffinity 中,導致執行具有標籤為 role=auth 的 Pod 的節點在排程程式做出決定時被選中的可能性更小。

topologyKey 用於對規則將應用於哪個領域做出更細粒度的決策。topologyKey 接受一個標籤鍵,該標籤鍵必須出現在選擇過程中考慮的節點上。在我們的示例中,我們使用了自動填充的標籤,該標籤在預設情況下自動新增到所有節點,並引用節點的主機名。但是您可以使用其他自動填充的標籤,甚至是自定義的標籤。例如,您可能需要只在具有 rack 或 zone 標籤的節點上應用 Pod 親和規則。

關於 IgnoredDuringExecution 的註釋

您可能已經注意到,硬需求和軟需求都有 IgnoredDuringExecution 字尾。這意味著在做出排程決策之後,排程程式將不會嘗試更改已經放置的 Pods,即使條件發生了變化。例如,根據節點親和性規則,將一個 Pod 排程到一個具有標籤為 app=prod 的節點上。如果該標籤被更改為 app=dev, 舊 Pod 不會被終止,並在另一個有 app=prod 標籤的節點上啟動新的 Pod。這個行為在將來可能會改變,以允許排程程式在部署後繼續檢查節點和 Pod 的關聯性(和反關聯性)規則。

汙點與容忍

在某些場景中,您可能希望阻止將 Pod 排程到特定節點。可能您正在執行測試或掃描此節點以查詢威脅,而您不希望應用程式受到影響。節點反親和性可以實現這一目標。但是,這是一個重大的管理負擔,因為您需要向部署到叢集的每個新 Pod 新增反關聯規則。對於這種場景,您應該使用汙點。

當一個節點配置了汙點時,除非 Pod 能夠容忍這種汙點,否則不能對它排程 Pod。容忍只是一個與汙點匹配的鍵-值對。讓我們舉個例子來說明:

需要對主機 web01 進行汙染,以使其不接受更多 Pod。taint 命令如下:

kubectl taint nodes web01 locked=true:NoSchedule

上面的命令在名為 web01 的節點上放置了一個汙點,該節點具有以下屬性:

標籤 locked=true,該標籤必須配置在想要執行在該節點的 Pod 上。NoSchedule 的汙點型別。汙點型別定義了應用汙點的行為,它有以下幾種可能:NoSchedule:此節點一定不要排程。PreferNoSchedule:儘量不要排程,類似軟親和性。NoExecute:不僅不會排程,還會驅逐 Node 上已有的 Pod。

在帶有汙點的節點上,Pod 的定義檔案可能如下所示:

apiVersion: v1kind: Podmetadata: name: mypodspec: containers: - name: mycontainer   image: nginx tolerations: - key: "locked"   operator: "Equal"   value: "true"   effect: "NoSchedule"

讓我們仔細看看這個定義的容忍部分:

為了具有正確的容忍,我們需要指定鍵(locked),值(true)和運算子。運算子可以是兩個值之一:Equal:當使用 equal 運算子時,鍵、值和汙染效果必須與節點的汙染匹配。Exists:在使用 exists 運算子時,不需要將汙點與容忍匹配,只需匹配建即可。如果使用 Exists 運算子,則可以忽略容忍鍵、值和效果。具有這種容忍的 Pod 可以被排程到具有任何受汙點的節點。

注意,在 Pod 上放置容忍並不能保證它被部署到受汙染的節點上。它只允許行為發生。如果要強制 Pod 加入受汙染的節點,還必須像前面討論的那樣向其定義新增節點親和性。

TL; DR

在節點上自動放置 Pod 是 Kubernetes 誕生的原因之一。作為管理員,只要您對 Pod 需求做出了良好的宣告,您就不用擔心節點是否有足夠的空閒資源來執行這些 Pod。但是,有時您必須手動干預和覆蓋系統關於在何處放置 Pods 的決定。在本文中,我們討論了幾種方法,在決定部署 Pods 時,您可以透過這些方法對特定節點的排程器產生更大的影響。讓我們快速回顧一下這些方法:

節點名稱:透過將節點的主機名新增到 Pod 定義的 .spec.nodeName 引數中,可以強制此 Pod 在該特定節點上執行。排程程式使用的任何選擇演算法都將被忽略。不建議使用此方法。節點選擇器:透過在節點上放置指定的標籤,Pod 可以使用 nodeelector 引數指定一個或多個鍵-值標籤,這些標籤必須存在於目標節點上才能被選中以執行 Pod。推薦使用這種方法,因為它增加了很多靈活性,並建立了松耦合的 node-Pod 關係。節點親和性:在選擇應該考慮哪個節點來排程特定的 Pod 時,這種方法增加了更多的靈活性。使用節點親和性,Pod 可能嚴格要求在具有特定標籤的節點上排程。它還可以透過影響排程程式為特定節點賦予更大的權重來表示對特定節點的某種程度的偏好。Pod 親和性和反親和性:當 Pod 與同一節點上的其他 Pod 共存(或不共存)時,可以使用此方法。Pod 親和性允許將 Pod 部署在具有特定標籤的 Pod 執行的節點上。相反,Pod 可能會強制排程程式不將其排程到具有特定標籤的 Pod 執行的節點上。汙點和容忍:在這種方法中,您不需要決定將 Pod 排程到哪些節點,而是決定哪些節點是否接受 所有 Pod 排程,或者只接受選定的 Pod 排程。透過汙染一個節點,排程程式將不考慮將這個節點作為任何 Pod 的排程節點,除非 Pod 配置了容忍。容忍由鍵、值和受染的效果組成。

原文連結:https://www.magalix.com/blog/influencing-kubernetes-scheduler-decisions

11
最新評論
  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • 指令碼小子的資訊收集