Pod的排程機制

misakivv發表於2024-08-09

目錄
  • 一、Pod排程概述
  • 二、Pod排程策略實現方式
  • 三、kube-scheduler排程
    • 1、kube-scheduler排程的流程
    • 2、過濾階段
    • 3、打分階段
    • 4、kube-scheduler 排程示例
      • 4.1、建立 Deployment 資源清單
      • 4.2、應用Deployment
      • 4.3、檢視被kube-scheduler自動排程的Pod
  • 四、nodeName排程
    • 1、建立Pod資源清單
    • 2、應用Pod
    • 3、檢視Pod的排程情況
    • 4、驗證容器是否正常啟動並在執行中
  • 五、nodeSelector排程
    • 1、分別給兩個node新增標籤
    • 2、檢視node節點標籤
    • 3、建立Pod資源清單
    • 4、應用Pod
    • 5、檢視Pod排程情況
    • 6、刪除標籤
    • 7、檢視Pod狀態
    • 8、把Pod刪除後重新建立
    • 9、describe檢視events
  • 六、汙點taint與容忍度tolerations排程
    • 1、概述
    • 2、汙點
      • 2.1、汙點型別
      • 2.2、Master汙點
      • 2.3、檢視k8s叢集中Master節點的汙點
      • 2.4、檢視系統級別Pod的容忍度
      • 2.5、定義汙點
      • 2.6、新增汙點
      • 2.7、檢視汙點
      • 2.8、建立 Pod 資源清單
      • 2.9、應用Pod並檢視Pod排程情況
      • 2.10、刪除汙點
    • 3、容忍度
      • 3.1、如何定義
      • 3.2、為node打上不同等級的汙點
        • 新增一個worker節點
      • 3.3、檢視叢集中節點的汙點
      • 3.4、建立容忍NoSchedule級別汙點的Pod
        • 3.4.1、應用Pod並檢視排程情況
      • 3.5、建立容忍PreferNoSchedule級別汙點的Pod
        • 3.5.1、應用Pod並檢視排程情況
      • 3.6、建立容忍NoExecute級別汙點的Pod
        • 3.6.1、應用Pod並檢視排程情況
      • 3.7、建立沒有容忍度的Pod
        • 3.7.1、應用Pod並檢視排程情況
      • 3.8、清除用於測試汙點
  • 七、NodeAffinity 節點親和性排程
    • 1、概述
    • 2、兩種規則
    • 3、定義節點親和性規則注意點
    • 4、節點硬親和性
      • 4.1、節點硬親和性配置模板
      • 4.2、引數解析
      • 4.3、給 Node 節點新增標籤
      • 4.4、排程到同時有environment=sit和role=db標籤的節點(存在)
      • 4.5、排程到同時有environment=prod和role=db標籤的節點(不存在)
      • 4.6、排程到具有 environment=sit 標籤但不具有 role=db 標籤的節點
      • 4.7、排程到具有environment 標籤的節點(無論其值)
    • 5、節點軟親和性
      • 5.1、節點軟親和性配置模板
      • 5.2、引數解析
      • 5.3、示例
        • 5.3.1、分析
        • 5.3.2、應用Deploymet檢視排程情況
    • 6、清除 Node 標籤
  • 八、PodAffinity Pod親和性排程
    • 1、概述
    • 2、分類
    • 3、Pod 硬親和性
      • 3.1、Pod 硬親和性配置模板
      • 3.2、引數解析
      • 3.3、為 Node 打上不同地區的標籤
      • 3.4、建立 Pod 資源清單(使用 Pod 硬親和性)
      • 3.5、檢視排程結果
      • 3.6、建立帶有特定標籤的 Pod
      • 3.7、檢視排程結果
    • 4、Pod 軟親和性
      • 4.1、Pod 軟親和性配置模板
      • 4.2、引數解析
      • 4.3、建立帶有 app=nginx 和 app=busybox 標籤的 Pod。
      • 4.4、建立 Pod 軟親和性的 Deployment
      • 4.5、應用標籤為 cache 和 db 的 Pod
      • 4.6、應用帶有 Pod 軟親和性的 Deployment
      • 4.7、檢視Pod排程情況
  • 九、Pod Anti-Affinity Pod反親和性排程
    • 1、概述
    • 2、分類
    • 3、Pod 硬反親和性
      • 3.1、Pod 硬反親和性配置模板
      • 3.2、建立帶有硬反親和性規則的Deployment
      • 3.3、應用Deployment檢視Pod排程情況
    • 4、Pod軟反親和性
      • 4.1、Pod 軟反親和性配置模板
      • 4.2、建立帶有 Pod 軟反親和性的 Deployment
      • 4.3、應用 Deployment 檢視排程情況

一、Pod排程概述

API Server 接受客戶端提交Pod物件建立請求後的操作過程中,有一個重要的步驟就是由排程器程式 kube-scheduler 從當前叢集中選擇一個可用的最佳節點來接收並執行它,通常是預設的排程器 kube-scheduler 負責執行此類任務。

對於每個待建立的Pod物件來說,排程過程通常分為兩個階段:過濾 --> 打分,過濾階段用來過濾掉不符合排程規則的Node,打分階段建立在過濾階段之上,為每個符合排程的Node進行打分,分值越高則被排程到該Node的機率越大。

二、Pod排程策略實現方式

  • nodeName(直接指定Node主機名)
  • nodeSelector (節點選擇器,為Node打上標籤,然後Pod中透過nodeSelector選擇打上標籤的Node)
  • 汙點taint與容忍度tolerations
  • NodeAffinity 節點親和性
  • Pod Affinity Pod親和性
  • Pod Anti-Affinity Pod反親和性

三、kube-scheduler排程

kube-scheduler 是Kubernetes 叢集的預設排程器,並且是叢集控制面(master)的一部分。對每一個新建立的Pod或者是未被排程的Pod,kube-scheduler會選擇一個最優的Node去執行這個Pod。

然而,Pod內的每一個容器對資源都有不同的需求,而且Pod本身也有不同的資源需求。因此,Pod在被排程到Node上之前,根據這些特定的資源排程需求,需要對叢集中的Node進行一次過濾。

在一個叢集中,滿足一個Pod排程請求的所有Node稱之為可排程節點。如果沒有任何一個Node能滿足Pod的資源請求,那麼這個Pod將一直停留在未排程狀態直到排程器能夠找到合適的Node。

