一、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效用辨別。