Scheduler工作原理
請求及Scheduler調度步驟:
- 節點預選(Predicate):排除完全不滿足條件的節點,如內存大小,端口等條件不滿足。
- 節點優先級排序(Priority):根據優先級選出最佳節點
- 節點擇優(Select):根據優先級選定節點
-
首先用戶通過 Kubernetes 客戶端 Kubectl 提交創建 Pod 的 Yaml 的文件,向Kubernetes 系統發起資源請求,該資源請求被提交到
-
Kubernetes 系統中,用戶通過命令行工具 Kubectl 向 Kubernetes 集羣即 APIServer 用 的方式發送“POST”請求,即創建 Pod 的請求。
-
APIServer 接收到請求後把創建 Pod 的信息存儲到 Etcd 中,從集羣運行那一刻起,資源調度系統 Scheduler 就會定時去監控 APIServer
-
通過 APIServer 得到創建 Pod 的信息,Scheduler 採用 watch 機制,一旦 Etcd 存儲 Pod 信息成功便會立即通知APIServer,
-
APIServer會立即把Pod創建的消息通知Scheduler,Scheduler發現 Pod 的屬性中 Dest Node 爲空時(Dest Node=””)便會立即觸發調度流程進行調度。
-
而這一個創建Pod對象,在調度的過程當中有3個階段:節點預選、節點優選、節點選定,從而篩選出最佳的節點
- 節點預選:基於一系列的預選規則對每個節點進行檢查,將那些不符合條件的節點過濾,從而完成節點的預選
- 節點優選:對預選出的節點進行優先級排序,以便選出最合適運行Pod對象的節點
- 節點選定:從優先級排序結果中挑選出優先級最高的節點運行Pod,當這類節點多於1個時,則進行隨機選擇
k8s的調用工作方式
Kubernetes調度器作爲集羣的大腦,在如何提高集羣的資源利用率、保證集羣中服務的穩定運行中也會變得越來越重要Kubernetes的資源分爲兩種屬性。
- 可壓縮資源(例如CPU循環,Disk I/O帶寬)都是可以被限制和被回收的,對於一個Pod來說可以降低這些資源的使用量而不去殺掉Pod。
- 不可壓縮資源(例如內存、硬盤空間)一般來說不殺掉Pod就沒法回收。未來Kubernetes會加入更多資源,如網絡帶寬,存儲IOPS的支持。
常用預選策略
預選策略 | 作用 |
---|---|
CheckNodeCondition | 檢查是否可以在節點報告磁盤、網絡不可用或未準備好時將Pod調度其上 |
HostName | 如果Pod對象擁有spec.hostname屬性,則檢查節點名稱字符串是否和該屬性值匹配。 |
PodFitsHostPorts | Pod的spec.hostPort屬性時,檢查端口是否被佔用 |
MatchNodeSelector | Pod的spec.nodeSelector屬性時,檢查節點標籤 |
NoDiskConflict | Pod依賴的存儲卷在此節點是否可用,默認沒有啓用 |
PodFitsResources | 檢查節點上的資源(CPU、內存)可用性是否滿足Pod對象的運行需求。 |
PodToleratesNodeTaints | Pod的spec.tolerations屬性,僅關注NoSchedule和NoExecute兩個效用標識的污點 |
PodToleratesNodeNoExecuteTaints | Pod的spec.tolerations屬性,是否能接納節點的NoExecute類型污點,默認沒有啓用 |
CheckNodeLabelPresence | 僅檢查節點上指定的所有標籤的存在性,默認沒有啓用 |
CheckServiceAffinity | 將相同Service的Pod對象放置在同一個或同一類節點上以提高效率,默認沒有啓用 |
MaxEBSVolumeCount | 檢查節點已掛載的EBS(亞馬遜彈性塊存儲)存儲卷數量是否超過設置的最大值,默認爲39 |
MaxGCEPDVolumeCount | 檢查節點上已掛載的GCE PD(谷歌雲存儲) 存儲卷數量是否超過最大值,默認爲16 |
MaxAzureDiskVolumeCount | 檢查節點上已掛載的Azure Disk存儲卷數量是否超過最大值,默認爲16 |
CheckVolumeBinding | 檢查節點上已綁定和未綁定的PVC是否滿足需求 |
NoVolumeZoneConflict | 在給定區域zone限制下,檢查此節點部署的Pod對象是否存在存儲卷衝突 |
CheckNodeMemoryPressure | 檢查節點內存壓力,如果壓力過大,那就不會講pod調度至此 |
CheckPodePIDPressure | 檢查節點PID資源壓力 |
CheckNodeDiskPressure | 檢查節點磁盤資源壓力 |
MatchInterPodAffinity | 檢查節點是否滿足Pod對象親和性或反親和性條件 |
常用優先函數
函數名稱 | 詳細說明 |
---|---|
LeastRequestedPriority | 節點的優先級就由節點空閒資源與節點總容量的比值,即由(總容量-節點上Pod的容量總和-新Pod的容量)/總容量)來決定。 CPU和內存具有相同權重,資源空閒比越高的節點得分越高。 cpu((capacity – sum(requested)) * 10 / capacity) + memory((capacity – sum(requested)) * 10 / capacity) / 2 |
BalancedResourceAllocation | CPU和內存使用率越接近的節點權重越高,該策略不能單獨使用,必須和LeastRequestedPriority組合使用,儘量選擇在部署Pod後各項資源更均衡的機器。 如果請求的資源(CPU或者內存)需求大於節點的capacity,那麼該節點永遠不會被調度到。 |
InterPodAffinityPriority | 通過迭代 weightedPodAffinityTerm 的元素計算和,並且如果對該節點滿足相應的PodAffinityTerm,則將 “weight” 加到和中,具有最高和的節點是最優選的。 |
SelectorSpreadPriority | 爲了更好的容災,對同屬於一個service、replication controller或者replica的多個Pod副本,儘量調度到多個不同的節點上。 如果指定了區域,調度器則會盡量把Pod分散在不同區域的不同節點上。當一個Pod的被調度時,會先查找Pod對於的service或者replication controller, 然後查找service或replication controller中已存在的Pod,運行Pod越少的節點的得分越高。本質就是往運行同類pod少的節點上分配。 |
NodeAffinityPriority | 親和性機制。Node Selectors(調度時將pod限定在指定節點上), 支持多種操作符(In, NotIn, Exists, DoesNotExist, Gt, Lt),而不限於對節點labels的精確匹配。 另外支持兩種類型的選擇器,一種是“hard(requiredDuringSchedulingIgnoredDuringExecution)”選擇器, 它保證所選的主機必須滿足所有Pod對主機的規則要求。 這種選擇器更像是之前的nodeselector,在nodeselector的基礎上增加了更合適的表現語法。 另一種是“soft(preferresDuringSchedulingIgnoredDuringExecution)”選擇器, 它作爲對調度器的提示,調度器會盡量但不保證滿足NodeSelector的所有要求。 |
NodePreferAvoidPodsPriority(權重1W) | 如果 節點的 Anotation (註解信息)沒有設置 key-value:scheduler. alpha.kubernetes.io/ preferAvoidPods = "...",則節點對該 policy 的得分就是10分, 加上權重10000,那麼該node對該policy的得分至少10W分。如果Node的Anotation設置了, scheduler.alpha.kubernetes.io/preferAvoidPods = "..." ,如果該 pod 對應的 Controller 是 ReplicationController 或 ReplicaSet, 則該 node 對該 policy 的得分就是0分。 |
TaintTolerationPriority | 使用 Pod 中 tolerationList 與 節點 Taint 列表項進行匹配,配對成功的項越多,則得分越低。污點越匹配,得分越低 |
ImageLocalityPriority | 根據Node上是否存在一個pod的容器運行所需鏡像大小對優先級打分,分值爲0-10。遍歷全部Node, 如果某個Node上pod容器所需的鏡像一個都不存在,分值爲0; 如果Node上存在Pod容器部分所需鏡像,則根據滿足當前需求的鏡像的大小來決定分值,鏡像越大,分值就越高;如果Node上存在pod所需全部鏡像,分值爲10。默認沒有啓用 |
EqualPriority | 是一個優先級函數,它給予所有節點相等權重。 |
MostRequestedPriority | 在 ClusterAutoscalerProvider 中,替換 LeastRequestedPriority,給使用多資源的節點,更高的優先級。 計算公式爲: (cpu(10 sum(requested) / capacity) + memory(10 sum(requested) / capacity)) / 2 默認沒有啓用 |
節點親和性調度
節點親和性規則:硬親和性 required 、軟親和性 preferred。
- 硬親和性規則不滿足時,Pod會置於Pending狀態,軟親和性規則不滿足時,會選擇一個不匹配的節點
- 當節點標籤改變而不再符合此節點親和性規則時,不會將Pod從該節點移出,僅對新建的Pod對象生效
節點硬親和性
requiredDuringSchedulingIgnoredDuringExecution
- 方式一:Pod使用 spec.nodeSelector (基於等值關係)
- 方式二:Pod使用 spec.affinity 支持matchExpressions屬性 (複雜標籤選擇機制)
- 注意:所有的選擇都是通過主機名,或給 node打標籤後,再根據標籤選擇的
# 調度至 zone = foo 的節點
kubectl label nodes kube-node1 zone=foo
apiVersion: v1
kind: Pod
metadata:
name: with-required-nodeaffinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 定義硬親和性
nodeSelectorTerms:
- matchExpressions: #集合選擇器
- {key: zone,operator: In,values: ["foo"]}
containers:
- name: myapp
image: ikubernetes/myapp:v1
節點軟親和性
preferredDuringSchedulingIgnoredDuringExecution
- 柔性控制邏輯,當條件不滿足時,能接受被編排於其他不符合條件的節點之上
- 權重 weight 定義優先級,1-100 值越大優先級越高
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy-with-node-affinity
spec:
replicas: 2
selector:
matchLabels:
app: myapp
template:
metadata:
name: myapp-pod
labels:
app: myapp
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: #節點軟親和性
- weight: 60
preference:
matchExpressions:
- {key: zone, operator: In, values: ["foo"]}
- weight: 30
preference:
matchExpressions:
- {key: ssd, operator: Exists, values: []}
containers:
- name: myapp
image: ikubernetes/myapp:v1
Pod資源親和調度
- Pod對象間
親和性
,將一些Pod對象組織在相近的位置(同一節點、機架、區域、地區) - Pod對象間
反親和性
,將一些Pod在運行位置上隔開
調度器將第一個Pod放置於任何位置,然後與其有親和或反親和關係的Pod據此動態完成位置編排
# 基於MatchInterPodAffinity
預選策略完成節點預選,基於InterPodAffinityPriority
優選函數進行各節點的優選級評估
位置拓撲,定義"同一位置"
Pod硬親和調度
requiredDuringSchedulingIgnoredDuringExecution
Pod親和性描述一個Pod與具有某特徵的現存Pod運行位置的依賴關係;即需要事先存在被依賴的Pod對象
# 被依賴Pod
kubectl run tomcat -l app=tomcat --image tomcat:alpine
kubectl explain pod.spec.affinity.podAffinity.requiredDuringSchedulingIgnoredDuringExecution.topologyKey
apiVersion: v1
kind: Pod
metadata:
name: with-pod-affinity
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬親和調度
- labelSelector:
matchExpressions: #集合選擇器
- {key: app, operator: In, values: ["tomcat"]} # 選擇被依賴Pod
# 上面意思是,當前pod要跟標籤爲app值爲tomcat的pod在一起
topologyKey: kubernetes.io/hostname # 根據挑選出的Pod所有節點的hostname作爲同一位置的判定
containers:
- name: myapp
image: ikubernetes/myapp:v1
Pod軟親和調度
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-with-preferred-pod-affinity
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: ikubernetes/myapp:v1
Pod反親和調度
Pod反親和調度用於分散同一類應用,調度至不同的區域、機架或節點等
將 spec.affinity.podAffinity
替換爲 spec.affinity.podAntiAffinity
反親和調度也分爲柔性約束和強制約束
apiVersion: v1
kind: Pod
metadata:
name: pod-first
labels:
app: myapp
tier: fronted
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
---
apiVersion: v1
kind: Pod
metadata:
name: pod-second
labels:
app: backend
tier: db
spec:
containers:
- name: busybox
image: busybox:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh", "-c", "sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["myapp"]}
topologyKey: zone
污點和容忍度
污點 taints 是定義在節點
上的鍵值型屬性數據,用於讓節點拒絕將Pod調度運行於其上,除非Pod有接納節點污點的容忍度容忍度 tolerations 是定義在Pod
上的鍵值屬性數據,用於配置可容忍的污點,且調度器將Pod調度至其能容忍該節點污點的節點上或沒有污點的節點上
使用PodToleratesNodeTaints預選策略和TaintTolerationPriority優選函數完成該機制
- 節點親和性使得Pod對象被吸引到一類特定的節點 (nodeSelector和affinity)
- 污點提供讓節點排斥特定Pod對象的能力
定義污點和容忍度
污點定義於nodes.spec.taints
容忍度定義於pods.spec.tolerations
語法: key=value:effect
effect定義排斥等級:
NoSchedule
,不能容忍,但僅影響調度過程,已調度上去的pod不受影響,僅對新增加的pod生效。PreferNoSchedule
,柔性約束,節點現存Pod不受影響,如果實在是沒有符合的節點,也可以調度上來NoExecute
,不能容忍,當污點變動時,Pod對象會被驅逐
在Pod上定義容忍度時:
- 等值比較 容忍度與污點在key、value、effect三者完全匹配
- 存在性判斷 key、effect完全匹配,value使用空值
一個節點可配置多個污點,一個Pod也可有多個容忍度
管理節點的污點
同一個鍵值數據,effect不同,也屬於不同的污點
給節點添加污點:
kubectl taint node <node-name> <key>=<value>:<effect>
kubectl taint node node2 node-type=production:NoShedule #舉例
查看節點污點:
kubectl get nodes <nodename> -o go-template={{.spec.taints}}
刪除節點污點:
kubectl taint node <node-name> <key>[:<effect>]-
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'
kubectl taint node kube-node1 node-type=production:NoSchedule
kubectl get nodes kube-node1 -o go-template={{.spec.taints}}
# 刪除key爲node-type,effect爲NoSchedule的污點
kubectl taint node kube-node1 node-type:NoSchedule-
# 刪除key爲node-type的所有污點
kubectl taint node kube-node1 node-type-
# 刪除所有污點
kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}'
給Pod對象容忍度
spec.tolerations
字段添加tolerationSeconds
用於定義延遲驅逐Pod的時長
# 等值判斷
tolerations:
- key: "key1"
operator: "Equal" #判斷條件爲Equal
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
# 存在性判斷
tolerations:
- key: "key1"
operator: "Exists" #存在性判斷,只要污點鍵存在,就可以匹配
effect: "NoExecute"
tolerationSeconds: 3600
apiVersion: v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
tolerations:
- key: "node-type"
operator: "Equal"
value: "production":
effect: "NoExecute"
tolerationSeconds: 3600
問題節點標識
自動爲節點添加污點信息,使用NoExecute效用標識,會驅逐現有Pod
K8s核心組件通常都容忍此類污點
node.kubernetes.io/not-ready 節點進入NotReady狀態時自動添加
node.alpha.kubernetes.io/unreachable 節點進入NotReachable狀態時自動添加
node.kubernetes.io/out-of-disk 節點進入OutOfDisk狀態時自動添加
node.kubernetes.io/memory-pressure 節點內存資源面臨壓力
node.kubernetes.io/disk-pressure 節點磁盤面臨壓力
node.kubernetes.io/network-unavailable 節點網絡不可用
node.cloudprovider.kubernetes.io/uninitialized kubelet由外部雲環境程序啓動時,自動添加,待到去控制器初始化此節點時再將其刪除
Pod優選級和搶佔式調度
優選級,Pod對象的重要程度
優選級會影響節點上Pod的調度順序和驅逐次序
一個Pod對象無法被調度時,調度器會嘗試搶佔(驅逐)較低優先級的Pod對象,以便可以調度當前Pod
Pod優選級和搶佔機制默認處於禁用狀態
啓用:同時爲kube-apiserver、kube-scheduler、kubelet程序的 --feature-gates 添加 PodPriority=true
使用:
事先創建優先級類別,並在創建Pod資源時通過 priorityClassName屬性指定所屬的優選級類別