排程器先在叢集中找到一個Pod的所有可排程節點,然後根據一系列函式對這些可排程節點打分,然後選出其中得分最高的Node來執行Pod。之後,排程器將這個排程決定通知給kube-apiserver,這個過程叫做繫結。

在做排程決定是需要考慮的因素包括:單獨和整體的資源請求、硬體/軟體/策略限制、親和以及反親和要求、資料局域性、負載間的干擾等等。

1、kube-scheduler排程的流程

kube-scheduler給一個pod做排程選擇包含兩個步驟

1.過濾(Predicates 預選策略)2.打分(Priorities 優選策略)

過濾階段:過濾階段會將所有滿足 Pod 排程需求的 Node 選出來。例如,PodFitsResources 過濾函式會檢查候選 Node 的可用資源能否滿足 Pod 的資源請求。在過濾之後,得出一個 Node 列表,裡面包含了所有可排程節點;通常情況下,這個 Node 列表包含不止一個 Node。如果這個列表是空的,代表這個 Pod 不可排程。

打分階段:在過濾階段後排程器會為 Pod 從所有可排程節點中選取一個最合適的 Node。根據當前啟用的打分規則,排程器會給每一個可排程節點進行打分。最後,kube-scheduler 會將 Pod 排程到得分最高的 Node 上。如果存在多個得分最高的 Node,kube-scheduler 會從中隨機選取一個。

整體流程如下圖所示:

image-20240809005101411

2、過濾階段

  1. PodFitsHostPorts:檢查Node上是否不存在當前被排程Pod的埠(如果被排程Pod用的埠已被佔用,則此Node被Pass)。
  2. PodFitsHost:檢查Pod是否透過主機名指定了特性的Node (是否在Pod中定義了nodeName)
  3. PodFitsResources:檢查Node是否有空閒資源(如CPU和記憶體)以滿足Pod的需求。
  4. PodMatchNodeSelector:檢查Pod是否透過節點選擇器選擇了特定的Node (是否在Pod中定義了nodeSelector)。
  5. NoVolumeZoneConflict:檢查Pod請求的卷在Node上是否可用 (不可用的Node被Pass)。
  6. NoDiskConflict:根據Pod請求的卷和已掛載的卷,檢查Pod是否合適於某個Node (例如Pod要掛載/data到容器中,Node上/data/已經被其它Pod掛載,那麼此Pod則不適合此Node)
  7. MaxCSIVolumeCount::決定應該附加多少CSI卷,以及是否超過了配置的限制。
  8. CheckNodeMemoryPressure:對於記憶體有壓力的Node,則不會被排程Pod。
  9. CheckNodePIDPressure:對於程序ID不足的Node,則不會排程Pod
  10. CheckNodeDiskPressure:對於磁碟儲存已滿或者接近滿的Node,則不會排程Pod。
  11. CheckNodeCondition:Node報告給API Server說自己檔案系統不足,網路有寫問題或者kubelet還沒有準備好執行Pods等問題,則不會排程Pod。
  12. PodToleratesNodeTaints:檢查Pod的容忍度是否能承受被打上汙點的Node。
  13. CheckVolumeBinding:根據一個Pod併發流量來評估它是否合適(這適用於結合型和非結合型PVCs)。

3、打分階段

當過濾階段執行後滿足過濾條件的Node,將進行打分階段。

  1. SelectorSpreadPriority:優先減少節點上屬於同一個 Service 或 Replication Controller 的 Pod 數量
  2. InterPodAffinityPriority:優先將 Pod 排程到相同的拓撲上(如同一個節點、Rack、Zone 等)
  3. LeastRequestedPriority:節點上放置的Pod越多,這些Pod使用的資源越多,這個Node給出的打分就越低,所以優先排程到Pod少及資源使用少的節點上。
  4. MostRequestedPriority:儘量排程到已經使用過的 Node 上,將把計劃的Pods放到執行整個工作負載所需的最小節點數量上。
  5. RequestedToCapacityRatioPriority:使用預設資源評分函式形狀建立基於requestedToCapacity的 ResourceAllocationPriority。
  6. BalancedResourceAllocation:優先平衡各節點的資源使用。
  7. NodePreferAvoidPodsPriority:根據節點註釋對節點進行優先順序排序,以使用它來提示兩個不同的 Pod 不應在同一節點上執行。scheduler.alpha.kubernetes.io/preferAvoidPods。
  8. NodeAffinityPriority:優先排程到匹配 NodeAffinity (Node親和性排程)的節點上。
  9. TaintTolerationPriority:優先排程到匹配 TaintToleration (汙點) 的節點上
  10. ImageLocalityPriority:儘量將使用大映象的容器排程到已經下拉了該映象的節點上。
  11. ServiceSpreadingPriority:儘量將同一個 service 的 Pod 分佈到不同節點上,服務對單個節點故障更具彈性。
  12. EqualPriority:將所有節點的權重設定為 1。
  13. EvenPodsSpreadPriority:實現首選pod拓撲擴充套件約束。

4、kube-scheduler 排程示例

預設配置使用的就是kube-scheduler排程元件,下面例子啟動三個Pod,看分別被分配到哪個Node。

4.1、建立 Deployment 資源清單

cat > scheduler-pod.yaml << EOF
apiVersion: apps/v1
kind: Deployment
metadata:
  name: scheduler-deploy
spec:
  replicas: 3
  selector:
    matchLabels:
      app: scheduler-pod
  template:
    metadata:
      labels:
        app: scheduler-pod
    spec:
      containers:
      - image: busybox:latest
        name: scheduler-pod
        command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF

4.2、應用Deployment

kubectl apply -f scheduler-pod.yaml

image-20240805132004036

4.3、檢視被kube-scheduler自動排程的Pod

kubectl get pods -o wide | grep scheduler

image-20240805132727817

四、nodeName排程

nodeNamed這種排程方式比較簡單,我們可以指定Pod在哪臺Node上進行執行,透過spec.nodeName引數來指定Node主機名稱即可。

1、建立Pod資源清單

cat > nodeName-pod.yaml << EOF
apiVersion: v1
kind: Pod
metadata:
  name: nodename-pod
spec:
#指定該Pod執行在k8s-node2節點上
  nodeName: k8s-node2
  containers:
  - image: busybox:latest
    name: nodename-containers
    command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF

2、應用Pod

