一、kubernetes調度器
調度器(scheduler)是當創建Pod對象時,負責爲每一個未經調度的Pod資源基於一系列的規則集從集羣中挑選一個合適的節點來運行該Pod。其核心目標是基於資源可用性將各Pod資源公平地分佈於集羣節點之上。
Kubernetes平臺提供的默認調度器稱爲“通用調度器”,它通過節點預選(Prediicate)、節點優先級排序(Priority)及節點擇優(Selete)三個步驟完成調度操作。
1、常用的預選策略
預選策略即節點的過濾器,用於排除掉不適用的節點。預選後如果不存在任何一個滿足條件的節點則Pod被置於Pending狀態,直到至少有一個節點可用位置。常用的預選策略如下:
(1)CheckNodeCondition:檢查是否可以在節點報告磁盤、網絡不可用或未準備好的情況下將Pod對象調度於其上。
(2)HostName:若Pod對象擁有spec.hostname屬性,則檢查節點名稱與此屬性值是否匹配
(3)PodFitsHostPorts:若Pod容器定義了ports.hostPort屬性,則檢查其值指定的端口是否已被節點上的其他容器或服務佔用。
(4)MatchNodeSelector:若Pod對象定義了spec.nodeSelector屬性,則檢查節點標籤是否能匹配此屬性值。
(5)NoDiskConfict:檢查Pod對象請求的存儲卷在此節點是否可用
(6)PodFitsResources:檢查節點是否有足夠的資源滿足Pod對象的運行需求。而那些在註解中標記爲關鍵性(critical)的Pod資源不受此預選策略影響。
(7)PodToleratesNodeTaints:若Pod對象定義了spec.tolerations屬性,則檢查其值是否能夠節點定義的污點(taints)
(8)PodToleratesNodeNoExecuteTaints:若Pod對象定義了spec.tolerations屬性,則檢查其值是否能夠接納節點定義的NoExecute類型的污點。
(9)CheckNodeLabelPresence:僅檢查節點上指定的所有標籤的存在性,要檢查的標籤以及其可否存在取決於用戶的定義。
(10)CheckServiceAffinity:根據當前Pod對象所屬的Service已有的其他Pod對象所運行的節點進行調度,其目的在於將相同的Service的Pod對象放置在同一個或同一類節點上以提高運行效率。
(11)MaxEBSVolumeCount:檢查節點上已掛載的EBS存儲卷的數量是否超過了設置的最大值,默認值爲39
(12)MaxGCEPDVolumeCount:檢查節點上已掛載的GCE PD存儲卷的數量是否超過了設置的最大值,默認值爲16
(13)MaxAzureDiskVolumeCount:檢查節點上已掛載的AzureDisk存儲卷的數量是否超過了設置的最大值,默認值爲16
(14)CheckVolumeBinding:檢查節點上已綁定的和未綁定的PVC是否能夠滿足Pod對象存儲卷需求
(15)NoVolumeZoneConflict:在給定了區域(zone)限制的前提下,檢查此節點部署Pod對象是否存在存儲卷衝突。
(16)CheckNodeMemoryPressure:若給定的節點已經報告了存在內存資源壓力過大的狀態,則檢查當前Pod對象是否可調度至此節點之上。
(17)CheckNodePIDPressure:若給定的節點已經報告了存在PID資源壓力過大的狀態,則檢查當前Pod對象是否可調度至此節點之上。
(18)CheckNodeDiskPressure:若給定的節點已經報告了存在磁盤資源壓力過大的狀態,則檢查當前Pod對象是否可調度至此節點之上。
(19)MatchInterPodAffinity:檢查給定節點是否能夠滿足Pod對象的親和性或反親和性條件,以實現Pod親和性調度或反親和性調度。
2、常用的優選函數
在優選的過程中,調度器向每個通過預選的節點傳遞一系列的優選函數來計算優先級的分值。優先級的分值介於0到10之間。同時,調度器還支持爲每個優選函數指定一個簡單的由正數值標識的權重;進行節點優先級分值計算時,它首先將每個優選函數的計算得分乘以其權重,然後將所有優選函數的得分相加從而得出節點的最終優先級分值。主要的優選函數有:
(1)LeastRequestdPriority:由節點空閒資源與節點總容量的比值計算而來
(2)BalancedResourceAllocation:以CPU和內存資源佔用率的相近程序作爲評估標準,越接近的節點權重越高。該函數要與LeastRequestedPriority組合使用來平衡優化節點資源的使用狀況。
(3)NodePreferAvoidPodPriority:默認權限爲10000,它將根據節點是否設置了註解信息”scheduler.aplha.kubernetes.io/preferAvodPods”來計算其優先級。
(4)NodeAffinityPriority:基於節點親和性調度偏好進行優先級評估,它將根據Pod資源中的nodeSelector對給定節點進行匹配度檢查。
(5)TainTolerationPriority:基於Pod資源對節點的污點容忍度偏好進行其優先級的評估,將Pod對象的tolerations列表與節點的污點進行匹配度檢查,成功匹配的條目越多,則節點得分越低。
(6)SelectorSpreadPrity:此優選函數會盡量將同一標籤選擇器匹配到的Pod資源分散到不同的節點上運行。
(7)InterPodAffinityPriority:遍歷Pod對象的親和性條目,並將那些能夠匹配到給定節點的條目的權重相加,結果值越大的節點得分越高
(8)MostRequestedPriority:與優選函數LeastRequestedPriority的評估節點得分的方法相似,資源佔用比例越大的節點得分越高。
(9)NodeLabelPriority:根據節點是否擁有特定的標籤來評估其得分
(10)ImageLocalityPriority:基於給定節點上擁有的運行當前Pod對象中的容器所依賴到的鏡像文件來計算節點得分。不具有Pod依賴到的任何鏡像文件的節點其得分爲0,而擁有相應鏡像文件的各節點中,所擁有的被依賴到的鏡像文件其體積之和越大則節點得分越高。
二、節點親和調度
節點親和性是調度程序用來確定Pod對象調度位置的一組規則,這組規則基於節點上的自定義標籤和Pod對象上指定的標籤選擇器進行定義。
節點親和性規則有兩種。一是硬親和性,實現強執行規則,二是軟親和性,實現柔性調度規則。定義節點親和規則的關鍵點有兩個,一是爲節點配置合乎需求的標籤,另一個是爲Pod對象定義合理的標籤選擇器。
1、節點硬親和性
節點的親和性可以通過pod.spec.affinity.nodeAffinity字段定義,nodeAffinity字段中支持使用matchExpressions屬性構建更爲複雜的標籤選擇器。
# 定義一個pod資源清單,將該pod調度至有標籤爲zone=foo的節點上
apiVersion: v1
kind: Pod
metadata:
name: required-nodeaffinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- {key: zone, operator: In, values: ["foo"]}
containers:
- name: busybox-test
image: busybox
# 創建並查看該pod資源,由於選擇不到合適的節點所以該pod一直處於pending狀態
]# kubectl apply -f nodeAffinity-test01.yaml
]# kubectl get pods with-requiredth-nodeaffinity
NAME READY STATUS RESTARTS AGE
with-requiredth-nodeaffinity 0/1 Pending 0 89s
# 當爲其中一個節點打上標籤zone=foo後,該pod會選擇該節點並運行起來
]# kubectl label node node02.dayi123.com zone=foo
]# kubectl get pods with-requiredth-nodeaffinity
NAME READY STATUS RESTARTS AGE
with-requiredth-nodeaffinity 1/1 Running 0 24s
定義節點親和性時,requiredDuringSchedulingIgnoredDuringExecution字段的值是一個對象列表,用於定義節點的硬親和性,它可由一個到多個nodeSelectorTerm定義的對象組成,多個對象直接爲或的關係。nodeSelectorTerm用於定義節點選擇器條目,值爲對象列表,可由一個或多個matchExpressions對象定義的匹配規則組成,多個規則之間爲邏輯與的關係。matchExmpressions下的多個標籤選擇器之間的也爲邏輯與的關係。
標籤選擇器表達式中支持使用的操作符有In,NotIn,Exists,DoesNotExists,Lt,Gt等。
2、節點軟親和性
節點軟親和性爲節點選擇提供了一種柔性的控制器邏輯,當條件不滿足時,也能夠接受被編排與其他不符合條件的節點之上。同時他還爲每種傾向性提供了weight屬性以便用於自定義優先級,範圍是1-100,越大越優。
# 給節點node打標籤
]# kubectl label node node01.dayi123.com server=nginx
# 定義一個基於deployment控制器的軟親和度資源配置清單
]# cat deploy-preferred-nodeAffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: deploy-with-node-affinity
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 60
preference:
matchExpressions:
- {key: server, operator: In, values: ["nginx"]}
- weight: 30
preference:
matchExpressions:
- {key: zone, operator: In, values: ["foo"]}
containers:
- name: nginx
image: nginx:1.12
三、Pod資源親和調度
出於某些需求,將一些Pod對象組織在相近的位置(同一節點、機架、區域等),此時這些這些pod對象間的關係爲親和性;而出於安全或分佈式等原因將一些Pod對象在其運行的位置上隔離開,此時這些pod對象的關係稱之爲反親和性。
Pod的親和性調度也存在硬親和性和軟親和性的區別,他們表示的約束意義同節點親和性相似。Kubernetes調度器通過內建的MatchInterPodAffinity預選策略爲這種調度方式完成節點的預選並基於InterPodAffinityPriority優選函數進行各節點的優選級評估。
在定義Pod對象的親和性和反親和性時,需要藉助於標籤選擇器來選擇被依賴的Pod對象,並根據選出的Pod對象所在的節點的標籤來判定“同一位置”的具體意義。
1、Pod資源的硬親和性調度
Pod硬親和性調度也使用requiredDuringSchedulingIgnoreDuringExecution屬性進行定義。
# 先創建一個運行tomcat的pod,並打一個標籤爲server=tomcat
]# kubectl run tomcat -l server=tomcat --image=tomcat:latest
# 定義一個硬親和性調度的pod
]# cat podaffinity-test01.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: server, operator: In, values: ["tomcat"]}
topologyKey: kubernetes.io/hostname
containers:
- name: server-nginx
image: nginx:1.12
# 創建後查看是兩個pod會被調度至同一個node上
]# kubectl get pods tomcat-65865b6bd-2fpkj pod-affinity -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
tomcat-65865b6bd-2fpkj 1/1 Running 0 35m 10.244.2.51 node02.dayi123.com <none> <none>
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-affinity 1/1 Running 0 3m27s 10.244.2.52 node02.dayi123.com <none> <none>
2、Pod的軟親和性調度
Pod軟親和調度使用方法與Node軟親和調度方法類似。
]# cat deploy-preferred-podaffinity.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: pod-affinity
spec:
replicas: 3
selector:
matchLabels:
app: myserver
template:
metadata:
name: myserver
labels:
app: myserver
spec:
affinity:
podAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 80
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["tomcat"]}
topologyKey: zone
- weight: 20
podAffinityTerm:
labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["myapp"]}
topologyKey: zone
containers:
- name: nginx-test
image: nginx:1.12
3、Pod的反親和性調度
Pod的反親和性調度通過spec.affinity.podAntiAffinity字段定義,反親和性調度用於分散同一類應用的Pod對象,也用於將不同安全級別的Pod對象調度至不同的區域或節點。Pod的反親和性調度也支持硬性和柔性調度機制,用法同pod的硬性柔性調度機制類似。
四、污點和容忍度
污點:定義在節點之上的鍵值性屬性數據,用於讓節點拒絕將Pod調度運行於其上,除非該Pod對象具有接納節點污點的容忍度
容忍度:定義在Pod對象上的鍵值型的屬性數據,用於配置其可容忍的節點污點,而且調度器僅能將Pod對象調度至其能夠容忍該節點污點的節點之上。
K8s系統使用PodToleratesNodeTaints預選策略和TainTolerationPriority優選函數來完成此種類型的高級調度機制。
1、定義污點和容忍度
污點信息在節點的node.Spec字段中定義,容忍度信息在pod的pod.spec字段中定義,他們都是鍵值型數據,但都額外支持一個效果(effect)標記,語法格式爲“key=value:effect”。Effect主要用於定義對Pod對象的排斥等級,主要的類型如下:
(1)NoSchedule:不能容忍此污點的Pod對象不可調度至當前節點,屬於強制約束性的關係,對節點現存Pod對象不受影響。
(2)PreferNoSchedule:NoSchedule的柔性約束版本,不能容忍此污點的Pod對象儘量不要調度至當前節點
(3)NoExecute:不能容忍此污點的新Pod對象不可調度至當前節點,屬強制型約束關係,而且節點上現存的Pod對象因節點污點變動或Pod容忍度變動而不再滿足匹配規則時Pod對象將被驅逐。
在Pod對象上定義容忍度時,支持兩種操作符:一種是等值比較(Equal),表示容忍度與污點必須在key、value、和effect三者之上完全匹配;二是存在性的判斷(Exists),表示二者的key和effect必須完全匹配,容忍度中的value值要使用空值。
使用kubeadm部署的kubernetes集羣,其master節點將自動添加污點信息以阻止不能容忍此污點的Pod對象調度至此節點。而一些系統應用在創建時就添加了相應的容忍度以確保被DaemonSet控制器創建時能夠調度至Master節點運行一個實例。
# 查看master節點的污點
]# kubectl get nodes master01.dayi123.com -o yaml
. . . . . .
spec:
podCIDR: 10.244.0.0/24
taints:
- effect: NoSchedule
key: node-role.kubernetes.io/master
. . . . . .
# 查看系統及應用的容忍度
]# kubectl get pods coredns-86c58d9df4-jnhz4 -n kube-system -o yaml
. . . . . .
tolerations:
- key: CriticalAddonsOnly
operator: Exists
- effect: NoSchedule
key: node-role.kubernetes.io/master
- effect: NoExecute
key: node.kubernetes.io/not-ready
operator: Exists
tolerationSeconds: 300
- effect: NoExecute
key: node.kubernetes.io/unreachable
operator: Exists
tolerationSeconds: 300
. . . . . .
2、管理節點的污點
節點污點的定義可以使用字母、數字、連接符、點號、和下劃線且只能以字母或數字開頭,鍵名的上限爲253各字符,值上限爲63個字符,向節點添加污點可通過“kubectl taint”名令添加。語法格式如下:
kubectl taint nodes <node-name> <key>=[:<effect>]
對node1節點添加污點並查看污點信息:
]# kubectl taint nodes node01.dayi123.com node-type=production:NoSchedule
]# kubectl get nodes node01.dayi123.com -o go-template={{.spec.taints}}
[map[effect:NoSchedule key:node-type value:production]]
刪除污點的語法格式如下:
kubectl taint nodes <node-name> <key>=[:<effect>]-
刪除污點的具體用法如下:
# 刪除node1節點上node-type的鍵效用標識爲”Noschedule”的污點信息
]# kubectl taint nodes node01.dayi123.com node-type:NoSchedule-
# 刪除指定鍵名的所有污點,只需在刪除命令中省略效率標識即能實現
]# kubectl taint nodes node01.dayi123.com noed-type-
# 刪除節點上的全部污點信息,通過kubectl patch命令將節點屬性spec.taints的值直接置空即可。
]# kubectl patch nodes nodes01.dayi123.com -p '{"spec":{"taints":[]}}'
3、Pod對象的容忍度
Pod對象的容忍度可通過其spec.tolerations字段進行添加,根據使用的操作符不同,主要由兩種可用的形式,一種是與污點信息完全匹配的等值關係Equal;另一種是判斷污點信息存在性的匹配方式Exists。
# 給node1節點定義一個污點
]# kubectl taint nodes node01.dayi123.com node-type=production:NoExecute
# 定義Pod資源清單並定義該污點容忍度
]# cat pod-tolerations.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-toler
spec:
tolerations:
- key: node-type
operator: "Equal"
value: "production"
effect: "NoExecute"
tolerationSeconds: 3600
containers:
- name: server-nginx
image: nginx:1.12
4、問題節點的標識
問題節點的標識是通過節點控制器在特定條件下自動爲節點添加污點信息實現,它們都使用NoExecute效用標識。