k8s-高级调度方式
调度器优良的调度是分布式系统的核心。Scheduler调度器做为Kubernetes三大核心组件之一, 承载着整个集群资源的调度功能,其根据特定调度算法和策略,将Pod调度到最优工作节点上,从而更合理与充分的利用集群计算资源,使资源更好的服务于业务服务的需求。随着业务服务不断Docker化与微服务化,Kubernetes集群规模不断的扩大,而Kubernetes调度器作为集群的中枢系统,在如何..
调度器
优良的调度是分布式系统的核心。Scheduler调度器做为Kubernetes三大核心组件之一, 承载着整个集群资源的调度功能,其根据特定调度算法和策略,将Pod调度到最优工作节点上,从而更合理与充分的利用集群计算资源,使资源更好的服务于业务服务的需求。
随着业务服务不断Docker化与微服务化,Kubernetes集群规模不断的扩大,而Kubernetes调度器作为集群的中枢系统,在如何提高集群的底层计算资源利用率、保证集群中服务的稳定运行中也就变得尤为重要。
调度流程
kube-scheduler的根本工作任务是根据各种调度算法将Pod绑定(bind)到最合适的工作节点,整个调度流程分为两个阶段:预选策略(Predicates)和优选策略(Priorities)。
预选(Predicates):输入是所有节点,输出是满足预选条件的节点。kube-scheduler根据预选策略过滤掉不满足策略的Nodes。例如,如果某节点的资源不足或者不满足预选策略的条件如“Node的label必须与Pod的Selector一致”时则无法通过预选。
优选(Priorities):输入是预选阶段筛选出的节点,优选会根据优先策略为通过预选的Nodes进行打分排名,选择得分最高的Node。例如,资源越富裕、负载越小的Node可能具有越高的排名。
值得一提的是,如果在预选阶段没有节点满足条件,Pod会一直处在Pending状态直到出现满足的节点,在此期间调度器会不断的进行重试。
Pod的整个启动流程总结:
- 资源管控中心Controller Manager创建新的Pod,将该Pod加入待调度的Pod列表。
- kube-scheduler通过API Server提供的接口监听Pods,获取待调度pod,经过预选和优选两个阶段对各个Node节点打分排序,为待调度Pod列表中每个对象选择一个最优的Node。
- kube-scheduler将Pod与Node的绑定写入etcd(元数据管理服务)。
- 节点代理服务kubelet通过API Server监听到kube-scheduler产生的绑定信息,获得Pod列表,下载Image并启动容器,然后由kubelet负责拉起Pod。
预选策略(Predicates)
1.基于存储卷数量的判断
- MaxEBSVolumeCount:确保已挂载的EBS存储卷数量不超过设置的最大值(默认39),调度器会检查直接或及间接使用这种类型存储的PVC,累加总数,如果卷数目超过设最大值限制,则不能调度新Pod到这个节点上。
- MaxGCEPDVolumeCount:同上,确保已挂载的GCE存储卷数量不超过预设的最大值(默认16)。
- MaxAzureDiskVolumeCount:同上,确保已挂载的Azure存储卷不超过设置的最大值(默认16)。
2.基于资源压力状态的判断
- CheckNodeMemoryPressure:判断节点是否已经进入到内存压力状态,如果是则只允许调度内存为0标记的Pod。
- CheckNodeDiskPressure:判断节点是否已经进入到磁盘压力状态,如果是,则不能调度新的Pod。
3.基于卷冲突的判断
- NoDiskConflict:卷冲突判断,即如果该节点已经挂载了某个卷,其它同样使用相同卷的Pod将不能再调度到该节点。
- NoVolumeZoneConflict:对于给定的某块区域,判断如果在此区域的节点上部署Pod是否存在卷冲突。
- NoVolumeNodeConflict:对于某个指定节点,检查如果在此节点上部署Pod是否存在卷冲突。
4.基于约束关系的判断
- MatchNodeSelector:检查节点标签(label)是否匹配Pod指定的nodeSelector,是则通过预选。
- MatchInterPodAffinity:根据Pod之间的亲和性做判断。
- PodToleratesNodeTaints:排斥性关系,即判断Pod不允许被调度到哪些节点。这里涉及到两个概念Taints(污点)和Toleration(容忍)。Node可以定义一或多个Taint,Pod可以定义一或多个Toleration,对于具有某个Taint的节点,只有遇到能容忍它的(即带有对应Toleration的)Pod,才允许Pod被调度到此节点,从而避免Pod被分配到不合适的节点。
5.基于适合性的判断
- PodFitsResources:检查节点是否有足够资源(如CPU、内存、GPU等)满足Pod的运行需求。
- PodFitsHostPorts:检查Pod容器所需的HostPort是否已被节点上其它容器或服务占用。如果已被占用,则禁止Pod调度到该节点。
- PodFitsHost:检查Pod指定的NodeName是否匹配当前节点。
优选策略(Priorities)
优选过程会根据优选策略对每个候选节点进行打分,最终把Pod调度到分值最高的节点。kube-scheduler用一组优先级函数处理每个通过预选的节点,每个函数返回0-10的分数,各个函数有不同权重,最终得分是所有优先级函数的加权和
优选的优先级函数包括:
-
LeastRequestedPriority(默认权重1):尽量将Pod调度到计算资源占用比较小的Node上,这里涉及两种计算资源:内存和CPU。计算公式如下:其中,capacity表示该节点的现有容量,requested表示Pod所请求的容量。
-
BalancedResourceAllocation(默认权重1):CPU和内存使用率越接近的节点权重越高。该策略均衡了节点CPU和内存的配比,尽量选择在部署Pod后各项资源更均衡的机器。该函数不能单独使用,必须和LeastRequestedPriority同时使用,因为如果请求的资源(CPU或者内存)大于节点的capacity,那么该节点永远不会被调度到。计算公式如下:
-
SelectorSpreadPriority(默认权重1):把属于同一个Service或者ReplicationController的Pod,尽量分散在不同的节点上,如果指定了区域,则尽量把Pod分散在该区域的不同节点。通常来说节点上已运行的Pod越少,节点分数越高。计算公式如下,是基于节点的计算和基于区域的计算的加权和,其中,maxPriority代表系数,默认为10,maxCount为节点最多允许运行的Pod数量,nodeCount为该节点已经存在的Pod数量,maxCountByZone为该区域最多允许的Pod数量,zoneCount为区域内已经运行的Pod数量。
-
NodeAffinityPriority(默认权重1):尽量调度到标签匹配Pod属性要求的节点,判断行为与预选中的MatchNodeSelector相似,未来可能会完全将其取代。
该函数提供两种选择器:requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。前者是强要求,指定将Pod调度到节点上必须满足的所有规则;后者是弱要求,即尽可能调度到满足特定限制的节点,但允许不满足。计算公式如下,在节点满足requiredDuringSchedulingIgnoredDuringExecution后,该节点会累加preferredDuringSchedulingIgnoredDuringExecution中所有满足条件的规则的权值weight_i,CountWeight为preferredDuringSchedulingIgnoredDuringExecution中所有规则的权值总和:
- InterPodAffinityPriority(默认权重1):叠加该节点已调度的每个Pod的权重,权重可配置文件里设定,通常亲和性越强的Pod权重越高,如果Pod满足要求则将加到权重和,具有最高权重和的节点是最优的。提供两种选择器:requiredDuringSchedulingIgnoredDuringExecution(保证所选的主机必须满足所有Pod对主机的规则要求)、preferredDuringSchedulingIgnoredDuringExecution(调度器会尽量但不保证满足NodeSelector的所有要求)。
计算公式如下,其中,weight_i为节点上符合亲和性的每个Pod的权重,sumCount为节点上符合亲和性的Pod权重和,maxCount为节点上所有Pod的权重和,minCount为节点上最小的Pod权重,maxPriority是系数,默认为10。
-
NodePreferAvoidPodsPriority(默认权重10000):避免将ReplicationController或ReplicaSet调度到节点。如果Pod由RC或者RS的Controller调度,则得分为0,不对最终加权得分产生影响;如果不是,则总分为100000,意味着覆盖其他策略,直接决定最优节点。
-
TaintTolerationPriority(默认权重1):Pod与Node的排斥性判断。通过Pod的tolerationList与节点Taint进行匹配,配对失败的项越少得分越高,类似于Predicates策略中的PodToleratesNodeTaints。计算公式如下:其中,totalTaints表示Taint总个数,intolerableTaints表示配对不成功的个数。
-
ImageLocalityPriority(默认权重1):尽量调度到Pod所需镜像的节点。检查Node是否存在Pod所需镜像:如果不存在,返回0分;如果存在,则镜像越大得分越高。计算公式如下:其中,sumSize表示该节点上存在的Pod所需镜像大小总和,maxImgSize表示Pod所需镜像总大小,minImgSize表示Pod所需最小镜像的尺寸。
-
EqualPriority(默认权重1):给予所有节点相等权重,一般仅用于测试。
-
MostRequestedPriority(默认权重1):适用于动态伸缩集群环境,会优先调度Pod到使用率最高的节点,方便在伸缩集群时,先腾出空闲机器,从而进行停机处理。
调度方式案例展示:
调度方式总结为:
- 节点选择器(nodeSelector)
- 节点亲和调度(nodeAffinity)
- pod亲和调度 (podAffinity、podAntiAffinity)
- 污点调度
节点选择器(nodeSelector)
apiVersion: v1
kind: Pod
metadata:
name: pod-demo
labels:
app: myapp
tier: frontent
spec:
containers:
- name: myapp
image: docker.io/busybox
imagePullPolicy: "IfNotPresent"
command: ["sh","-c","sleep 3600"]
nodeSelector:
disktype: harddisk #指定该pod调度到有disktype=harddisk 标签的node节点上
$kubectl apply -f pod-demo.yaml
pod "pod-demo" created
$kubectl get pods
NAME READY STATUS RESTARTS AGE
pod-demo 0/1 Pending 0 1m #由于集群所以节点上都没有disktype=harddisk标签,所以pod为“Pending”状态
$kubectl label node k8s-b disktype=harddisk #为node打标签
$kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
pod-demo 1/1 Running 0 7m 10.244.1.75 k8s-b #可见pod被成功调度
$kubectl label node k8s-b disktype- #去处node标签
node "k8s-b" labeled
亲和性调度
preferredDuringSchedulingIgnoreDuringExecution:软亲和性;不管节点上能否满足设定条件,Pod都可以被调度,只是Pod优先被调度到符合条件多的节点上。
- preference:##与相应权重相关联的节点选择器项。
matchExpressions:##按节点标签列出的节点选择器要求列表
- key: ##键
operator:##表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values: ##值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
matchFields:##按节点字段列出的节点选择器要求列表
- key: ##键
operator:##表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values: ##值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
weight: ##权重,0~100的数值
requiredDuringSchedulingIgnoreDuringExecution: 硬亲和性;节点必须满足设定条件,Pod才能被调度到这个节点。
nodeSelectorTerms: ##节点选择器列表
- matchExpressions:##按节点标签列出的节点选择器要求列表
- key: ##键
operator:##表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values: ##值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
matchFields:##按节点字段列出的节点选择器要求列表
- key: ##键
operator:##表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values: ##值;若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
example 节点亲和调度(nodeAffinity):
硬亲和
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-demo
namespace: default
spec:
containers:
- name: app
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: ## 硬亲和性
nodeSelectorTerms:
- matchExpressions:
- key: zone ## 检查有zone标签的节点
operator: In
values: ["foo","bar"] ## zone标签的值是foo 或 bar
软亲和
apiVersion: v1
kind: Pod
metadata:
name: pod-nodeaffinity-demo2
labels:
app: myapp
tier: fronttend
spec:
containers:
- name: myapp
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution: ## 软亲和
- preference:
matchExpressions:
- key: zone ## 即使任何节点都没有zone标签,也会找个节点让Pod运行起来。
operator: In
values: ["foo", "bar"]
weight: 60
example pod亲和调度 (podAffinity):
表示一组pod更倾向与运行在一起,一般需要高效通信时需要将pod与pod运行在相近的位置。
第一个pod被调度到某一个节点,第二个pod会跟随第一个pod运行在同一个位置相近的节点上。
同一个位置的节点不一定是同一个节点,这个节点可能是同一个命名空间、网段、机柜、机房、甚至同一个区域的某一个节点上。
因为如果说,同一个节点上的资源不足时,pod被调度不到同一个节点,那么就会找与这个节点相近的某个节点上。
节点相近是指节点到节点的网络路程较近。
当然,若资源空间充足也可以实现让第二个Pod跟随第一个pod运行在同一个节点上。
可以根据topologyKey设定的标签来判定拥有哪些标签的节点属于同一位置
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
tier: fround
spec:
containers:
- name: myapp
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
---
apiVersion: v1
kind: Pod
metadata:
name: myapp2
labels:
app: myapp
tier: backend
spec:
containers:
- name: myapp2
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #硬亲和性
- labelSelector:
matchExpressions: ## #匹配pod的,而不是匹配节点
- key: app # 标签名
operator: In # 表示键与一组值的关系。有效的运算符有:In、NotIn、Exist、DoesNotExsit。GT和LT
values: # 若operator为In或NotIn则值必须为非空;若operator为Exists或DoesNotExist则值必须为空;若operator为Gt或Lt则值必须有一个元素。
- "myapp" # 标签值
topologyKey: kubernetes.io/hostname #节点标签(选取包含kubernetes.io/hostname标签的节点)
反亲和性podAntiAffinity
apiVersion: v1
kind: Pod
metadata:
name: myapp-first
labels:
app: myapp
tier: fround
spec:
containers:
- name: myapp
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
---
apiVersion: v1
kind: Pod
metadata:
name: myapp-second
labels:
app: myapp
tier: backend
spec:
containers:
- name: myapp2
image: docker.io/nginx:latest
imagePullPolicy: "IfNotPresent"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["myapp", "foo"]}
topologyKey: kubernetes.io/hostname ## pod调度策略是podAntiAffinity反亲和性,所以myapp-first和myapp-second不能同时运行在标有kubernetes.io/hostname标签的节点上。
污点容忍度调度:Taint、toleration(nodes.spec.taints)(pod.spec.tolerations)
污点就是定义在节点上的键值属性数据:三类:1.标签。2.注解。3.污点。
其中,标签和注解可以在节点或pod上使用,而污点只能在节点上使用。
污点主要是让节点拒绝那些不能容忍自己污点的pod的。
而pod上可以定义容忍度,只要是节点上的污点是pod的容忍度的子集,则pod就可以运行在这个节点上。
taints是用在节点上的键值数据定义污点的,toleration是用在pod上的键值数据定义容忍度的。
污点:taints(nodes.spec.taints)
在节点上定义污点:
nodes.spec.taints.
- effect: ##当pod不能容忍污点时采取的措施是什么。
NoSchedule: ##仅影响调度过程,对现存的pod不产生影响;
PreferNoSchedule: ##柔性版的NoSchedule
NoExecute: ##不仅影响调度,而且影响现存pod对象,不容忍的pod对象将被驱逐;
key: ##键
timeAdded:
value: ##值
添加污点命令:kubectl taint node NODE_NAME KEY_1=VAL_1:TAINT_EFFECT_1 ... KEY_N=VAL_N:TAINT_EFFECT_N [options]
example: ]# kubectl taint node node1 node-type=production:NoSchedule
删除污点命令:kubectl taint node NODE_NAME KEY_NAME-
容忍度:toleration(pod.spec.tolerations)
在pod中定义容忍度:
pod.spec.tolerations.
- effect: ##同上
key: ##同上
value: ##同上
operator:##有效的运算符是Exists、Equal。默认为Equal。这样pod就可以容忍某一特定类别的污点
tolerationSeconds:##若不能容忍污点,多长时间后被驱逐。
example:
apiVersion: v1
kind: Pod
metadata:
name: myapp
labels:
app: myapp
spec:
containers:
- name: myapp
image: docker.io/nginx
imagePullPolicy: "IfNotPresent"
tolerations:
- effect: "NoSchedule"
key: "node-type"
operator: "Equal"
value: "production"
example
apiVersion: apps/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: "Exists" #表示只要节点匹配key: node-type,不管其value是什么,pod都能容忍节点上的污点
value: ""
effect: "NoSchedule"
参考文档:
https://www.cnblogs.com/kcxg/p/11119679.html
https://www.cnblogs.com/Smbands/p/10949478.html
http://blog.itpub.net/28916011/viewspace-2215522/
更多推荐
所有评论(0)