kubectl apply -f nodeName-pod.yaml

image-20240805140808550

3、檢視Pod的排程情況

nodename-pod被繫結在了k8s-node2上

kubectl get pods -o wide | grep nodename

image-20240805140957819

4、驗證容器是否正常啟動並在執行中

kubectl logs nodename-pod

image-20240805144303586

五、nodeSelector排程

nodeSelector用於將Pod排程到匹配Label的Node上,所以要先給node打上標籤,然後在Pod配置清單中選擇指定Node的標籤。先給規劃node用途,然後打標籤

例如將兩臺node劃分給不同團隊使用:

1、分別給兩個node新增標籤

k8s-node1給開發團隊(dev)用,k8s-node2給運維團隊(ops)用

kubectl label node k8s-node1 team=dev

kubectl label node k8s-node2 team=ops

image-20240805141358899

2、檢視node節點標籤

kubectl get nodes --show-labels | grep team

image-20240805142017343

3、建立Pod資源清單

cat <<EOF > nodeSelector-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nodeselector-pod
spec:
  nodeSelector:                      #指定標籤選擇器
    team: dev                #label指定開發團隊的label
  containers:
  - image: busybox:latest
    name: nodeselector-containers
    command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF

4、應用Pod

kubectl apply -f nodeSelector-pod.yaml

5、檢視Pod排程情況

kubectl get pods -o wide | grep nodeselector

image-20240805145459330

6、刪除標籤

kubectl label node k8s-node1 team-

kubectl label node k8s-node2 team-

image-20240805145758201

7、檢視Pod狀態

可以看到刪除標籤後pod正常執行

kubectl get pods -o wide | grep nodeselector

image-20240805150353826

8、把Pod刪除後重新建立

會發現該pod一直在等待中,找不到清單中配置標籤的Node

kubectl get pods -w | grep nodeselector

image-20240805150814936

9、describe檢視events

事件:3個節點都不匹配 node selector

kubectl describe pods nodeselector-pod | grep -A 5 Events

image-20240805151058727

六、汙點taint與容忍度tolerations排程

1、概述

汙點(taint)是定義在Node之上的鍵值型的資料,用於讓節點拒絕將Pod排程執行於其上,除非該Pod物件具有接納Node汙點的容忍度。而容忍度(tolerations)是定義在Pod物件的鍵值型屬性資料,用於配置其可容忍的Node汙點,而且排程器僅能將Pod物件排程至其能夠容忍該Node汙點的Node之上。

image-20240805151854833

  • Pod-A具備k8s-node01汙點的容忍度,所以能夠被排程器排程至k8s-node01上。
  • Pod-A不完全具備k8s-node02汙點的容忍度,所以不能被排程至k8s-node02。
  • Pod-A雖然具備容忍度,但同樣可以排程至沒有汙點的k8s-node03節點上。
  • Pod-B自身沒有容忍度,所以只能被排程至沒有汙點的k8s-node03節點上。

2、汙點

2.1、汙點型別

汙點定義在nodeSpec中,容忍度定義在PodSpec中,他們都是鍵值型資料,但又都額外支援一個效果(effect)標記,語法格式為 “key=value:effect” ,其中key和value的用法及格式與資源註解資訊相似,而effect則用於定義對Pod物件的排斥等級,它主要包含以下三種排斥型別。

  • NoSchedule :為Node新增汙點等級為NoSchedule,除容忍此汙點的Pod以外的其它Pod將不再被排程到本機。
  • PreferNoSchedule:為Node新增汙點等級為PreferNoSchedule,不能容忍此汙點的Pod物件儘量不要排程到當前節點,如果沒有其它節點可以供Pod選擇時,也會接受沒有容忍此汙點的Pod物件。
  • NoExecute:為Node新增汙點等級為NoExecute,能容忍此汙點的Pod將被排程到此節點,而且節點上現存的Pod物件因節點使用了NoExceute等級的汙點,則現存的Pod將被驅趕至其它滿足條件的Node(除非現存Pod容忍了當前節點的汙點)。

2.2、Master汙點

以kubeadm部署的kubernetes叢集,其Master節點將自動新增汙點資訊以阻止不能容忍此汙點的Pod物件排程至此節點,因此使用者可以手動建立Pod來容忍Master的汙點。

2.3、檢視k8s叢集中Master節點的汙點

kubectl describe nodes k8s-master | grep Taints

image-20240805152903352

不過,有些系統級別應用,如 kube-proxy 或者 kube-flannel 等也是以Pod形式執行在叢集上,這些資源在建立時就新增上了相應的容忍度以確保他們被 DaemonSet 控制器建立時能夠排程至 Master 節點執行一個例項。

2.4、檢視系統級別Pod的容忍度

kubectl get pods -n kube-system -o name | cut -d'/' -f2 | xargs -I {} kubectl describe pod {} -n kube-system | grep "Tolerations:"

image-20240805160111271

另外,這類Pod是構成Kubernetes系統的基礎且關鍵的元件,它們甚至還定義了更大的容忍度,從下面某kube-flannel例項的容忍度定義來看,它還能容忍那些報告了磁碟壓力或記憶體壓力的節點,以及未就緒的節點和不可達的節點,以確保它們能在任何狀態下正常排程至叢集節點上執行。

kubectl get pods -n kube-system | grep flannel

kubectl describe pods kube-flannel-ds-2rzg6 -n kube-system | grep -A 10 Tolerations:

