這應該是最全的K8s-Pod調度策略了
API Server接受客戶端提交Pod對象創建請求后的操作過程中,有一個重要的步驟就是由調度器程序kube-scheduler從當前集群中選擇一個可用的最佳節點來接收并運行它,通常是默認的調度器kube-scheduler負責執行此類任務。
對于每個待創建的Pod對象來說,調度過程通常分為兩個階段—》過濾—》打分,過濾階段用來過濾掉不符合調度規則的Node,打分階段建立在過濾階段之上,為每個符合調度的Node進行打分,分值越高則被調度到該Node的機率越大。
Pod調度策略除了系統默認的kube-scheduler調度器外還有以下幾種實現方式:
1.nodeName(直接指定Node主機名)
2.nodeSelector (節點選擇器,為Node打上標簽,然后Pod中通過nodeSelector選擇打上標簽的Node)
3.污點taint與容忍度tolerations
4.NodeAffinity 節點親和性
5.PodAffinity Pod親和性
6.PodAntAffinity Pod反親和性
以下幾章節內容主要講解上面幾種調度策略以及kube-scheduler調度器的調度原理。
Pod調度之kube-scheduler
官方文檔:
https://kubernetes.io/zh/docs/concepts/scheduling-eviction/kube-scheduler/
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,這個過程叫做綁定。
在做調度決定是需要考慮的因素包括:單獨和整體的資源請求、硬件/軟件/策略限制、親和以及反親和要求、數據局域性、負載間的干擾等等。
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 會從中隨機選取一個。
整體流程如下圖所示:
過濾階段
官方文檔:
https://kubernetes.io/docs/reference/scheduling/policies/
在調度時的過濾階段到底時通過什么規則來對Node進行過濾的呢?就是通過以下規則!
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)。
打分階段
官方文檔:
https://kubernetes.io/docs/reference/scheduling/policies/ 當過濾階段執行后滿足過濾條件的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拓撲擴展約束。
kube-scheduler 調度示例
默認配置使用的就是kube-scheduler調度組件,我們下面例子啟動三個Pod,看分別被分配到哪個Node。
1.創建資源配置清單
cat scheduler-pod.yaml
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" ]
2.使用kubectl創建資源對象
kubectl apply -f scheduler-pod.yaml
3.查看被kube-scheduler自動調度的Pod 兩個Pod在Node03上,一個在Node02上
kubectl get pods -o wide | grep scheduler
scheduler-deploy-65d8f9c98-cqdm9 1/1 Running 0 111s 10.244.5.59 k8s-node03 <none> <none>
scheduler-deploy-65d8f9c98-d4t9p 1/1 Running 0 111s 10.244.5.58 k8s-node03 <none> <none>
scheduler-deploy-65d8f9c98-f8xxc 1/1 Running 0 111s 10.244.2.45 k8s-node02 <none> <none>
4.我們查看一下Node資源的使用情況 Node01,可用內存2.7G
Node02,可用內存5.8G
Node03,可用內存5.6G
所以默認的kube-scheduler調度策略經過了過濾和打分后,將以上三個Pod分布在Node2和Node3上。
Pod調度之nodeName
nodeNamed這種調度方式比較簡單,我們可以指定Pod在哪臺Node上進行運行,通過spec.nodeName參數來指定Node主機名稱即可。
1、創建資源配置清單
cat nodeName-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nodename-pod
spec:
#指定該Pod運行在k8s-node02節點上
nodeName: k8s-node02
containers:
- image: busybox:latest
name: nodename-containers
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
2、創建Pod資源對象
kubectl apply -f nodeName-pod.yaml
3、查看Pod調度節點
如下,nodename-pod被綁定在了k8s-node02上
kubectl get pods -o wide | grep name
nodename-pod 1/1 Running 0 25s 10.244.2.46 k8s-node02 <none> <none>
Pod調度之nodeSelector
nodeSelector用于將Pod調度到匹配Label的Node上,所以要先給node打上標簽,然后在Pod配置清單中選擇指定Node的標簽。先給規劃node用途,然后打標簽,例如將兩臺node劃分給不同團隊使用:
為Node添加標簽
k8s-node02給開發團隊用,k8s-node03給大數據團隊用
1.添加標簽
kubectl get nodes -o wide --show-labels
2.查看標簽
kubectl apply -f nodeSelector-pod.yaml
創建資源配置清單
cat nodeSelector-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nodeselector-pod
spec:
nodeSelector: #指定標簽選擇器
team: development #label指定開發團隊的label
containers:
- image: busybox:latest
name: nodeselector-containers
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
創建Pod對象
kubectl apply -f nodeSelector-pod.yaml
查看pod被分配的Node
kubectl get pods -o wide | grep nodeselect
nodeselector-pod 1/1 Running 0 49s 10.244.2.47 k8s-node02 <none> <none>
刪除標簽
kubectl label nodes k8s-node02 team-
kubectl label nodes k8s-node03 team-
刪除標簽后pod還在正常運行
kubectl get pods -o wide | grep nodeselect
nodeselector-pod 1/1 Running 0 11m 10.244.2.47 k8s-node02 <none> <none>
把Pod刪除然后再次創建Pod
kubectl get pods -o wide | grep nodeselectnodeselector-pod 0/1 Pending 0 55s <none> <none> <none> <none>
會發現該pod一直在等待中,找不到清單中配置標簽的Node
kubectl describe pods/nodeselector-pod | grep -A 10 EventsEvents: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling <unknown> default-scheduler 0/6 nodes are available: 6 node(s) didn't match node selector. Warning FailedScheduling <unknown> default-scheduler 0/6 nodes are available: 6 node(s) didn't match node selector.
事件:6個節點都不匹配 node selector
kubectl describe pods/nodeselector-pod | grep -A 10 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling <unknown> default-scheduler 0/6 nodes are available: 6 node(s) didn't match node selector.
Warning FailedScheduling <unknown> default-scheduler 0/6 nodes are available: 6 node(s) didn't match node selector.
Pod調度之污點與容忍
官方文檔:
https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/#example-use-cases
污點(taint)是定義在Node之上的鍵值型的數據,用于讓節點拒絕將Pod調度運行于其上,除非該Pod對象具有接納Node污點的容忍度。而容忍度(tolerations)是定義在Pod對象的鍵值型屬性數據,用于·配置其可容忍的Node污點,而且調度器僅能將Pod對象調度至其能夠容忍該Node污點的Node之上。
如下圖所示:
?Pod-A具備k8s-node01污點的容忍度,所以能夠被調度器調度至k8s-node01上。?Pod-A不完全具備k8s-node02污點的容忍度,所以不能被調度至k8s-node02。?Pod-A雖然具備容忍度,但同樣可以調度至沒有污點的k8s-node03節點上。?Pod-B自身沒有容忍度,所以只能被調度至沒有污點的k8s-node03節點上。
污點介紹及定義
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.Master污點介紹 以kubeadm部署的kubernetes集群,其Master節點將自動添加污點信息以阻止不能容忍此污點的Pod對象調度至此節點,因此用戶可以手動創建Pod來容忍Master的污點。
查看kubernetes集群中master節點的污點:
kubectl get pods -o wide | grep nodeselectnodeselector-pod 1/1 Running 0 49s 10.244.2.47 k8s-node02 <none> <none>
不過,有些系統級別應用,如kube-proxy或者kube-flannel等也是以Pod形式運行在集群上,這些資源在創建時就添加上了相應的容忍度以確保他們被 DaemonSet 控制器創建時能夠調度至 Master 節點運行一個實例。
查看系統級別Pod的容忍度
kubectl describe pods/etcd-k8s-master01 pods/etcd-k8s-master01 pods/kube-flannel-ds-amd64-2smzp pods/kube-flannel-ds-amd64-2smzp -n kube-system | grep Tolerations
Tolerations: :NoExecute
Tolerations: :NoExecute
Tolerations: :NoSchedule
Tolerations: :NoSchedule
另外,這類Pod是構成Kubernetes系統的基礎且關鍵的組件,它們甚至還定義了更大的容忍度,從下面某kube-flannel實例的容忍度定義來看,它還能容忍那些報告了磁盤壓力或內存壓力的節點,以及未就緒的節點和不可達的節點,以確保它們能在任何狀態下正常調度至集群節點上運行。
kubectl describe pods kube-flannel-ds-amd64-2smzp -n kube-system
Tolerations: :NoSchedule
node.kubernetes.io/disk-pressure:NoSchedule
node.kubernetes.io/memory-pressure:NoSchedule
node.kubernetes.io/network-unavailable:NoSchedule
node.kubernetes.io/not-ready:NoExecute
node.kubernetes.io/pid-pressure:NoSchedule
node.kubernetes.io/unreachable:NoExecute
node.kubernetes.io/unschedulable:NoSchedule
Events: <none>
3.定義污點
定義污點語法 kubectl taint nodes <node-name> <key>=<value>:<effect>
node-name:指定需要打污點的Node主機名 key=value:指定污點的鍵值型數據 effect:為污點的等級
key名稱長度上線為253個字符,可以使用字母或者數字開頭,支持字母、數字、連接符、點號、下劃線作為key或者value。value最長是 63個字符。污點通常用于描述具體的部署規劃,它們的鍵名形式如 node-type、node-role、node-project、node-geo等。
1.添加污點 為k8s-node02添加污點,污點程度為NoSchedule,type=calculate為標簽
kubectl taint node k8s-node02 type=calculate:NoSchedule
2.查看污點
kubectl describe nodes k8s-node02 | grep Taints
這樣的話我們創建Pod就不會被調度到我們打上污點的k8s-node02的節點上
3.創建Pod資源配置清單 我們創建3個Pod,看看其是否會將Pod調度到我們打污點Node上
cat taint-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint-deploy
spec:
replicas: 3
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" ]
2.查看Pod被調度的Node 下面三個Pod都被調度到了Node03上,效果可能不是很明顯,我們為Node02打了污點,還有Node01沒有體現出來
kubectl apply -f taint-pod.yaml
kubectl get pods -o wide | grep taint
taint-deploy-748989f6d4-f7rbq 1/1 Running 0 41s 10.244.5.62 k8s-node03 <none> <none>
taint-deploy-748989f6d4-nzwjg 1/1 Running 0 41s 10.244.5.61 k8s-node03 <none> <none>
taint-deploy-748989f6d4-vzzdx 1/1 Running 0 41s 10.244.5.60 k8s-node03 <none> <none>
4.擴容Pod 我們將Pod擴容至9臺,讓Pod分配到Node01節點,可以直觀的展現污點
kubectl scale --replicas=9 deploy/taint-deploy -n default
kubectl get pods -o wide | grep taint
taint-deploy-748989f6d4-4ls9d 1/1 Running 0 54s 10.244.5.65 k8s-node03 <none> <none>
taint-deploy-748989f6d4-794lh 1/1 Running 0 68s 10.244.5.63 k8s-node03 <none> <none>
taint-deploy-748989f6d4-bwh5p 1/1 Running 0 54s 10.244.5.66 k8s-node03 <none> <none>
taint-deploy-748989f6d4-ctknr 1/1 Running 0 68s 10.244.5.64 k8s-node03 <none> <none>
taint-deploy-748989f6d4-f7rbq 1/1 Running 0 2m27s 10.244.5.62 k8s-node03 <none> <none>
taint-deploy-748989f6d4-hf9sf 1/1 Running 0 68s 10.244.3.51 k8s-node01 <none> <none>
taint-deploy-748989f6d4-nzwjg 1/1 Running 0 2m27s 10.244.5.61 k8s-node03 <none> <none>
taint-deploy-748989f6d4-prg2f 1/1 Running 0 54s 10.244.3.52 k8s-node01 <none> <none>
taint-deploy-748989f6d4-vzzdx 1/1 Running 0 2m27s 10.244.5.60 k8s-node03 <none> <none>
以上調度了兩臺Pod到Node02,目前Node03和Node01都可以分配到Pod,而被打了污點的Node02無法分配Pod
5.刪除污點 刪除污點之需要指定標簽的 key 及污點程度
kubectl taint node k8s-node02 type:NoSchedule-
容忍度介紹及定義
Pod對象的容忍度可以通過其spec.tolerations字段進行添加,根據使用的操作符不同,主要有兩種可用的形式:
1.容忍度與污點信息完全匹配的等值關系,使用Equal操作符。2.判斷污點是否存在的匹配方式,使用Exists操作富。
容忍度所用到的參數tolerations,tolerations參數下的還有以下幾個二級參數:
?operator:此值被稱為運算符,值可以為[Equal|Exists],Equal表示污點的key是否等于value(默認參數),Exists只判斷污點的key是否存在,使用該參數時,不需要定義value。
?effect:指定匹配的污點程度,為空表示匹配所有等級的污點,值可以為 [NoSchedule|PreferNoSchedule|NoExecut]。
?key:指定Node上污點的鍵key。
?value:指定Node上污點的值value。
?tolerationSeconds:用于定于延遲驅趕當前Pod對象的時長,如果設置為0或者負值系統將立即驅趕當前Pod。(單位為秒)
1. 為Node打上不同的等級污點
kubectl taint nodes k8s-node01 nodes=gpu:NoSchedule
kubectl taint nodes k8s-node02 data=ssd:PreferNoSchedule
kubectl taint nodes k8s-node03 traffic=proxy:NoExecute
2.查看三個Node被打上的污點
kubectl describe nodes k8s-node01 k8s-node02 k8s-node03 | grep Taint
Taints: nodes=gpu:NoSchedule
Taints: data=ssd:PreferNoSchedule
Taints: traffic=proxy:NoExecute
3.創建容忍NoSchedule級別污點的Pod并查看Pod調度結果
cat pod-tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-noschedule
spec:
containers:
- name: gpu-container
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
tolerations:
- key: "nodes" #指定污點的key
operator: "Equal" #Equal值表示我們指定的key必須要等于value
value: "gpu" #指定value
effect: "NoSchedule" #指定污點級別
#調度結果如我們期望所致在node01上
kubectl get pods -o wide | grep pod-noschedule
pod-noschedule 1/1 Running 0 58s 10.244.3.62 k8s-node01 <none> <none>
4.創建容忍PreferNoSchedule級別污點的Pod并查看Pod調度結果
cat pod-tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-prefernoschedule
spec:
containers:
- name: ssd-container
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
tolerations:
- key: "data"
operator: "Exists" #Exists參數,只判斷key等于data是否存在,不需要關心value是什么
effect: "PreferNoSchedule
#調度結果如我們期望所致在node02上
kubectl get pods -o wide | grep pod-prefer
pod-prefernoschedule 1/1 Running 0 45s 10.244.2.82 k8s-node02 <none> <none>
5.創建容忍NoExecute級別污點的Pod并查看調度結果
apiVersion: v1
kind: Pod
metadata:
name: pod-noexecute
spec:
containers:
- name: proxy-container
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
tolerations:
- key: "traffic"
operator: "Equal"
value: "proxy"
effect: "NoExecute" #指定污點級別
tolerationSeconds: 300 #指定驅趕當前Node上Pod的延遲時間
#調度結果在Node03上
kubectl get pods -o wide | grep pod-noexecute
pod-noexecute 1/1 Running 0 24s 10.244.5.89 k8s-node03 <none> <none>
6.創建沒有容忍度的Pod并查看調度結果 PreferNoSchedule污點級別為盡量不接受沒有容忍此污點的Pod,如果沒有其它節點可以供Pod選擇時,也會接受沒有容忍此污點的Pod對象。所以創建一個沒有容忍度的Pod看其調度結果。
cat pod-tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-notolerations
spec:
containers:
- name: notolerations-container
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
#如下,調度結果與我們料想一致
kubectl get pods -o wide | grep pod-notolerations
pod-notolerations 1/1 Running 0 29s 10.244.2.83 k8s-node02 <none> <none>
實踐中,若集群中的一組機器專用于為運行非生產典型的容器應用而備置,而且它們可能隨時按需上下線,那么就應該為其添加污點信息,以確保僅那些能夠容忍此污點的非生產型Pod對象可以調度到其上,另外,某些有種特殊硬件的節點需要專用于運行一類有著SSD、或者GPU的設備,也應該為其添加污點信息以排除其它Pod對象。
Pod調度之節點親和性調度
官方文檔:
https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#node-affinity
節點親和性調度程序是用來確定Pod對象調度位置的一組規則,這些規則基于節點上的自定義標簽和Pod對象上指定的標簽選擇器進行定義。
節點親和性允許Pod對象定義針對一組可以調度于其上的節點的親和性或反親和性,不過,它無法具體到某個特定的節點。例如將Pod調度至有著CPU的節點或者一個可用區域內的節點之上。定義節點親和性規則時有兩種類型的節點親和性規則:
1.硬親和性(required):硬親和性實現的是強制性規則,它是Pod調度時必須要滿足的規則,而在不存在滿足規則的Node時,Pod對象會被置為Pending狀態。
2.軟親和性(preferred):軟親和性規則實現的是一種柔性調度限制,它傾向于將Pod對象運行于某類特定節點之上,而調度器也將盡量滿足此需求,但在無法滿足需求時它將退而求其次地選擇一個不匹配規則的節點之上。
定義節點親和性規則的關鍵點有兩個:
1.為節點配置合乎需求的標簽。
2.為Pod對象定義合理的標簽選擇器,從而能夠基于標簽選擇器選擇出符合需求的標簽。
不過,如
requiredDuringSchedulingIgnoredDuringExecution和
preferredDuringSchedulingIgnoredDuringExecution名字中的后半段字符串IgnoredDuringExecution隱藏的意義所指,在Pod資源基于節點親和性規則調度至某節點之后,節點標簽發生了改變而不在符合此類節點親和性規則時,調度器不會將Pod對象從此節點移除,因為它僅對新建的Pod對象生效。
幫助文檔:kubectl explain
pods.spec.affinity.nodeAffinity
節點硬親和性
節點硬親和性類似于Pod對象使用nodeSelector屬性可以基于節點標簽匹配的方式將Pod對象調度至某一個節點之上。不過它僅能基于簡單的等值關系定義標簽選擇器,而nodeAffinity中支持使用matchExpressions屬性構建更為復雜的標簽選擇機制。
節點硬親和性參數解析:
?nodeSelectorTerms:節點選擇列表(比nodeSelector高級一點)。
?matchExpressions:按照節點label列出節點選擇器列表。(與matchFields是兩種方式,不過結果是一至)
?matchFields:按照節點字段列出節點選擇器列表。(與matchExpressions是兩種方式,不過結果是一至)
?key:指定要選擇節點label的key。
?values:指定要選擇節點label的value,值必須為數組 ["value"] ,如果操作符為In或者 Notin,value則不能為空,如果操作符為Exists或者DoesNotExist ,value則必須為空[],如果操作符為Gt或Lt,則value必須有單個元素,該元素將被解釋為整數。
?operator:操作符,指定key與value的關系。
?In:key與value同時存在,一個key多個value的情況下,value之間就成了邏輯或效果。
?NotIn:label 的值不在某個列表中。
?Exists:只判斷是否存在key,不用關心value值是什么。
?DoesNotExist:某個 label 不存在。
?Gt:label 的值大于某個值。
?Lt:label 的值小于某個值
1.為Node打上標簽
#node01打兩個標簽ssd=true及zone=foo
kubectl label node k8s-node01 ssd=true zone=foo
#node02打一個標簽zone=foo
kubectl label node k8s-node02 zone=foo
#node03打兩個標簽ssd=true zone=bar
kubectl label node k8s-node03 ssd=true zone=bar
2.創建Pod資源配置清單 下面Pod資源清單中,該Pod將被綁定到標簽key為zone,value為foo的Node上,符合該規則有兩個Node,分別是Node01和Node02,下面資源配置清單中只創建了一個Pod,可以來觀察下該Pod會被調度至Node01還是Node02。
apiVersion: apps/v1
kind: Deployment
metadata:
name: required-nodeaffinity-deploy
labels:
type: required-deploy
spec:
replicas: 3
selector:
matchLabels:
app: required-nodeaffinity-pod
template:
metadata:
labels:
app: required-nodeaffinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: zone, operator: In, values: ["foo"] }
containers:
- name: myapp
image: busybox:latest
command: ["/bin/sh", "-c", "tail -f /etc/passwd"]
3.查看Pod被調度至哪臺Node 如下結果可以看到三個Pod都被調度到了Node01上
kubectl apply -f required-nodeAffinity-pod.yaml
kubectl get pods -o wide | grep requ
required-nodeaffinity-deploy-55448998fd-hm9ww 0/1 ContainerCreating 0 7s <none> k8s-node01 <none> <none>
required-nodeaffinity-deploy-55448998fd-pkwph 0/1 ContainerCreating 0 7s <none> k8s-node01 <none> <none>
required-nodeaffinity-deploy-55448998fd-z94v2 0/1 ContainerCreating 0 7s <none> k8s-node01 <none> <none>
4.創建Pod資源清單2 如下value有兩個值,兩個值之間是或關系,可以調度到key為zone,values為foo或者bar標簽的Node上, 下面配置清單中有兩個key,兩個key之間是與關系,第二個key在第一個key的基礎上,Node還有有標簽key為ssd,values無需關心,因為使用操作符Exists。下面的配置清單中,只能調度到標簽key為zone,values為foo或者bar以及key為ssd的Node上,滿足此需求的Node有Node01和Node03。
cat required-nodeAffinity-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: required-nodeaffinity-deploy
labels:
type: required-deploy
spec:
replicas: 3
selector:
matchLabels:
app: required-nodeaffinity-pod
template:
metadata:
labels:
app: required-nodeaffinity-pod
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- { key: zone, operator: In, values: ["foo","bar"] } #foo和bar之間是或關系
- { key: ssd, operator: Exists, values: [] } #兩個matchExpressions之間是與關系
containers:
- name: myapp
image: busybox:latest
command: ["/bin/sh", "-c", "tail -f /etc/passwd"]
5.查看Pod調度結果 如下三個Pod都被調度在Node03節點
kubectl apply -f required-nodeAffinity-pod.yaml
kubectl get pods -o wide | grep required-nodeaffinity
required-nodeaffinity-deploy-566678b9d8-c84nd 1/1 Running 0 65s 10.244.5.97 k8s-node03 <none> <none>
required-nodeaffinity-deploy-566678b9d8-pn27p 1/1 Running 0 65s 10.244.5.95 k8s-node03 <none> <none>
required-nodeaffinity-deploy-566678b9d8-x8ttf 1/1 Running 0 65s 10.244.5.96 k8s-node03 <none> <none>
節點軟親和性
節點軟親和性為節點選擇機制提供了一種柔性控邏輯,當調度的Pod對象不再是"必須",而是“應該”放置于某些特性節點之上,當條件不滿足時,它也能夠接受編排于其它不符合條件的節點之上,另外,它還為每種傾向性提供了weight屬性以便用戶定義其優先級,取值范圍是1-100,數字越大優先級越高。
節點軟親和性參數解析:
?preference:節點選擇器,與相應的權重相關聯。
?weight:在1-100范圍內,與匹配相應的節點選項相關聯的權重。
?matchExpressions:按照節點label列出節點選擇器列表。(與matchFields是兩種方式,不過結果是一至)
?matchFields:按照節點字段列出節點選擇器列表。(與matchExpressions是兩種方式,不過結果是一至)
?key:指定要選擇節點label的key。
?values:指定要選擇節點label的value,值必須為數組 ["value"] ,如果操作符為In或者 Notin,value則不能為空,如果操作符為Exists或者DoesNotExist ,value則必須為空[""],如果操作符為Gt或Lt,則value必須有單個元素,該元素將被解釋為整數。
?operator:操作符,指定key與value的關系。
?In:key與value同時存在,一個key多個value的情況下,value之間就成了邏輯或效果。
?NotIn:label 的值不在某個列表中。
?Exists:只判斷是否存在key,不用關心value值是什么。
?DoesNotExist:某個 label 不存在。
?Gt:label 的值大于某個值。
?Lt:label 的值小于某個值
1.創建Pod資源配置清單 如下示例中,Pod模版定義了Node軟親和性運行在標簽key為zone和values為foo或bar上,以及key為ssd(值無需擔心是什么)的Node之上,符合以下需求的是Node01和Node03,但是如下第一個條件key為zoo的權重為60,而key為ssd的為30,所以第一個條件的權重要比第二個條件的權重高一倍,我們下面運行了3個Pod,調度器應該會在Node01上分配兩個Pod,Node03上分配1個Pod。
cat preferred-nodeAffinitt-pod.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: preferred-nodeaffinity-deploy
labels:
type: preferred-deploy
spec:
replicas: 3
selector:
matchLabels:
app: preferred-nodeaffinity-pod
template:
metadata:
labels:
app: preferred-nodeaffinity-pod
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- { key: zone, operator: In, values: ["foo","bar"] }
- weight: 30
preference:
matchExpressions:
- { key: ssd, operator: Exists, values: [] }
containers:
- name: myapp
image: busybox:latest
command: ["/bin/sh", "-c", "tail -f /etc/passwd"]
2.查看調度結果
kubectl get pods -o wide | grep preferred
preferred-nodeaffinity-deploy-5bf4699fd9-pcxvz 1/1 Running 0 5m32s 10.244.5.98 k8s-node03 <none> <none>
preferred-nodeaffinity-deploy-5bf4699fd9-phm8b 1/1 Running 0 5m32s 10.244.3.106 k8s-node01 <none> <none>
preferred-nodeaffinity-deploy-5bf4699fd9-xf87j 1/1 Running 0 5m32s 10.244.3.105 k8s-node01 <none> <none>
3.創建標簽key為app,值為proxy或者web的Pod
cat app_proxy.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-proxy-pod
labels:
app: proxy
spec:
containers:
- name: app-proxy
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
4.查看調度結果
kubectl apply -f app_proxy.yaml
#具備標簽key為app,values的Pod被調度到了node03上
kubectl get pods -owide | grep app-proxy
app-proxy-pod 1/1 Running 0 42s 10.244.5.102 k8s-node03 <none> <none>
#如下podAffinity硬親和性調度也被調度到此Node
kubectl get pods -owide | grep podaff
podaffinity-required-pod 1/1 Running 0 2m30s 10.244.5.103 k8s-node03 <none> <none>
Pod調度之Pod親和性調度
podAffinity介紹
出于高效通信的需求,我們要把幾個Pod對象運行在比較近的位置,例如APP Pod與DB Pod,我們的APP Pod需要連接DB Pod,這個時候就需要把這兩個Pod運行在較近的位置以便于網絡通信,一般可以按照區域、機房、地區等來劃分。像這種類型就屬于Pod的親和性調度。但是有時候出于安全或者分布式考慮,也有可能將Pod運行在不同區域、不同機房,這個時候Pod的關系就是為反親和性。
podAffinity也被分為硬親和性和軟親和性,其原理與Node中的硬親和性及軟親和性一致。
硬親和性(required):硬親和性實現的是強制性規則,它是Pod調度時必須要滿足的規則,而在不存在滿足規則的Node時,Pod對象會被置為Pending狀態。
軟親和性(preferred):軟親和性規則實現的是一種柔性調度限制,它傾向于將Pod對象運行于某類特定節點之上,而調度器也將盡量滿足此需求,但在無法滿足需求時它將退而求其次地選擇一個不匹配規則的節點之上。
定義Pod親和性規則的關鍵點有兩個:
1.為節點配置合乎需求的標簽。
2.為Pod對象定義合理的標簽選擇器labelSelector,從而能夠基于標簽選擇器選擇出符合需求的標簽。
Pod反親和硬親和性
Pod硬親和性調度使用
requiredDuringSchedulingIgnoredDuringExecution屬性進行定義,Pod硬親和性使用topologyKey參數來指定要運行在具備什么樣標簽key的Node上,然后再通過labelSelector選擇你想關聯Pod的標簽,可能有點繞,下面看示例應該就明白了。
Pod硬親和性參數解析:
?labelSelector:標簽選擇器?。
?topologyKey:指定要將當前創建Pod運行在具備什么樣的Node標簽上,通常指定Node標簽的Key。
?namespaces:指定labelSelector應用于哪個名稱空間,null或空列表表示“此pod的名稱空間”。
?matchExpressions:按照Pod label列出節點選擇器列表。(與matchLabels是兩種方式,不過結果是一至)。
?matchLabels:按照節點字段列出節點選擇器列表。(與matchExpressions是兩種方式,不過結果是一至)。
?key:指定要選擇節點label的key。
?values:指定要選擇節點label的value,值必須為數組 ["value"] ,如果操作符為In或者 Notin,value則不能為空,如果操作符為Exists或者DoesNotExist ,value則必須為空[],如果操作符為Gt或Lt,則value必須有單個元素,該元素將被解釋為整數。
?operator:操作符,指定key與value的關系。
?In:key與value同時存在,一個key多個value的情況下,value之間就成了邏輯或效果。
?NotIn:label 的值不在某個列表中。
?Exists:只判斷是否存在key,不用關心value值是什么。
?DoesNotExist:某個 label 不存在。
?Gt:label 的值大于某個值。
?Lt:label 的值小于某個值
1.為Node打上不同地區的標簽 node01標簽為beijing node02標簽為shanghai node03標簽為shenzhen
kubectl label node k8s-node01 zone=beijing
kubectl label node k8s-node02 zone=shanghai
kubectl label node k8s-node03 zone=shenzhen
2.創建資源配置清單 下面清單中,Pod首先會選擇標簽key為zone的Node,我們上面做了三個Node標簽key都為zone,匹配之后,開始在標簽key為zone的Node上尋找標簽key為app,values為proxy或者web的Pod,然后與其運行在那臺Node之上。
cat podaffinity-pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: podaffinity-required-pod
spec:
containers:
- name: nginx-containers
image: nginx:latest
affinity:
podAffinity:
#硬親和性
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
#選擇標簽key為app,values為proxy或者web的Pod,然后與其運行在同一個Node上
- { key: app, operator: In, values: ["proxy","web"] }
#選擇key為zone的Node
topologyKey: zone
3.查看調度結果 如下可以看到,三臺Node上沒有標簽key為app,values為proxy或者web的Pod,我們采用的是硬親和性,所以該Pod一直為Pending狀態。
kubectl apply -f podaffinity-pod.yaml
kubectl get pods -o wide | grep podaffinity
podaffinity-required-pod 0/1 Pending 0 3m43s <none> <none> <none> <none>
4.創建標簽key為app,值為proxy或者web的Pod
cat app_proxy.yaml
apiVersion: v1
kind: Pod
metadata:
name: app-proxy-pod
labels:
app: proxy
spec:
containers:
- name: app-proxy
image: busybox:latest
command: [ "/bin/sh", "-c", "tail -f /etc/passwd" ]
5.查看調度結果
kubectl apply -f app_proxy.yaml
#具備標簽key為app,values的Pod被調度到了node03上
kubectl get pods -owide | grep app-proxy
app-proxy-pod 1/1 Running 0 42s 10.244.5.102 k8s-node03 <none> <none>
#如下podAffinity硬親和性調度也被調度到此Node
kubectl get pods -owide | grep podaff
podaffinity-required-pod 1/1 Running 0 2m30s 10.244.5.103 k8s-node03 <none> <none>
Pod軟親和性
Pod軟親和性使用
preferredDuringSchedulingIgnoredDuringExecution屬性進行定義,Pod軟親和性使用podAffinityTerm屬性來挑選Pod標簽,當調度的Pod對象不再是”必須”,而是“應該”放置于某些特性節點之上,當條件不滿足時,它也能夠接受編排于其它不符合條件的節點之上,另外,它還為每種傾向性提供了weight屬性以便用戶定義其優先級,取值范圍是1-100,數字越大優先級越高。
?Pod軟親和性參數解析:
?podAffinityTerm:Pod親和性選擇器。
?weight:在1-100范圍內,與匹配相應的節點選項相關聯的權重。
?labelSelector:標簽選擇器。
?matchExpressions:按照Pod label列出節點選擇器列表。(與matchLabels是兩種方式,不過結果是一至)。
?matchLabels:按照節點字段列出節點選擇器列表。(與matchExpressions是兩種方式,不過結果是一至)。
?key:指定要選擇節點label的key。
?values:指定要選擇節點label的value,值必須為數組 ["value"] ,如果操作符為In或者 Notin,value則不能為空,如果操作符為Exists或者DoesNotExist ,value則必須為空[],如果操作符為Gt或Lt,則value必須有單個元素,該元素將被解釋為整數。
?operator:操作符,指定key與value的關系。
?In:key與value同時存在,一個key多個value的情況下,value之間就成了邏輯或效果
?NotIn:label 的值不在某個列表中。
?Exists:只判斷是否存在key,不用關心value值是什么。
?DoesNotExist:某個 label 不存在。
?Gt:label 的值大于某個值。
?Lt:label 的值小于某個值
1.創建資源配置清單
下面創建一個Pod軟親和性資源配置清單,定義了兩組親和性判斷機制,一個是選擇cache Pod所在節點的zone標簽,并賦予權重為80,另一個是選擇db Pod所在的zone標簽,權重為20,調度器首先會將Pod調度到具有zone標簽key的Node上,然后將多數Pod調度到具備標簽為app=cache的Pod同節點,其次調度到具備標簽app=db的Pod同節點。
如果Node上的Pod都具備app=cache和app=db,那么根據Pod軟親和性策略,調度器將退而求其次的將Pod調度到其它Node,如果甚至連Node都具備標簽zone鍵,那么根據軟親和策略,調度器還是會退而求其次的將Pod調度到不存在zone鍵的Node上。
cat podaffinity-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: podaffinity-perferred-pod
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
name: myapp
labels:
app: myapp
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
podAffinityTerm:
labelSelector:
matchExpressions:
- { key: app, operator: In, values: ["cache"] }
topologyKey: zone
- weight: 20
podAffinityTerm:
labelSelector:
matchExpressions:
- { key: app, operator: In, values: ["db"] }
topologyKey: zone
containers:
- name: myapp
image: busybox:latest
command: ["/bin/sh", "-c", "tail -f /etc/passwd" ]
2.查看調度結果
#Pod調度結果為node01兩個,node03一個
kubectl get pods -o wide | grep podaffinity-perferred-pod
podaffinity-perferred-pod-7cddc8c964-5tfr2 1/1 Running 0 12m 10.244.5.106 k8s-node03 <none> <none>
podaffinity-perferred-pod-7cddc8c964-kqsmk 1/1 Running 0 12m 10.244.3.109 k8s-node01 <none> <none>
podaffinity-perferred-pod-7cddc8c964-wpqqw 1/1 Running 0 12m 10.244.3.110 k8s-node01 <none> <none>
#以下三個Node都具備標簽鍵為zone,但是這三個Node上沒有Pod標簽為app=cache及app=db,所以上面的調度策略在選擇Pod標簽的時候進行退步才得以將Pod調度到Node01和Node03
k8sops@k8s-master01:~/manifests/pod$ kubectl get nodes -l zone -L zone
NAME STATUS ROLES AGE VERSION ZONE
k8s-node01 Ready <none> 28d v1.18.2 beijing
k8s-node02 Ready <none> 28d v1.18.2 shanghai
k8s-node03 Ready <none> 29d v1.18.2 shenzhen
Pod調度之Pod反親和性調度
podAntiAffinity介紹
Pod反親和性podAntiAffinity用于定義Pod對象的親和約束,Pod反親和性與Pod親和性相反,Pod親和性是將有密切關聯的Pod運行到同一平面、同一個區域或者同一臺機器上,而反親和性是將Pod運行在不同區域、不同機器上,Pod反親和性調度一般用于分散同一類應用的Pod對象等。
podAntiAffinity也被分為硬親和性和軟親和性,其原理與Node中的硬親和性及軟親和性一致。
硬親和性(required):硬親和性實現的是強制性規則,它是Pod調度時必須要滿足的規則,而在不存在滿足規則的Node時,Pod對象會被置為Pending狀態。
軟親和性(preferred):軟親和性規則實現的是一種柔性調度限制,它傾向于將Pod對象運行于某類特定節點之上,而調度器也將盡量滿足此需求,但在無法滿足需求時它將退而求其次地選擇一個不匹配規則的節點之上。
幫助文檔:kubectl explain
pods.spec.affinity.podAntiAffinity
podAntiAffinity示例
1.創建資源配置清單
以下創建了4個Pod,自身標簽為app=myapp,使用Pod反親和的硬親和性,需要運行在具備標簽key為zone的Node上,然后不運行在具備標簽為app=myapp的Pod同臺Node上,我們下面啟動了4個Pod,一共有三個Node,前三個Pod都會被分別調度到不同的三臺Node上(因為采用的是反親和性,還是硬性,所以相同標簽的Pod不會調度到同一臺Node),最后一個Pod將無家可歸,最后無法調度。
cat podAntiAffinity-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: podantiaffinity-perferred-pod
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" ]
2.創建Pod對象
kubectl apply -f podAntiAffinity-deploy.yaml
3.查看調度結果
kubectl get pods -L app -l app=myapp -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES APP
podantiaffinity-perferred-pod-6576cf75c8-5bw9f 0/1 Pending 0 80s <none> <none> <none> <none> myapp
podantiaffinity-perferred-pod-6576cf75c8-bxp4k 1/1 Running 0 80s 10.244.2.88 k8s-node02 <none> <none> myapp
podantiaffinity-perferred-pod-6576cf75c8-d2fcm 1/1 Running 0 80s 10.244.5.107 k8s-node03 <none> <none> myapp
podantiaffinity-perferred-pod-6576cf75c8-dghr9 1/1 Running 0 80s 10.244.3.111 k8s-node01 <none> <none> myapp
4.查看Node標簽
kubectl get nodes -L zone -l zone
NAME STATUS ROLES AGE VERSION ZONE
k8s-node01 Ready <none> 28d v1.18.2 beijing
k8s-node02 Ready <none> 28d v1.18.2 shanghai
k8s-node03 Ready <none> 29d v1.18.2 shenzhen
文章來源于網絡,侵刪!