K8s预选策略和优选函数简介
调度器选择策略:
预选策略(Predicate)
1. 根据运行Pod的资源限制来排除不符合要求的Node
2. 根据运行Pod时,是否要求共享宿主机的网络名称空间来判断,如: 某Pod启动要共享宿主机的网络名称空间,启动80端口,而某些Node的80已经被占用,那它就不符合,就也要不排除。
优选策略(Priority):
此阶段会经过一系列函数,会把预选出来的节点的相关属性都输入到这些函数中,通过计算来获取每个节点的优先分值,然后在倒序排序,取得分最高者,作为运行Pod的节点,若计算后,发现有多个Node得分相同,此时将随机选取一个Node作为该Pod运行的Node。
选定(Select):
当优选选出一个Node后,该Pod将会被绑定到该Node上运行。
我们在定义一个Pod要运行在那个Node,是有一定偏向性的,比如有些Pod需要运行的有SSD硬盘的Node上,而有些Pod则需要运行在有GPU的节点上等,这时就需要我们给Node上打上不同的标签,来标识整个集群中不同Node的特性,这些特性包括,特有硬件标识,地理位置标识,不同机房标识等。
我们使用kubectl explain pod.spec 可以看到其中有nodeName 和 nodeSelector 两个属性,第一个是明确指定Node节点名,我就要运行在这个Node上,第二个就是通过匹配Node标签,来选择运行的Node。
调度方式有以下几类:
1. 节点倾向性(或叫 节点亲和性调度)
这种调度通常会采用 nodeSelector 来完成调度。
2. Pod倾向性 和 Pod非倾向性(这也称为Pod亲和性和非亲和性)
有时候我们需要让某些Pod能运行在同一处时,就需要使用Pod亲和性来定义,如:我们要定义一个NMT(Nginx+Tomcat+MySQL),若这三个Pod分别被调度三个不同地域的机房中,比如北京,上海,深圳等地,那肯定不是我们所希望的,这时我们就需要使用Pod亲和性来定义这三个Pod能运行在相同的Node 或 相邻的Node上。
而在另外一些情况下,我们又希望某些Pod一定不能运行在相同Node上,这时就需要使用Pod的非亲和性了。
3. 污点 和 污点容忍调度
Taints(污点):是定义在Node上的
Tolerations(容忍): 是定义在Pod上的
污点:指有时我们希望不将某些Pod调度到某些Node上,这时我们可对某些Node上打上污点,然后,当我们创建Pod时,我们可定义此Pod能容忍的污点范围。
假如:NodeA上有5个污点: "吃喝嫖赌抽",而此次要调度的Pod比较大度,能容忍5个污点,而NodeA的污点正好是Pod能容忍污点的范围内,于是Pod就能"嫁入"该NodeA。
假如,Pod运行到NodeA上后,后期我们又给该NodeA打上了新污点如:"坑蒙拐骗偷",此时Pod发现NodeA的恶性原来有这么多,怎么办?通常有两种选择策略:
1. Pod继续运行在NodeA上"艰苦度日"
2. Pod被驱逐,或者叫Pod逃离。
默认调度器的调度规则是:根据Node最大资源空闲率来进行均衡调度。
调度器:
预选策略
【注意:下面这些预选策略仅是其中一部分,并且k8s在进行预选时,它会是综合评估的,即所有启用的策略规则都要做判断,所得结果越符合就越会被挑选出来,进入优选策略中】:
CheckNodeCondition: 检查节点是否符合调度条件
GeneralPredicates:
HostName: 这种是判断Pod是否定义了pod.spec.hostname属性,若定义了,就在预选时,看看这些Node上是否存在相同主机名的Pod,若有,就排除该Node; 这可能是因为,某些Pod是需要有固定主机名,才会使用。
PodFitsHostPorts: 此预选策略是判断 pods.spec.containers.ports.hostPort 属性是否定义了,若定义了就表示该Pod要绑定到Node上指定的Port上,这时在进行预选时,就要判断这个端口是否被占用了,若占用就会排除该Node。
MatchNodeSeletctor:此预选策略会判断 pods.spec.nodeSelector 属性是否定义了,若定义了就根据Pod所定义的NodeSelector来选出匹配指定标签的Node。
PodFitsResources: 此预选策略会判断 Node上是否符合运行Pod所需的最小空闲资源。
NoDiskConfict: 用于判断若Pod定义了存储卷,则要检查该存储卷在该Node上是否可用,若Node能满足Pod存储卷的使用需求,则表示此Node可用。
PodToleratesNodeTaints:检查Pod上的spec.tolerations可容忍的污点是否完全包含Node上定义的污点,若完全包含,则表示Pod能容忍该Node节点的污点,否则该Node不会通过预选。
PodToleratesNodeNoExecuteTaints:
#首先,污点并非单一属性,它有三种属性,NoExcute是污点的一种属性。
#此检查是,若Pod被调度到某Node上时,最初Node上没有Pod不能容忍的污点,但后来Node的污点改变了,多了Pod不能容忍的污点,这时要怎么处理那?默认是继承既定事实,继续在该Node上运行。
# 第二种是不接受,也就是检查此属性,此时Node会驱逐该Pod,让该Pod重新调度到新Node上。
CheckNodeLabelPresence:这是定义在选择Node时,检查Node上是否存在指定的标签,若存在则可调度。此规则默认不启用。
CheckServiceAffinity: 当我们需要创建一些Pod时,这些Pod都使用相同的Serivce,这时,若启用该预选策略,则将这些Pod优先调度到 已存在较多该Service下的Pod的Node上。
#下面三个默认启用,因为这三个是最大的三个云运营商
MaxEBSVolumeCount:此预选策略是指若Pod需要使用亚马逊的EBS(弹性块存储服务),则检查该EBS是否已经达到最大运行挂载数39个,若没有,则表示还有存储空间可用。
MaxGCEPDVolumeCount: GCEPD:是Google的云环境中的持久存储,默认是16个
MaxAzureDiskVolumeCount: 最大是16个
CheckVolumeBinding:检查Node上是否存在以绑定 和 未绑定的PVC,若Node上有PVC,并且没有被绑定则能满足Pod运行的需求。
NoVolumeZoneConflict:它是在给定了区域限制的情况下,Zone在IDC机房是有限制的,他们通常会按房间,机柜,机架来划分范围,假如机架上有20台服务器,每2台一个区域,这个就是一个逻辑区域,此配置项的含义就是检查区域中Node上是否存在逻辑卷冲突。
CheckNodeMemoryPressure:检查Node上是否存在内存压力,即若某Node上已经出现内存紧张的情况了,那就不要在往它上面调度了。
CheckNodePIDPressure:检查Node上是否存在PID压力过大的情况,即若某Node上运行的进程过多,导致PID可能紧张,这时在选择调度时,也不会选择它。
CheckNodeDiskPressure:检查Node上是否存在磁盘使用压力过大的情况
MatchInterPodAffinity:检查Node上是否满足Pod的亲和性,假如Pod是Nginx,它是要为Tomcat Pod做代理的,那么在调度tomcat Pod时,就会检查Node上是否有Nginx Pod,若有这个非常亲和的Pod则优先调度到该Node上。
优选函数:
默认启用了7个红色的优选函数,它们的得分相加值越高,该节点越优选被选中。
LeastRequested: 【与它相反对一个优选函数:MostRequested,它是Node资源占用越高得分越高,有点像是,先将某Node的资源先全部占满的意味,然后空出部分Node.】
计算得分的算法公式=(cpu((capacity - sum(requested))*10 / capacity) + memory((capacity - sum(requested))*10 / capacity))/2
此公式的含义:
假如当前有16个核心,已经用了8个核心,那么总的使用率就是 (16-8)/16 = 0.5 ,而乘以10,是为了计算得分方便,将其转化为0~10之间的数,
而内存的计算含义一样,假如内存32G,已经用了8G,则使用率为 (32-8)/32 = 0.75 ,乘以10
将CPU + Memory/2 就可以得到一个平均值。该平均值越高,表示该节点的资源空闲率越高。
BalanceResourceAllocation:
它表示CPU和内存资源占用率的相近程度,作为评估标准,越接近也优选选择,比如: Node1的CPU和内存使用率一个48%一个50%,而Node2的CPU和内存使用率都是50%,则Node2胜出。
#它通常要和LeastRequested 结合来评估Node的资源利用率的。
#两个组合主要是为了平衡各Node上资源的利用率。
NodePreferAvoidPods:
根据Node节点上是否定义了注解信息"scheduler.alpha.kubernetes.io/preferAvoidPods",若没有则该Node得分为10,而且权重为1万,有此注解则说明该Node是适合运行Pod的。而对于那些有Replicas Controller的控制器则,该Node的得分为0,此时则表示Pod不能运行在该Node上,但这不能决定Pod一定不能运行在该Node上,因为最终是要看总体得分的。
注解信息:
# kubectl describe node node1.zcf.com
Name: node1.zcf.com
Roles: node
..........
Annotations: node.alpha.kubernetes.io/ttl: 0 #这就是所谓的node上的注解信息。
volumes.kubernetes.io/controller-managed-attach-detach: true
TaintToleration:
基于Pod对调度Node上的污点容忍度来评估是否可调度到该Node上。
简单说:就是取出Pod对象中定义的spec.tolerations列表,查看其中能容忍的污点,然后,一个一个去对比Node上存在的污点,若匹配的越多,则该Node的得分越低,就越不会调度到该Node上。
SelectorSpreading:
此优化函数是希望将相同标签选择器选取的Pod尽可能的散开到多个Node上。因此假如:ReplicaSet控制器,已经在B上创建了一个Pod,那么它要再创建一个Pod时,此优选函数在计算A,B,C三个Node的得分时,会根据那个Node上拥有此ReplicaSet控制器的标签选择器所匹配的Pod数量,来评分,数量越少,分数越高,反之越低。
而使用标签选择器的资源对象有:Service,Replication Controller,ReplicaSet,StatefulSet。
InterPodAffinity:
遍历对象的亲和性条目,并将能够匹配到给定节点的条目的条目数相加结果值越大得分越高。
简单说:NodeA上运行了3个Pod,NodeB上运行了6个Pod,NodeC上运行了5个Pod,现在要调度一个Pod到其中一个Node上,而该Pod的比较亲和某类Pod,此优选函数就会将这些Node上,所有匹配该Pod亲和条目的数量相加,值越大,则越得分越高。其中条目的理解,我还不是很懂。
NodeAffinity:
它是根据pod中定义的nodeSeletor来对Node做亲和性检查, 能成功匹配的数量越多,则得分越高。
NodeLabel:
根据Node是否有某些标签来做评估,然后计算得分的,此优选函数只关注标签,不关注值,只有Node上有这个标签就可以得分。
ImageLocality:
它评分的标准是,判断Node上是否有运行该Pod的镜像,若有则得分,否则不得分。
但它评估镜像是根据镜像总的体积大小来计算得分的,例如:NodeA上有1个镜像1G,NodeB上有2镜像,NodeC上有3个镜像,而运行此Pod需要4个镜像,其中一个镜像1G,其它都是比较小,这时NodeA的得分会最高。
#实验:
1. 定义一个Pod,并设置其nodeSelector,若指定的nodeSeletor标签没有匹配到任何Node,则Pod将处于Pinding状态,只有你给某个Node打上指定的标签和值后,该Pod才会被调度上去。
#实验2:
kubectl explain pods.spec.affinity
nodeAffinity: 定义Node的亲和性
podAffinity: 定义Pod的亲和性
podAntiAffinity:定义Pod非亲和性
nodeAffinity:
# 软亲和性,即若能满足则一定运行在满足条件的Node上,否则运行在其它Node上也不是不可以。
preferredDuringSchedulingIgnoredDuringExecution
#硬亲和性,若不能满足运行条件,则不运行Pod。
requiredDuringSchedulingIgnoredDuringExecution
nodeSelectorTerms:
matchExpressions : 这是更强大的一种方式,它是配表达式的。
matchFields:
key: 要对那个label key做匹配操作
operator:指定你是做什么比较操作,支持: In/NotIn(包含/不包含), Exists/DoesNotExist(存在/不存在) , Gt/Lt(大于/小于)
values:若操作符为Exists/DoesNotExists则,values必须为空。
vim pod-node-required-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: zone
operator: In
values:
- foo
- bar #默认node上没有打上zone=foo 或 zone=bar的标签,此时是硬亲和,若不能满足条件,则无法调动. vim pod-node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-affinity-
labels:
app: myapp
tier: frontend
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: zone
operator: In
values:
- foo
- bar
weight: # 此为软亲和,若node上有zone=foo 或 zone=bar,则优先调度上去,若全部都没有,勉强选一个调度上去也不是不可以
为啥有了节点亲和性,还要有Pod亲和性?
假如我们有一个分布式跨地域的大集群,现在想构建一个NMT的架构,为了实现这个目的,我完全可以给Node上打标签,然后,让NMT这些Pod都匹配这些标签,然后被调度到这些Node上去运行,这不是也可以实现我们的目的吗?
看上去没有问题,但问题是,假如你跨地域的分布式K8s集群,分别分布在北京,上海,深圳,杭州等地,你就不得不精心规划不同地域,不同IDC,不同机房,不同机柜的Node标签规划,否则你很可能在将来实现这个目的是变得困难不堪,你可以想象一下,你希望让一组NMT运行在北京某IDC的某机房中,这样一个NMT架构在工作时,才能更加高效的通信,你想实现这样的控制,你不规划Node的标签,你让预选策略如何按照你的想法去调度那?这还仅是一方面,你为了NMT架构能分离开,北京一套,上海一套.....你也要配置Pod的在选择Node标签时,设定它亲和哪些标签,所以工作量你可自己评估。
Pod亲和性的逻辑时,我要部署NMT环境,我的MySQL Pod第一个被调用,我不管调度器会把MySQL Pod调度到哪里,反正只要调度完成,并且运行了,我后续的Nginx,Tomcat的Pod是亲和MySQL Pod的,MySQL Pod在哪个Node上,那在调度NT时,就更加优先调度到那个Node上。
这样说看上去很简单,但仔细想想,MySQL被调度到某Node上,要是将NT也调度到那个Node上合适吗?若那个Node没有这么多资源运行它们怎么办?能不能将NT调度到M所在Node旁边的Node上,或同机房的Node中?那这算亲和吗? 其实也算,但怎么知道运行MySQL Pod的Node ,它旁边的Node是否那个主机?这其实还是需要借助于Node标签来实现,因此为集群标签的规划是在所难免的,因为你必须给预选策略一种判断标准,哪些是相同机柜,哪些是不同机房对吧,否则鬼知道集群中那么多Node那个和那个是邻居对吧,当然若你靠主机名来判断也不是不可以,你就要定义根据主机名的判断标准了。所以,比较通用的方法是,给每个Node打上不同的标签,如:北京机房1 机柜20 机架号等等来定义,这样根据这些标签值,就可以判断Node和Node之间的临近关系了。
打个比方: MySQL Pod被调度到 rack=bjYZ1 ,那后续调度NT时,就会优选rack=bjYZ1的Node,只要有这个标签值得Node会被优选调度,这样NMT它们就都可以运行在北京亦庄的机房中了。
kubectl pods.spec.affinity.podAffinity.
requiredDuringSchedulingIgnoredDuringExecution : 硬限制
labelSelector: 指定亲和Pod的标签
namespaces: 你要指定亲和Pod,你就需要指定你亲和的Pod属于哪个名称空间,否则默认是Pod创建在那个名称空间,就匹配那个名称空间的Pod
Pod亲和性示例:
vim pod-required-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: web1-first
labels:
app: web1
tier: frontend
spec:
containers:
- name: myapp
image: harbor.zcf.com/k8s/myapp:v1 ---
apiVersion: v1
kind: Pod
metadata:
name: db1-second
labels:
app: db1
tier: db1
spec:
containers:
- name: busybox
image: busybox: latest
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "sleep 3600"]
affinity:
podAffinity: #若需要测试Pod的反亲和性,只需要修改podAffinity为 podAntiAffinity 即可测试
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["web1","web2"]}
topologyKey: kubernetes.io/hostname #通过默认Node上主机名标签来临时代表地区标签,即:只有主机名相同,就认为是在相同位置的。 #Pod反亲和测试:
Pod亲和性示例:
vim pod-required-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: web1-first
labels:
app: web1
tier: frontend
spec:
containers:
- name: myapp
image: harbor.zcf.com/k8s/myapp:v1 ---
apiVersion: v1
kind: Pod
metadata:
name: db1-second
labels:
app: db1
tier: db1
spec:
containers:
- name: busybox
image: busybox: latest
imagePullPolicy: IfNotPresent
command: ["sh", "-c", "sleep 3600"]
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- {key: app, operator: In, values: ["web1","web2"]}
topologyKey: kubernetes.io/hostname
#第一次测试: 使用存在的标签来测试,web1会运行在一个节点上,db1一定不会运行在web1所在的Node上。
topologyKey: zone
#第二次测试: 使用此key,因为两个Node上都没有此标签key,因此预选策略将认为,没有找到不同区域的Node,因此db1将处于Pinding状态,无法启动。
vim myapp-toleration.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-toler1
spec:
replicas:
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v2
ports:
- name: http
containerPort:
tolerations:
- key: "node-type"
operator: "Equal"
value: "production"
effect: "NoSchedule"
#说明: 在定义Pod的容忍度时,若指定为NoSchedule,则不能定义tolerationSeconds,即容忍不了时,可宽限多久被驱逐。
# 若定义为NoExecute 则可以定义tolerationSeconds。
# Equal:做等值比较,即node-type标签 和 其值必须完全匹配。
# Exists :做存在性比较,即只要node-type标签存在,即可匹配,不看其标签值是否相同。 #测试NoExecute影响
#目前node2.zcf.com 上定义了node-type污点的影响为: NoExecute
............
tolerations:
- key: "node-type"
operator: "Exists"
value: "" #设置node-type的值为空,因为Exists是做标签判断,只要node-type标签存在,即可.
effect: "NoSchedule"
#定义污点影响度为NoSchedule,即若Node上没有这个node-type污点标签,就不调度到其上.
#若Node上污点影响(effect)为NoExecute,它是不包含NoSchedule的,即Node是不允许不能容忍NoExecute的Pod调度到自己上面的。 #若Pod能容忍node-type标签的污点,无论它是什么值,什么影响,都可以容忍
...............
tolerations:
- key: "node-type"
operator: "Exists"
value: ""
effect: "" #删除节点上的污点:
kubectl taint node node01.zcf.com node-type-
#注意:node-type是:node01上的标签,最后的“-”是删除该标签的意思。
K8s预选策略和优选函数简介的更多相关文章
- 05-k8s调度器、预选策略、优选函数
目录 k8s调度器.预选策略.优选函数 节点选择过程 调度器 预选策略 优选函数 高级调度设置机制 node选择器/node亲和调度 pod亲和性 污点调度 Taints 与 Tolerations ...
- k8s调度的预选策略及优选函数
scheduler调度过程: Predicate(预选)-->Priority(优选)-->Select(选定)调度方式: 1.节点亲和性调度(NodeAffinity)使用n ...
- k8s之调度器、预选策略及优选函数
1.调度器(scheduler) 调度器的功能是调度Pod在哪个Node上运行,这些调度信息存储在master上的etcd里面,能够和etcd打交道的只有apiserver; kubelet运行在no ...
- K8S 调度器,预选策略,优选函数
Kubernetes Scheduler 提供的调度流程分三步: 预选策略(predicate) 遍历nodelist,选择出符合要求的候选节点,Kubernetes内置了多种预选规则供用户选择. 优 ...
- k8s-调度器、预选策略及优选函数-二十
一.简介 master上运行着三个最核心的组件,apiserver.scheduler.controller manager.此外,master还依赖于ectd存储节点,最好ectd是有冗余能力的集群 ...
- Kubernetes 学习20调度器,预选策略及优选函数
一.概述 1.k8s集群中能运行pod资源的其实就是我们所谓的节点,也称为工作节点.master从本质上来讲,他其实是运行整个集群的控制平面组件的比如apiserver,scheal,controlm ...
- k8s调度器、预选策略及调度方式
一.k8s调度流程 1.(预选)先排除完全不符合pod运行要求的节点2.(优先)根据一系列算法,算出node的得分,最高没有相同的,就直接选择3.上一步有相同的话,就随机选一个 二.调度方式 1.no ...
- linux进程编程:子进程创建及执行函数简介
linux进程编程:子进程创建及执行函数简介 子进程创建及执行函数有三个: (1)fork();(2)exec();(3)system(); 下面分别做详细介绍.(1)fork() 函数定 ...
- Linux Shell系列教程之(十五) Shell函数简介
本文是Linux Shell系列教程的第(十五)篇,更多Linux Shell教程请看:Linux Shell系列教程 函数可以将一个复杂功能划分成若干模块,从而使程序结构更加清晰,代码重复利用率更高 ...
随机推荐
- Vue.js 源码分析(十四) 基础篇 组件 自定义事件详解
我们在开发组件时有时需要和父组件沟通,此时可以用自定义事件来实现 组件的事件分为自定义事件和原生事件,前者用于子组件给父组件发送消息的,后者用于在组件的根元素上直接监听一个原生事件,区别就是绑定原生事 ...
- 用 ubuntu 自带的 gome-screenshot 来实现类似QQ截图那样的功能,同时设置键盘快捷键
在window下习惯了使用ctrl+Alt+A截图,在linux还真有点不习惯,所以下面介绍一下替代的用法. 打开 ubuntu 的系统设置-->键盘-->快捷键:界面如下: 01 添加一 ...
- Angulaur导入其他位置的样式
建立一个统一样式文件base-xxx.component.css 在需要导入样式的组件中,编辑.ts文件导入样式: 右侧是它的相对路径.
- JAVA学习之开发环境配置
JAVA SDK 下载地址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html 版 ...
- make几个知识点
即时变量和延时变量 在下面代码中,定义了一个值为x的x变量,以延时变量的方式将它的值赋给y,以即时变量的方式将它的值赋给z. 因为y为延时变量,所以y的取值并不会立即计算,而是在整个文件解析完成之后才 ...
- C# 实体对象作为参数统一去除空格
/** * ------------------------------------------------------------------------------ * @Copyright in ...
- android studio学习---签名打包的两种方式
注:给我们自己开发的app签名,就代表着我自己的版权,以后要进行升级,也必须要使用相同的签名才行.签名就代表着自己的身份(即keystore),多个app可以使用同一个签名. 如果不知道签名是啥意思, ...
- URL&HTTP协议
一般来讲,URL地址有五个部分组成,协议,域名,端口,路径,URL地址参数,通常“//'之前的部分就是协议 常用的协议有: http 超文本传输协议 htttps http+ssl ssh 用来实现远 ...
- Ambari 管理hadoop、hbase、zookeeper节点
简介: Apache Ambari是一种基于Web的工具,支持Apache Hadoop集群的供应.管理和监控.Ambari已支持大多数Hadoop组件,包括HDFS.MapReduce.Hive.P ...
- thinkphp整合系列之极验滑动验证码geetest
给一个央企做官网,登录模块用的thinkphp验证码类.但是2019-6-10到12号,国家要求央企检验官网漏洞,防止黑客攻击,正直贸易战激烈升级时期,所以各事业单位很重视官网安全性,于是乎集团总部就 ...