image-20240805162137562

  • :NoSchedule op=Exists

    • 表示該 Pod 可以容忍任何未指定鍵值的汙點,但 Kubernetes 不會在具有此類汙點的節點上排程新 Pod。
  • node.kubernetes.io/disk-pressure:NoSchedule op=Exists

    • 表示當節點處於磁碟壓力狀態時,該 Pod 不會被排程到該節點上。如果 Pod 已經在節點上執行,則它將繼續執行,但不會被重新排程到其他節點。
  • node.kubernetes.io/memory-pressure:NoSchedule op=Exists

    • 表示當節點處於記憶體壓力狀態時,該 Pod 不會被排程到該節點上。如果 Pod 已經在節點上執行,則它將繼續執行,但不會被重新排程到其他節點。
  • node.kubernetes.io/network-unavailable:NoSchedule op=Exists

    • 表示當節點的網路不可用時,該 Pod 不會被排程到該節點上。如果 Pod 已經在節點上執行,則它將繼續執行,但不會被重新排程到其他節點。
  • node.kubernetes.io/not-ready:NoExecute op=Exists

    • 表示當節點的狀態變為 NotReady 時,Kubernetes 會嘗試驅逐該 Pod。這意味著如果節點的狀態變為 NotReady,那麼 Pod 將被終止,除非它能夠容忍此汙點。
  • node.kubernetes.io/pid-pressure:NoSchedule op=Exists

    • 表示當節點處於 PID 壓力狀態時,該 Pod 不會被排程到該節點上。如果 Pod 已經在節點上執行,則它將繼續執行,但不會被重新排程到其他節點。
  • node.kubernetes.io/unreachable:NoExecute op=Exists

    • 表示當節點變得不可達時,Kubernetes 會嘗試驅逐該 Pod。這意味著如果節點變得不可達,那麼 Pod 將被終止,除非它能夠容忍此汙點。
  • node.kubernetes.io/unschedulable:NoSchedule op=Exists

    • 表示當節點被標記為 Unschedulable 時,該 Pod 不會被排程到該節點上。如果 Pod 已經在節點上執行,則它將繼續執行,但不會被重新排程到其他節點。

2.5、定義汙點

kubectl taint nodes <node-name> <key>=<value>:<effect>

node-name: 指定需要打汙點的Node主機名 key=value:指定汙點的鍵值型資料 effect:為汙點的等級

key名稱長度上線為253個字元,可以使用字母或者數字開頭,支援字母、數字、連線符、點號、下劃線作為key或者value。value最長是 63個字元。汙點通常用於描述具體的部署規劃,它們的鍵名形式如 node-typenode-rolenode-projectnode-geo 等。

2.6、新增汙點

為k8s-node2新增汙點,汙點程度為NoSchedule,type=calculate為標籤

kubectl taint node k8s-node2 type=calculate:NoSchedule

image-20240805201558028

2.7、檢視汙點

這樣的話我們建立Pod就不會被排程到打上汙點的k8s-node2的節點上

kubectl describe node k8s-node2 | grep Taints

image-20240805201712935

2.8、建立 Pod 資源清單

cat <<EOF > taint-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: taint-deploy
spec:
  replicas: 2
  selector:
    matchLabels:
      app: taint-pod
  template:
    metadata:
      labels:
        app: taint-pod
    spec:
      containers:
      - image: busybox:latest
        name: taint-pod
        command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF

2.9、應用Pod並檢視Pod排程情況

可以看到 k8s-master1k8s-node2 因為有汙點所以不會被分配 Pod。兩個 Pod 均被分配到 k8s-node1

kubectl get pods -o wide | grep taint

image-20240805202534954

2.10、刪除汙點

刪除汙點之需要指定標籤的 key 及汙點程度

kubectl taint node k8s-node2 type:NoSchedule-

image-20240805203550376

3、容忍度

3.1、如何定義

Pod物件的容忍度可以透過其spec.tolerations欄位進行新增,根據使用的運算子不同,主要有兩種可用的形式:

  • Equal 運算子: 當使用 Equal 運算子時,Pod 的容忍度必須與節點的汙點完全匹配,即汙點的鍵(Key)、值(Value)和效果(Effect)都必須相同。

  • Exists 運算子:當使用 Exists 運算子時,Pod 的容忍度只需要與節點的汙點鍵(Key)和效果(Effect)匹配即可,而不關心汙點的具體值(Value)。

容忍度所用到的引數tolerations,tolerations引數下的還有以下幾個二級引數:

  • operator:此值被稱為運算子,值可以為[Equal|Exists],Equal表示汙點的key是否等於value(預設引數),Exists只判斷汙點的key是否存在,使用該引數時,不需要定義value。
  • effect:指定匹配的汙點程度,為空表示匹配所有等級的汙點
    • NoSchedule: 當節點上存在帶有 NoSchedule 效果的汙點時,新的 Pod 不會被排程到該節點上。但是,如果 Pod 已經在節點上執行,則它將繼續執行,不會被驅逐。
    • PreferNoSchedule : 當節點上存在帶有 PreferNoSchedule 效果的汙點時,新的 Pod 將盡量避免被排程到該節點上,但不是強制性的。也就是說,如果其他節點不可用或者不適合排程 Pod,則 Pod 仍可能被排程到該節點。
    • NoExecut: 當節點上存在帶有 NoExecute 效果的汙點時,新的 Pod 不會被排程到該節點上,並且已經執行在該節點上的 Pod 也會被驅逐。這種效果比 NoSchedule 更加強烈,因為它不僅阻止新的 Pod 被排程,還會驅逐已存在的 Pod。
  • key:指定Node上汙點的鍵key。
  • value:指定Node上汙點的值value。
  • tolerationSeconds:用於定於延遲驅趕當前Pod物件的時長,如果設定為0或者負值系統將立即驅趕當前Pod。(單位為秒)

3.2、為node打上不同等級的汙點

kubectl taint nodes k8s-node1 node-role.kubernetes.io=node1:NoSchedule
kubectl taint nodes k8s-node2 node-role.kubernetes.io=node2:PreferNoSchedule
kubectl taint nodes k8s-node3 node-role.kubernetes.io=node3:NoExecute

image-20240806140239307

新增一個worker節點

由於有三個不同等級的汙點,為了更直觀的展示,擴充套件為三個node

加入叢集前和平時步驟一樣

#在 master 節點上執行來獲取加入叢集所需的命令
kubeadm token create --print-join-command
#輸入剛才生成的命令加入叢集即可
kubectl get nodes

image-20240806001034185

3.3、檢視叢集中節點的汙點

kubectl describe node k8s-master1 k8s-node1 k8s-node2 k8s-node3 | grep Taints

image-20240806140345565

在實際使用中,汙點通常格式為 taint-key=value:effect。但是,在k8s-master1預設的中汙點中,node-role.kubernetes.io/master:NoSchedule 被視為一個完整的鍵,而沒有具體的值。

3.4、建立容忍NoSchedule級別汙點的Pod

cat << EOF > pod-NoSchedule.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-noschedule
spec:
  containers:
  - name: noschedule-container
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  tolerations:
  - key: "node-role.kubernetes.io"                #指定汙點的key
    operator: "Equal"           #Equal值表示我們指定的key必須要等於value
    value: "node1"                #指定value
    effect: "NoSchedule"        #指定汙點級別

