k8s的集群调度

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

相关推荐
玖石书几秒前
docker 数据管理
docker·容器
HoweWWW1 小时前
k8s-API 访问控制
云原生·容器·kubernetes
2420302 小时前
Docker笔记-容器数据卷
docker
shelby_loo3 小时前
通过 Docker 部署 WordPress 服务器
服务器·docker·容器
minsin4 小时前
【linux】【docker】Docker默认网段配置导致无法访问
docker
悲伤的创可贴6 小时前
Docker安装以及简单使用
linux·docker·centos
方圆师兄6 小时前
docker快速搭建kafka
docker·容器·kafka
小的~~7 小时前
k8s使用本地docker私服启动自制的flink集群
docker·flink·kubernetes
诚诚k8 小时前
docker存储
运维·docker·容器
sorel_ferris8 小时前
Ubuntu-24.04中Docker-Desktop无法启动
linux·ubuntu·docker