scheduler组件:负责调度资源,根据调度算法(预算策略、优先策略)把pod调度到node节点
1、 list-watch监听
(1) ****定义:****在k8s集群中,通过list-watch的机制进行每个组件之间的写作,保持数据同步,保证每个组件之间的解耦
(2) 数据流向
kubectl配置文件,向apiserver发送命令,通过apiserver把命令发送到各个组件
①创建pod
• 第一步把创建命令发送到apiserver
• 第二步由apiserver把消息传给controller manager
• 第三步由scheduler资源调度器根据调度算法把命令传给kubelet节点控制器
• 第四步由kubelet节点控制器具体分发到哪个节点
kubectl run nginx --image=nginx:1.22→apiserver→controller manager→scheduler→kubelet
②创建成功后,pod的详细信息均保存在etcd的数据库中
list-watch会监听apiserver6443的端口,controller manager,scheduler,kubelet,etcd都会监听apiserver6443的端口
注:只有apiserver在etcd上有读写权限
2、 调度过程和策略
scheduler是k8s集群的资源调度器,作用:把pod分配到集群节点
(1) 调度规则
****①公平分配:****每个节点都能分配资源
****②资源高效利用:****整个集群中的资源可以最大化使用
****③效率:****调度性能好,若pod数量对,能尽快完成大批量的pod的调度工作
****④灵活:****允许用户根据需求控制、改变调度逻辑
scheduler是一个单独运行的程序,启动后会一直监听apiserver,获取报文中的spec:nodeName字段。创建pod时,为每个pod创建binding,表示该往哪个节点上部署
(2) 调度策略(先执行预算策略,再执行优先策略。两个策略结合使用)
|---------------------------|------------------------------------------------------------------------------------------|
| #### 1)预算策略 (predicate自带算法,选择node节点,不需要人工干预) ||
| podfitsresources | pod适应资源。检查节点上的剩余资源是否满足pod请求的资源 (主要是CPU和内存资源) |
| podfitshost | pod适应主机。若要指定pod部署再哪个节点上,检测的主机名是否存在,存在要和pod指定名称匹配才能调度过去 |
| podselectormatches | pod选择器匹配。创建pod时可以根据node节点标签进行匹配,查找指定的node节点上标签是否存在,若存在,再检查标签是否匹配 |
| nodiskconflict | 无磁盘冲突。确保已挂载的卷与pod卷不发生冲突,除非目录是只读,可以覆盖原pod |
| 优先执行预算策略,再执行优先策略,若预算策略都不满足,pod将始终处于pending状态,scheduler不断的重试调度,直到有节点满足条件为止 ||
| #### 2)优先策略 ||
| leastrequestedpriority | 最低请求优先级策略。通过算法计算节点上的CPU和内存的使用率,来确定节点的权重,使用率越低的节点权重越高。调度时倾向于权重高的节点,实现资源合理利用 |
| balanceresourceallocation | 平衡资源分配策略。考虑CPU和内存的使用率,根据CPU和内存使用率接近给节点赋予权重,越接近权重越高 结合leastrequestedpriority最低请求优先级策略一起使用 |
| imagelocalitypriority | 节点上是否已存在要部署的镜像。与镜像总数成正比,满足的镜像数越多,权重越高 |
| 以上策略均是scheduler自带的算法。通过预算策略选择出可以部署的节点,再通过优先策略选择出最好的节点 ||
| 注:部署的node节点必须同时满足预算策略和优先策略,否则立刻报错 ||
3)指定节点(不经过scheduler资源调度器调度)
spec设置参数nodeName:node2
在参数中设置nodeName,指定节点名称会跳过scheduler的调度策略,这个规则是强制匹配,不走调度算法,不考虑该节点资源是否足够
4)指定标签 (经过scheduler资源调度器调度)
spec设置参数nodeSelector:标签名
① 查看节点标签(节点自带标签)
kubectl get nodes --show-labels
② 自定义节点标签
kubectl label nodes node2 ttt=c
③修改标签
kubectl label nodes node1 sss=b --overwrite
④删除标签(-减号)
kubectl label nodes master yyy-
⑤指定标签部署pod
指定节点标签部署pod经过scheduler调度算法,若节点不满足条件,pod进入pending算法,直到节点满足条件为止
键值运算关系
|--------------|------------------------------------------------------|
| 根据标签选择亲和性 ||
| In | 在,选择的标签值在node节点上 |
| NotIn | 不在,选择的标签值不在node节点上 |
| Gt | 大于选择的标签值(只能比较整数值) |
| Lt | 小于选择的标签值(只能比较整数值) |
| Exists | 存在,只选择标签对象。只要node节点上有这个标签对象即可,无论标签值是什么(不能使用values字段) |
| DoesNotExist | 不存在,选择不具有指定标签的对象,无论标签值是什么(不能使用values字段) |
| 亲和性根据标签进行选择 ||
5)节点亲和性
• 硬策略requiredDuringSchedulingIgnoredDuringExecution
选择node节点时,声明部署在node1节点,硬策略必须满足这个条件(强制性要求)
注:先满足软策略,再满足硬策略
• 软策略preferredDuringSchedulingIgnoredDuringExecution
选择node节点时,声明最好部署在node1,软策略会尽量满足这个条件,但不一定能完全实现
注:多个软策略看权重,权重高,执行指定的软策略
A 硬策略
• In方式调度node节点
• NotIn方式调度node节点
• Gt方式调度node节点
• Lt方式调度node节点
• Exists方式调度node节点
• DoesNotExist方式调度node节点
B 软策略(因为有权重,一个策略中可以有多个软策略)
• 一个策略中可以有多个软策略( 优先执行 权重高的策略)
• 一个策略中同时有硬策略和软策略(先 满足硬策略,再满足软策略)
• 不满足硬策略的条件,不再执行软策略,pod始终处于pending状态
在部署pod时如何选择策略? 【面试题】
结合业务举例说明:目前有3个node
|-------|------|
| node1 | 4核8G |
| node2 | 4核8G |
| node3 | 2核4G |
若集群中节点都正常运行,但性能高低不一致,选择软策略,性能高的多部署一点pod,性能低的少部署一点pod
若其中一个节点故障或维护中,选择硬策略,将pod部署在正常运行的节点
node亲和性和pod亲和性的区别
|-----------------|--------------|------------------------------------|-------------|-----------------------|
| 策略 | 匹配标签 | 操作符 | 拓扑域 | 调度目标 |
| node亲和性 | 主机标签 | In、NotIn、Exists、DoesNotExist、Gt、Lt | 不支持 | 指定主机 |
| pod亲和性 | pod标签 | In、NotIn、Exists、DoesNotExist | 支持 | pod和指定标签的pod部署在同一拓扑域 |
| pod反亲和性 | pod标签 | In、NotIn、Exists、DoesNotExist | 支持 | pod和指定标签的pod部署不在同一拓扑域 |
(6) pod亲和性
1)作用:把相关联的pod部署在同一节点 【面试】
2)拓扑域 ****:****k8s集群节点中的一个组织结构,可以根据节点的物理关系或逻辑关系进行划分,拓扑域可以用来表示节点之间的空间关系、网络关系或其他类型的关系。这里的拓扑域指的是标签
3)策略
①硬策略requiredDuringSchedulingIgnoredDuringExecution
要求调度器将pod调度到其他pod的亲和性匹配的节点上,硬策略必须满足这个要求
• In方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
第二步:设置pod亲和性
podAffinity:指定策略是pod亲和性
此时要满足三个条件:①pod标签是app
②pod标签值是nginx1
③拓扑域是yst(节点标签是yst)
三个条件要同时满足,否则处于pending状态
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
• Exists方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
第二步:设置pod亲和性
podAffinity:指定策略是pod亲和性
此时要满足两个条件:①pod标签是app
②拓扑域是yst(节点标签是yst)
两个条件要同时满足,否则处于pending状态
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
• DoesNotExist方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
第二步:设置pod亲和性
此时要满足两个条件:①pod标签不是app1
②拓扑域是yst(节点标签是yst)
两个条件要同时满足,否则处于pending状态
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
②软策略preferredDuringSchedulingIgnoredDuringExecution
要求调度器将pod调度到其他pod的亲和性匹配的节点上,软策略尽量满足这个要求
• DoesNotExist方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
第二步:设置pod亲和性
此时要满足两个条件:①pod标签不是app1
②拓扑域是yst(节点标签是yst)
只能尽量满足,但不是必须满足
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
( 7 ) pod反亲和性
①软策略
• In方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
\
第二步:设置pod亲和性
此时要满足三个条件:①pod标签是app
②pod标签值是nginx1
②拓扑域是ttt(节点标签是ttt)
只能尽量满足,但不是必须满足
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
②硬策略
• In方式分配node节点给pod
第一步:运行一个yaml文件在node节点上设置pod标签
第二步:设置pod亲和性
此时要满足三个条件:①pod标签是app
②pod标签值是nginx1
②拓扑域是ttt(节点标签是ttt)
三个条件必须同时满足,否则处于pending状态
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | ttt=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
注意事项:
• pod的亲和性策略,在配置时必须加上拓扑域关键字topologyKey(指向的是节点标签)
• pod亲和性策略分为硬策略和软策略
• pod亲和性的NotIn可以替代反亲和性,所以反亲和性很少用
• pod亲和性主要作用是把相关联的pod部署在同一节点
( 8 ) 污点
****1)定义:****污点和容忍可以配合node节点的亲和性一起使用,污点是node的调度机制,不是pod。被设为污点的节点不会部署pod,污点和亲和性相反,亲和性是尽量选择,设为污点的节点一定不被选择(不一定,看污点类型)
2)污点(taint)类型
****①NoSchedule:****不会把pod部署在这个节点上
****②PreferNoSchedule:****尽量避免把pod部署在该节点上(master节点一般设为此污点类型)
③ ★ NoExecute: 把该节点上的所有命名空间的pod全部驱逐出去,且不会调度此节点,系统集群组件不会被驱逐****(慎重)【面试】****
①基于控制器创建的pod虽然被驱逐,但会在其他节点重新部署
②自主pod会被直接杀死
适用场景:节点服务器需要维护,服务器关机,节点上的所有pod失效,在工作中主要部署pod的方式是基于控制器deployment部署。一旦节点设置为驱逐,控制器创建的pod会在其他节点重新部署
③适用于资源回收或节点维护、故障 【面试】
3)污点命令
①查看污点
kubectl describe nodes master|grep -i taints
②设置污点
• kubectl taint node node1 key=1:NoSchedule
• kubectl taint node node1 key=1:PreferNoSchedule
• kubectl taint node node1 key1=2:NoExecute
③去除污点
kubectl taint node node1 key:NoSchedule-
• 设置NoExecute污点
此时要满足三个条件:①pod标签是app
②pod标签值是nginx1
②拓扑域是yst(节点标签是yst)
三个条件必须同时满足,否则处于pending状态
此时各个节点上的node节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | yst=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
| 原本三个节点均满足条件的节点,但因为在master节点上设置污点NoExecute,把该节点上的pod全部驱逐,并且不会部署pod在此节点上,所以只有node1和node2节点可部署pod ||||
• 设置NoSchedule污点
此时要满足三个条件:①pod标签是app
②pod标签值是nginx1
②拓扑域是yst(节点标签是yst)
三个条件必须同时满足,否则处于pending状态
此时各个节点上的节点标签和pod标签如下:
|---------------|----------------|---------------|---------------|
| | master | node1 | node2 |
| 节点标签 | yst=200 | yst=500 | yst=800 |
| pod标签 | app=nginx1 | app=nginx1 | app=nginx1 |
| 原本三个节点均满足条件的节点,但因为在node1节点上设置污点NoSchedule,不会在该节点上部署pod,所以只有master和node2节点可部署pod ||||
( 9 ) 容忍
****1)定义:****即使节点上设置了污点,有了容忍机制,依然可以在设置为污点的节点上部署pod
特殊情况:NoExecute依然可以部署pod,但有生命周期,生命周期结束后,会驱逐一部分pod到其他节点,有的pod会保留在污点节点上被销毁重新拉起
2) ****适用场景:****该节点维护完毕,测试该节点是否正常工作
• 设置NoSchedule污点的容忍时间
所有节点均设置污点NoSchedule(不能部署pod在污点节点上)
此时满足三个条件仍可部署pod:
①污点标签是key
②污点标签值是1
③污点类型是NoSchedule
此时各个节点上的污点标签如下:
|--------------|------------------|------------------|------------------|
| | master | node1 | node2 |
| 污点标签 | key=1:NoSchedule | key=2:NoSchedule | key=3:NoSchedule |
| 三个节点均设置了污点标签NoSchedule,该节点不能部署pod,但有了容忍机制,满足条件:污点标签是key、污点标签值是1、污点类型是NoSchedule的节点仍然可以部署pod ||||
• 设置 NoExecute 污点的容忍时间(需指定容忍时间)
此时满足四个条件仍可部署pod:
①污点标签是key
②污点标签值是2
③污点类型是NoExecute
④生命周期60秒(测试环境设置成60秒,生产环境至少10分钟)
此时各个节点上的污点标签如下:
|--------------|------------------|-----------------|-----------------|
| | master | node1 | node2 |
| 污点标签 | key=1:NoSchedule | key=2:NoExecute | key=3:NoExecute |
| 设置污点NoSchedule,该节点不能部署pod, 设置污点NoExecute,该节点将所有pod驱逐,不部署pod在该节点, 但有了容忍机制,满足条件:污点标签是key、污点标签值是2、污点类型是NoExecute的节点在生命周期60秒内仍然可以部署pod,一旦生命周期结束pod会重新拉起 ||||
3) 污点容忍机制
①不指定key:会容忍所有污点的key,但只能容忍指定的污点类型的节点,其他类型的节点仍然不能容忍
此时各个节点上的污点标签如下:
|--------------|------------------|-----------------|-----------------|
| | master | node1 | node2 |
| 污点标签 | key=1:NoSchedule | key=2:NoExecute | key=3:NoExecute |
| 设置污点NoSchedule,该节点不能部署pod, 设置污点NoExecute,该节点将所有pod驱逐,不部署pod在该节点, 但有了容忍机制,①不指定key,所以可以容忍所有污点节点②但设置了污点类型,只能在这个类型的污点节点上部署pod ||||
②不指定effect:所有节点都能部署,可以容忍所有节点的污点类型
方式1:
此时各个节点上的污点标签如下:
|--------------|------------------|-----------------|-----------------|
| | master | node1 | node2 |
| 污点标签 | key=1:NoSchedule | key=2:NoExecute | key=3:NoExecute |
| 设置污点NoSchedule,该节点不能部署pod, 设置污点NoExecute,该节点将所有pod驱逐,不部署pod在该节点, 但有了容忍机制,不指定effect,所有该污点标签为key的都可以部署pod ||||
方式2:
此时各个节点上的污点标签如下:
|--------------|------------------|-----------------|-----------------|
| | master | node1 | node2 |
| 污点标签 | key=1:NoSchedule | key=2:NoExecute | key=3:NoExecute |
| 设置污点NoSchedule,该节点不能部署pod, 设置污点NoExecute,该节点将所有pod驱逐,不部署pod在该节点, 但有了容忍机制,不指定effect,所有该污点标签为key的都可以部署pod ||||
4)污点适用场景
多个master节点,设置为PreferNoSchedule,防止资源浪费
业务维护时,master节点上还有业务pod在运行,把该节点的污点设置为NoExecute。一般是基于deployment部署,设置了NoExecute污点会在其他节点上重新部署,并不是被杀死。但自主创建的pod会被杀死,一旦节点恢复一定要去除污点
(10) cordon标记和drain排水(命令行标记节点不可用)
1)cordon直接把节点标记为不可用状态
标记为不可部署状态kubectl cordon master
取消标记不可部署状态kubectl uncordon master
2)drain把该节点下的pod全部转移到其他的node节点上运行
①一旦执行drain,该node节点会变成不可调度状态
②会驱逐该节点上的所有pod
排水为不可部署状态
kubectl drain node1 --ignore-daemonsets --delete-emptydir-data --force
|---------------------|------------------------------------------------------------------------------|
| drain | 标记node节点为不可调度,然后驱逐pod |
| --ignore-daemonsets | 忽视daemonset部署的pod,daemonset部署的pod还在原节点上(daemonset部署的一般是重要的、后台运行的、系统的pod,不能动) |
| --delete-local-data | 有本地挂载卷的数据会被强制杀死 |
| --force | 强制释放不是控制器管理的pod(不是控制器创建的pod被杀死,基于控制器创建的pod被转移) |
设置node1排水之后:
取消排水kubectl uncordon node1