3.4.1、應用Pod並檢視排程情況

kubectl apply -f pod-NoSchedule.yaml

kubectl get pods -o wide

image-20240807125455562

3.5、建立容忍PreferNoSchedule級別汙點的Pod

cat << EOF > pod-PreferNoSchedule.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-prefernoschedule
spec:
  containers:
  - name: prefernoschedule-container
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  tolerations:
  - key: "node-role.kubernetes.io"
    operator: "Equal"
    value: "node2"
    effect: "PreferNoSchedule"
EOF

3.5.1、應用Pod並檢視排程情況

kubectl apply -f pod-PreferNoSchedule.yaml

kubectl get pods -o wide | grep pod-prefernoschedule

image-20240807140353254

3.6、建立容忍NoExecute級別汙點的Pod

cat<< EOF > pod-NoExecute.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-noexecute
spec:
  containers:
  - name: noexecute-container
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  tolerations:
  - key: "node-role.kubernetes.io"
    operator: "Equal"
    value: "node3"
    effect: "NoExecute"
    # tolerationSeconds 欄位指定了 Pod 可以容忍 NoExecute 汙點的時間為3600s
    tolerationSeconds: 3600
EOF

3.6.1、應用Pod並檢視排程情況

kubectl apply -f pod-NoExecute.yaml

kubectl get pods -o wide | grep pod-noexecute

image-20240807144207290

3.7、建立沒有容忍度的Pod

cat << EOF > pod-notolerations.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-notolerations
spec:
  containers:
  - name: notolerations-container
    image: nginx:1.14.0
EOF

3.7.1、應用Pod並檢視排程情況

建立了一個沒有容忍項的 Pod,那麼它不會被排程到帶有 NoSchedule(k8s-master1/k8s-node1) 或 NoExecute(k8s-node3) 汙點的節點上。

k8s-node2 的汙點是 PreferNoSchedule。雖然 Pod 不會被優先排程到該節點,但如果沒有其他合適的節點,Pod 仍然可以被排程到該節點上。

kubectl apply -f pod-notolerations.yaml

kubectl get pods -o wide | grep pod-notolerations

image-20240807144913186

3.8、清除用於測試汙點

kubectl taint node k8s-node1 node-role.kubernetes.io-
kubectl taint node k8s-node2 node-role.kubernetes.io-
kubectl taint node k8s-node3	 node-role.kubernetes.io-

image-20240807145724341

七、NodeAffinity 節點親和性排程

1、概述

節點親和性排程程式是用來確定Pod物件排程位置的一組規則,這些規則基於節點上的自定義標籤和Pod物件上指定的標籤選擇器進行定義。

節點親和性允許Pod物件定義針對一組可以排程於其上的節點的親和性或反親和性,不過,它無法具體到某個特定的節點。例如將Pod排程至有著CPU的節點或者一個可用區域內的節點之上。

2、兩種規則

定義節點親和性規則時有兩種型別的節點親和性規則:

  • 硬親和性(required):硬親和性實現的是強制性規則,它是Pod排程時必須要滿足的規則,而在不存在滿足規則的Node時,Pod物件會被置為Pending狀態。
  • 軟親和性(preferred):軟親和性規則實現的是一種柔性排程限制,它傾向於將Pod物件執行於某類特定節點之上,而排程器也將盡量滿足此需求,但在無法滿足需求時它將退而求其次地選擇一個不匹配規則的節點之上。

3、定義節點親和性規則注意點

  • 為節點配置合乎需求的標籤。

  • 為Pod物件定義合理的標籤選擇器,從而能夠基於標籤選擇器選擇出符合需求的標籤。

不過,如 requiredDuringSchedulingIgnoredDuringExecutionpreferredDuringSchedulingIgnoredDuringExecution 名字中的後半段字串 IgnoredDuringExecution 隱藏的意義所指,在Pod資源基於節點親和性規則排程至某節點之後,節點標籤發生了改變而不在符合此類節點親和性規則時,排程器不會將Pod物件從此節點移除,因為它僅對新建的Pod物件生效。

親和度

節點親和度

4、節點硬親和性

節點硬親和性類似於Pod物件使用 nodeSelector 屬性可以基於節點標籤匹配的方式將Pod物件排程至某一個節點之上。不過它僅能基於簡單的等值關係定義標籤選擇器,而 nodeAffinity 中支援使用 matchExpressions 屬性構建更為複雜的標籤選擇機制。

nodeSelectorTerms

4.1、節點硬親和性配置模板

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-node-affinity
spec:
  containers:
  - name: affinity-container
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: environment
            operator: In
            values:
            - production
          - key: role
            operator: In
            values:
            - web

4.2、引數解析

  1. nodeSelectorTerms:
    • 這是一個列表,其中包含一個或多個 matchExpressionsmatchFields 條件。Pod 必須至少滿足其中一個 nodeSelectorTerm 中的所有條件才能被排程到節點上。
  2. matchExpressions:
    • 按照節點的標籤列出節點選擇器列表。每個 matchExpression 描述了一個節點標籤的匹配條件。Pod 必須滿足 nodeSelectorTerm 中的所有 matchExpressions 條件才能被排程到節點上。
  3. matchFields:
    • 按照節點的欄位(而非標籤)列出節點選擇器列表。與 matchExpressions 類似,但用於節點的欄位而非標籤。
  4. key:
    • 指定要選擇節點標籤的鍵(key)。這是節點上標籤的名稱。
  5. values:
    • 指定要選擇節點標籤的值。值必須為陣列形式,例如 ["value1"]values 的內容取決於所使用的運算子:
      • 如果運算子為 InNotInvalues 必須包含一個或多個值,表示節點標籤必須具有這些值之一(In)或不能具有這些值之一(NotIn)。
      • 如果運算子為 ExistsDoesNotExistvalues 必須為空陣列 []
      • 如果運算子為 GtLtvalues 必須包含一個整數值作為元素。
  6. operator:
    • 運算子定義了 keyvalues 之間的關係:
      • In: 節點標籤的值必須在 values 列表中。
      • NotIn: 節點標籤的值不能在 values 列表中。
      • Exists: 節點標籤必須存在,而不管它的值是什麼。
      • DoesNotExist: 節點標籤不存在。
      • Gt: 節點標籤的值必須大於 values 中指定的整數值。
      • Lt: 節點標籤的值必須小於 values 中指定的整數值。

