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

相关推荐
功德+n7 小时前
Linux下安装与配置Docker完整详细步骤
linux·运维·服务器·开发语言·docker·centos
小敬爱吃饭8 小时前
Ragflow Docker部署及问题解决方案(界面为Welcome to nginx,ragflow上传文件失败,Docker中的ragflow-cpu-1一直重启)
人工智能·python·nginx·docker·语言模型·容器·数据挖掘
木子欢儿8 小时前
Docker Hub 镜像发布指南
java·spring cloud·docker·容器·eureka
coppher9 小时前
Ubuntu 22.04 amd64 离线安装 Docker 完整教程
linux·docker
虚伪的空想家11 小时前
k8s集群configmap和secrets备份脚本
linux·容器·kubernetes
SXJR11 小时前
k8s中的Pod
云原生·容器·kubernetes
文静小土豆11 小时前
K8s 滚动更新在 Java 应用中的实践与优化
java·容器·kubernetes
w61001046612 小时前
CKA-2026-Ingress
云原生·容器·kubernetes·cka
bloglin9999912 小时前
docker logs 如何一直监听日志输出
运维·docker·容器
说实话起个名字真难啊13 小时前
Docker 入门之网络基础
网络·docker·php