4.3、給 Node 節點新增標籤

  • k8s-node1:

    • environment=sit

    • role=web

  • k8s-node2:

    • environment=sit

    • role=db

  • k8s-node3:

    • environment=prod

    • role=web

kubectl label node k8s-node1 environment=sit role=web

kubectl label node k8s-node2 environment=sit role=db

kubectl label node k8s-node3 environment=prod role=web

kubectl get nodes k8s-node1 k8s-node2 k8s-node3 --show-labels | egrep 'environment|role'

image-20240807170635992

4.4、排程到同時有environment=sit和role=db標籤的節點(存在)

cat << EOF > pod-sit-db.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-sit-db
spec:
  containers:
  - name: container-sit-db
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: environment
            operator: In
            values: ["sit"]
          - key: role
            operator: In
            values: ["db"]
EOF

可以看到pod-sit-db被排程到k8s-node2上

kubectl apply -f pod-sit-db.yaml

kubectl get pods -o wide | grep pod-sit-db

image-20240807171636180

4.5、排程到同時有environment=prod和role=db標籤的節點(不存在)

這裡values的兩種寫法都是可以的

cat << EOF > pod-prod-db.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-prod-db
spec:
  containers:
  - name: container-prod-db
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: environment
            operator: In
            values:
              - prod
          - key: role
            operator: In
            values:
              - db
EOF

可以清晰地看到叢集中不存在滿足規則的Node時,Pod物件會被置為Pending狀態。

kubectl apply -f pod-prod-db.yaml

kubectl get pods -o wide | grep pod-prod-db

image-20240807172416105

describe pod pod-prod-db 檢視Events

kubectl describe pods pod-prod-db | grep -A 10 Events

image-20240807173526080

4.6、排程到具有 environment=sit 標籤但不具有 role=db 標籤的節點

cat << EOF > pod-sit-no-db.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-sit-no-db
spec:
  containers:
  - name: container-sit-no-db
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: environment
            operator: In
            values:
              - sit
          - key: role
            operator: NotIn
            values:
              - db
EOF

具有 environment=sit 標籤但不具有 role=db 標籤的節點即k8s-node1

image-20240807174341651

4.7、排程到具有environment 標籤的節點(無論其值)

cat << EOF > pod-environment-exists.yaml
apiVersion: v1
kind: Pod
metadata:
  name: pod-environment-exists
spec:
  containers:
  - name: container-environment-exists
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: environment
            operator: Exists
            values: []
EOF

這樣的話pod就會在 k8s-node1k8s-node2k8s-node3 三個node節點中隨機一個排程

kubectl apply -f pod-environment-exists.yaml

kubectl get pods -o wide | grep pod-environment-exists

image-20240807190828351

5、節點軟親和性

節點軟親和性為節點選擇機制提供了一種柔性控制邏輯,當排程的Pod物件不再是”必須”,而是“應該”放置於某些特性節點之上,當條件不滿足時,它也能夠接受編排於其它不符合條件的節點之上,另外,它還為每種傾向性提供了weight屬性以便使用者定義其優先順序,取值範圍是1-100,數字越大優先順序越高。

節點軟親和性

5.1、節點軟親和性配置模板

apiVersion: v1
kind: Pod
metadata:
  name: pod-with-node-preference
spec:
  containers:
  - name: affinity-container
    image: nginx:1.14.0
    imagePullPolicy: IfNotPresent
  affinity:
    nodeAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - preference:
          matchExpressions:
          - key: environment
            operator: In
            values: ["sit"]
        weight: 1

5.2、引數解析

  1. preferredDuringSchedulingIgnoredDuringExecution:
    • 這是一個列表,其中包含一個或多個 preference 條目。每個條目都有一個 weight,表示該偏好的重要程度。
  2. preference:
    • 定義了一個節點選擇偏好,其中包括一系列 matchExpressions
  3. weight:
    • 在 1-100 範圍內,與匹配相應的節點選項相關聯的權重。數值越高權重越高代表更強的偏好。
  4. matchExpressions:
    • 按照節點的標籤列出節點選擇器列表。每個 matchExpression 描述了一個節點標籤的匹配條件。Pod 將盡可能被排程到滿足這些條件的節點上。
  5. key:
    • 指定要選擇節點標籤的鍵(key)。這是節點上標籤的名稱。
  6. values:
    • 指定要選擇節點標籤的值。值必須為陣列形式,例如 ["value"]
    • 如果運算子為 In 或者 NotInvalues 則不能為空。
    • 如果運算子為 Exists 或者 DoesNotExistvalues 則必須為空 []。
    • 如果運算子為 GtLt,則 values 必須有單個元素,該元素將被解釋為整數。
  7. operator:
    • 運算子定義了 key 和 values 之間的關係。
      • In: 節點標籤的值必須在 values 列表中。
      • NotIn: 節點標籤的值不能在 values 列表中。
      • Exists: 節點標籤必須存在,而不管它的值是什麼。
      • DoesNotExist: 節點標籤不存在。
      • Gt: 節點標籤的值必須大於 values 中指定的整數值。
      • Lt: 節點標籤的值必須小於 values 中指定的整數值。

5.3、示例

cat << EOF > deployment-with-node-preferences.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: deployment-with-node-preferences
spec:
  replicas: 14
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: app-container
        image: nginx:1.14.0
        imagePullPolicy: IfNotPresent
      affinity:
        nodeAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["prod"]
              - key: role
                operator: In
                values: ["db"]
            weight: 100
          - preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["sit"]
              - key: role
                operator: In
                values: ["web"]
            weight: 90
          - preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["sit"]
              - key: role
                operator: In
                values: ["db"]
            weight: 90
          - preference:
              matchExpressions:
              - key: environment
                operator: In
                values: ["prod"]
              - key: role
                operator: In
                values: ["web"]
            weight: 90
          - preference:
              matchExpressions:
              - key: environment
                operator: NotIn
                values: ["prod"]
              - key: role
                operator: In
                values: ["web"]
            weight: 80
          - preference:
              matchExpressions:
              - key: environment
                operator: Exists
                values: []
              - key: role
                operator: In
                values: ["db"]
            weight: 80
          - preference:
              matchExpressions:
              - key: environment
                operator: DoesNotExist
                values: []
              - key: role
                operator: In
                values: ["web"]
            weight: 1
EOF

5.3.1、分析

  • 偏好 1:

    • 條件:節點必須具有 environment=prodrole=db 的標籤。

    • 權重:100

    • 無匹配節點。

  • 偏好 2:

    • 條件:節點必須具有 environment=sitrole=web 的標籤。

    • 權重:90

    • 匹配節點:k8s-node1

  • 偏好 3:

    • 條件:節點必須具有 environment=sitrole=db 的標籤。

    • 權重:90

    • 匹配節點:k8s-node2

  • 偏好 4:

    • 條件:節點必須具有 environment=prodrole=web 的標籤。

    • 權重:90

    • 匹配節點:k8s-node3

  • 偏好 5:

    • 條件:節點必須具有 environment 標籤,其值不為 prod,並且具有 role=web 的標籤。

    • 權重:80

    • 匹配節點:k8s-node1

  • 偏好 6:

    • 條件:節點必須具有 environment 標籤,並且具有 role=db的標籤。

    • 權重:80

    • 匹配節點:k8s-node2

  • 偏好 7:

    • 條件:節點沒有 environment 標籤,並且具有 role=web 的標籤。

    • 權重:1

    • 無匹配節點。

5.3.2、應用Deploymet檢視排程情況

結果不出意料的出乎了預料,節點軟親和性理解概念即可平時幾乎遇不上他

kubectl apply -f deployment-with-node-preferences.yaml

kubectl get pods -o wide

image-20240807211152136

6、清除 Node 標籤

kubectl label node k8s-node1 environment- role-
kubectl label node k8s-node2 environment- role-
kubectl label node k8s-node3 environment- role-

image-20240808000419353

八、PodAffinity Pod親和性排程

1、概述

Pod 親和性是一種機制,允許指定 Pod 應該與其他 Pod 之間的關係。當希望某些 Pod 被排程到與特定型別的其他 Pod 接近的位置時,可以使用 Pod 親和性。這通常用於需要低延遲通訊的場景,比如應用 Pod 需要與資料庫 Pod 進行頻繁互動。

2、分類

Pod 親和性可以根據其約束的嚴格程度分為兩類:硬親和性和軟親和性。

  • 硬親和性是一種必須滿足的約束,只有當 Pod 滿足了這些約束條件時,它才會被排程到叢集中的某個節點上。如果 Pod 已經被排程並且之後親和性條件不再滿足(例如,其他 Pod 被刪除),那麼已經排程的 Pod 不會被重新排程。

  • 軟親和性是一種偏好,它不構成硬性約束。Kubernetes 會在排程 Pod 時儘可能滿足這些偏好,但如果無法滿足,Pod 仍然會被排程。這意味著即使 Pod 無法完全按照軟親和性偏好進行排程,它也會被排程到叢集中的某個節點上。

Pod親和度

3、Pod 硬親和性

3.1、Pod 硬親和性配置模板

apiVersion: v1
kind: Pod
metadata:
  name: app-pod
  labels:
    app: app-pod
spec:
  containers:
  - name: app-container
    image: nginx:1.14.0
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - db-pod
        topologyKey: kubernetes.io/hostname

3.2、引數解析

  • affinity: 定義親和性和反親和性的配置。
    • podAffinity:Pod 親和性配置。
      • requiredDuringSchedulingIgnoredDuringExecution: 硬性約束,表示 Pod 必須滿足親和性要求才能被排程。
        • labelSelector: 選擇具有特定標籤的 Pod。
          • matchExpressions: 選擇具有指定鍵值對的 Pod。
            • key: 標籤鍵。
            • operator: 運算子,這裡使用 In 表示匹配鍵值對。
            • values: 標籤值。
        • topologyKey: 拓撲鍵,這裡使用 kubernetes.io/hostname 表示 Pod 應該在同一臺主機上。

3.3、為 Node 打上不同地區的標籤

kubectl label node k8s-node1 zone=beijing
kubectl label node k8s-node2 zone=shanghai
kubectl label node k8s-node3 zone=shenzhen

image-20240808000905576

3.4、建立 Pod 資源清單(使用 Pod 硬親和性)

cat << EOF > podaffinity-required-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: podaffinity-required-pod
spec:
  containers:
  - name: nginx-containers
    image: nginx:1.14.0
  affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: app
            operator: In
            values:
            - proxy
            - web
        topologyKey: zone
EOF
  • labelSelector: 選擇具有 app 標籤且值為 proxyweb 的 Pod。
  • topologyKey: 指定節點的標籤鍵 zone,這表示 Pod 必須與具有相同 zone 標籤的其他 Pod 執行在同一節點上。

3.5、檢視排程結果

由於叢集中還沒有其他帶有 app 標籤為 proxyweb 的 Pod,因此 podaffinity-required-pod 將保持在 Pending 狀態。

kubectl apply -f podaffinity-required-pod.yaml

kubectl get pods -o wide | grep podaffinity-required-pod

image-20240808001236041

3.6、建立帶有特定標籤的 Pod

cat << EOF > app-proxy-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: app-proxy-pod
  labels:
    app: proxy
spec:
  containers:
  - name: app-proxy
    image: nginx:1.14.0
EOF

3.7、檢視排程結果

kubectl apply -f app-proxy-pod.yaml 

kubectl get pods -o wide | grep app-proxy-pod

kubectl get pods -o wide | grep podaffinity-required-pod

image-20240808001642848

  • app-proxy-pod: 被排程到了 k8s-node1
  • podaffinity-required-pod: 由於硬親和性要求,該 Pod 也需要被排程到與 app-proxy-pod 相同的節點上,即 k8s-node1

4、Pod 軟親和性

4.1、Pod 軟親和性配置模板

apiVersion: v1
kind: Pod
metadata:
  name: my-pod
spec:
  containers:
  - name: my-container
    image: nginx:1.14.0
  affinity:
    podAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 1
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: app
              operator: In
              values:
              - my-other-app
          topologyKey: kubernetes.io/hostname

4.2、引數解析

preferredDuringSchedulingIgnoredDuringExecution:軟偏好,不構成硬性約束。k8s 會在排程 Pod 時儘可能滿足這些偏好

  • weight: 如果滿足此親和性條件時,給 Pod 分配到該節點的優先順序分數。取值範圍是1-100,數字越大優先順序越高。
  • podAffinityTerm:描述了親和性條件。
    • labelSelector: 指定要匹配的 Pod 的標籤。
      • matchExpressions:
        • key: 匹配標籤的鍵名,這裡是 app
        • operator: 匹配運算子,這裡是 In,表示標籤的值必須在 values 列表中。
        • values: 匹配標籤的具體值,這裡是 my-other-app
    • topologyKey: 指定要匹配的拓撲鍵,這裡是 kubernetes.io/hostname,表示希望 Pod 與具有相同 app=my-other-app 標籤的其他 Pod 在同一個節點上執行。

4.3、建立帶有 app=nginx 和 app=busybox 標籤的 Pod。

cat << EOF > pod-nginx-busybox.yaml
apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
  labels:
    app: nginx
spec:
  containers:
  - name: nginx-container
    image: nginx:1.14.0

---

apiVersion: v1
kind: Pod
metadata:
  name: busybox-pod
  labels:
    app: busybox
spec:
  containers:
  - image: busybox:latest
    name: nodename-containers
    command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF

4.4、建立 Pod 軟親和性的 Deployment

cat << EOF > soft-pod-affinity-deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: soft-pod-affinity-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        podAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 81
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - nginx
              topologyKey: zone
          - weight: 80
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - busybox
              topologyKey: zone
      containers:
      - name: myapp
        image: busybox:latest
        command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]
EOF

4.5、應用標籤為 cache 和 db 的 Pod

kubectl apply -f pod-cache-db.yaml

image-20240808190354655

4.6、應用帶有 Pod 軟親和性的 Deployment

kubectl apply -f soft-pod-affinity-deployment.yaml

image-20240808190658555

4.7、檢視Pod排程情況

  • busybox-pod被排程到k8s-node1,nginx-pod被排程到k8s-node3

  • 定義了兩個軟親和性偏好:

    • 第一個偏好權重為 81,表示 Pod 更傾向於與標籤為 app=nginx 的 Pod 執行在同一 zone 的節點上。
    • 第二個偏好權重為 80,表示 Pod 更傾向於與標籤為 app=busybox 的 Pod 執行在同一 zone 的節點上。
  • 從結果來看還是比較符合我們定義的軟親和度規則

kubectl get pods -o wide

image-20240808194657938

九、Pod Anti-Affinity Pod反親和性排程

1、概述

Pod 反親和性(Pod Anti-Affinity)是一種 Kubernetes 排程策略,它確保帶有特定標籤的 Pod 不會被排程到同一節點上。Pod親和性是將有密切關聯的Pod執行到同一平面、同一個區域或者同一臺機器上,而反親和性是將Pod執行在不同區域、不同機器上,Pod反親和性排程一般用於分散同一類應用的Pod物件等。

2、分類

  • 硬反親和性 (Hard Anti-Affinity) :硬反親和性是一種強制性的要求,如果 Pod 不能滿足硬反親和性條件,則不會被排程到任何節點。硬反親和性使用 requiredDuringSchedulingIgnoredDuringExecution 欄位來定義。

  • 軟反親和性 (Soft Anti-Affinity):軟反親和性則是一種偏好,如果滿足條件則更好,但即便不滿足條件,Pod 仍會被排程。軟反親和性使用 preferredDuringSchedulingIgnoredDuringExecution 欄位來定義。

3、Pod 硬反親和性

3.1、Pod 硬反親和性配置模板

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-anti-affinity-hard
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - myapp
            topologyKey: kubernetes.io/hostname
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - myapp
            topologyKey: zone
      containers:
      - name: myapp
        image: busybox:latest
        command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]

3.2、建立帶有硬反親和性規則的Deployment

cat << EOF > pod-anti-affinity-hard.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-anti-affinity-hard
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      name: myapp
      labels:
        app: myapp
    spec:
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values: 
                - myapp
            topologyKey: zone
      containers:
      - name: myapp
        image: busybox:latest
        command: ["/bin/sh", "-c", "tail -f /etc/passwd" ]
EOF
  • 定義了一個名為 pod-anti-affinity-hard 的 Deployment,它會建立 4 個副本。
  • Pod 的標籤為 app=myapp
  • topologyKey 設定為 zone,表示 Pod 不應被排程到具有相同 zone 標籤的節點上。

3.3、應用Deployment檢視Pod排程情況

kubectl apply -f pod-anti-affinity-hard.yaml

kubectl get pods -o wide --show-labels

image-20240808205014685

image-20240808205301329

  • 由於硬反親和性配置,帶有 app=myapp 標籤的 Pod 不會被排程到具有相同 zone 標籤的節點上。
  • 由於只有三個 Node 具有不同的 zone 標籤,所以只有三個 Pod 被成功排程到了不同的 Node 上。
  • 第四個 Pod 無法找到滿足硬反親和性條件的 Node,因此一直處於 Pending 狀態。

4、Pod軟反親和性

4.1、Pod 軟反親和性配置模板

apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-anti-affinity-soft
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 100
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - myapp
              topologyKey: kubernetes.io/hostname
          - weight: 50
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - myapp
              topologyKey: zone
      containers:
      - name: myapp
        image: busybox:latest
        command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]

4.2、建立帶有 Pod 軟反親和性的 Deployment

cat << EOF > pod-anti-affinity-soft.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: pod-anti-affinity-soft
spec:
  replicas: 4
  selector:
    matchLabels:
      app: myapp
  template:
    metadata:
      labels:
        app: myapp
    spec:
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
          - weight: 90
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - myapp
              topologyKey: kubernetes.io/hostname
          - weight: 89
            podAffinityTerm:
              labelSelector:
                matchExpressions:
                - key: app
                  operator: In
                  values:
                  - myapp
              topologyKey: zone
      containers:
      - name: myapp
        image: busybox:latest
        command: ["/bin/sh", "-c", "while true; do sleep 3600; done"]
EOF

4.3、應用 Deployment 檢視排程情況

kubectl apply -f pod-anti-affinity-soft.yaml

kubectl get pods -o wide --show-labels

kubectl get nodes -L zone

image-20240809000110419

根據軟反親和性配置,第一個規則的權重較高(90),因此排程器儘量避免將具有相同 app=myapp 標籤的 Pod 排程到同一節點上。

第二個規則的權重較低(89),表示儘量避免將 Pod 排程到具有相同 zone 標籤的節點上。

然後由於是軟反親和性,所以即使不滿足規則時 Pod 最終還是會被排程。

相關文章