K8s 源码剖析及debug实战之 Kube-Scheduler(四):预选算法详解
文章目录
- 0. 引言
- 1. 回顾
- 2. `podFitsOnNode` 为什么执行两次预选
- 3. 预选算法有哪些
- 4. 参考
0. 引言
欢迎关注本专栏,本专栏主要从 K8s 源码出发,深入理解 K8s 一些组件底层的代码逻辑,同时借助 debug Minikube 来进一步了解 K8s 底层的代码运行逻辑细节,帮助我们更好的了解不为人知的运行机制,让自己学会如何调试源码,玩转 K8s。
本专栏适合于运维、开发以及希望精进 K8s 细节的同学。同时本人水平有限,尽量将本人理解的内容最大程度的展现给大家~
前情提要:
《K8s 源码剖析及debug实战(一):Minikube 安装及源码准备》
《K8s 源码剖析及debug实战(二):debug K8s 源码》
《K8s 源码剖析及debug实战之 Kube-Scheduler(一):启动流程详解》
《K8s 源码剖析及debug实战之 Kube-Scheduler(二):终于找到了调度算法的代码入口》
《K8s 源码剖析及debug实战之 Kube-Scheduler(三):debug 到预选算法门口了》
文中采用的 K8s 版本是 v1.16。紧接上篇,本文主要介绍 K8s 的 Kube-Scheduler 源码的预选算法的具体逻辑。
1. 回顾
上节我们说到,调度里最关键的是 predicate 和 priority 这两个步骤,下面是进一步省略后的主要的调度逻辑:
func (g *genericScheduler) Schedule(pod *v1.Pod, pluginContext *framework.PluginContext) (result ScheduleResult, err error) {...// 4. 重要!!!关键方法,调度预选,predicate过滤不符合的nodefilteredNodes, failedPredicateMap, filteredNodesStatuses, err := g.findNodesThatFit(pluginContext, pod)...// 8. 重要!!!上面如果找到多个node,那需要按照priority策略筛选priorityList, err := PrioritizeNodes(pod, g.nodeInfoSnapshot.NodeInfoMap, metaPrioritiesInterface, g.prioritizers, filteredNodes, g.extenders, g.framework, pluginContext)// 9. 好了,最终选一个node吧!host, err := g.selectHost(priorityList)
}
上节我们分析了 predicate 的 findNodesThatFit 方法的大体流程,如下:
func (g *genericScheduler) podFitsOnNode(pluginContext *framework.PluginContext, pod *v1.Pod, meta predicates.PredicateMetadata, info *schedulernodeinfo.NodeInfo, predicateFuncs map[string]predicates.FitPredicate, queue internalqueue.SchedulingQueue, alwaysCheckAllPredicates bool) (bool, []predicates.PredicateFailureReason, *framework.Status, error) {// 执行两次for i := 0; i < 2; i++ {if i == 0 {// 第一次,特殊处理podsAdded, metaToUse, nodeInfoToUse = addNominatedPods(pod, meta, info, queue)} else if !podsAdded || len(failedPredicates) != 0 {break}// 按照预设的predicate表依次执行for _, predicateKey := range predicates.Ordering() {// 真正执行 predicate if predicate, exist := predicateFuncs[predicateKey]; exist {fit, reasons, err = predicate(pod, metaToUse, nodeInfoToUse)}}...}
}
这篇文章我们来具体分析 podFitsOnNode 的逻辑
2. podFitsOnNode 为什么执行两次预选
看代码的时候,可以看到有一个 for 循环,循环里执行了两次,那么为什么要执行两次呢?先来看下源码里的注解:
// We run predicates twice in some cases. If the node has greater or equal priority// nominated pods, we run them when those pods are added to meta and nodeInfo.// If all predicates succeed in this pass, we run them again when these// nominated pods are not added. This second pass is necessary because some// predicates such as inter-pod affinity may not pass without the nominated pods.// If there are no nominated pods for the node or if the first run of the// predicates fail, we don't run the second pass.// We consider only equal or higher priority pods in the first pass, because// those are the current "pod" must yield to them and not take a space opened// for running them. It is ok if the current "pod" take resources freed for// lower priority pods.// Requiring that the new pod is schedulable in both circumstances ensures that// we are making a conservative decision: predicates like resources and inter-pod// anti-affinity are more likely to fail when the nominated pods are treated// as running, while predicates like pod affinity are more likely to fail when// the nominated pods are treated as not running. We can't just assume the// nominated pods are running because they are not running right now and in fact,// they may end up getting scheduled to a different node.for i := 0; i < 2; i++ {...}
好了,仔细看上面的注解之后,我们可以得出结论,在 Kubernetes 调度器的执行流程中,调度器会对这些预选函数执行两次的原因在于:
-
考虑已提名(nominated)Pod的影响:当集群中存在优先级较高的待调度但尚未运行的 Pod,并且它们被提名到某个节点上时,调度器需要考虑到这些“假定”已经运行在节点上的高优先级 Pod 对当前待调度 Pod 的影响。第一次预选会包含这些已提名的 Pod 信息,以模拟如果它们实际运行时的情况。
-
确保调度决策的保守性和正确性:由于一些预选条件(如资源限制和 Pod 间的亲和性/反亲和性)在不同的场景下可能有不同的结果,比如:
- 当已提名 Pods 被视为正在运行时,资源限制检查和 Pod 反亲和性检查更有可能失败。
- 当已提名 Pods 被视为未运行时,Pod 亲和性检查则可能更容易失败。
因此,调度器在这两次的预选差异在于:
3. 第一次预选时,包含了所有优先级相同或更高的已提名 Pods,如果此时预选成功,还需进行第二次预选
4. 第二次预选时,不包含这些已提名的 Pods,再次检查待调度 Pod 是否仍满足调度条件。
这样可以保证无论已提名的 Pod 最终是否会被调度到该节点上,当前待调度的 Pod 都能够适应两种情况下的调度环境。只有在这两次预选都通过的情况下,调度器才会将 Pod 分配给该节点。
3. 预选算法有哪些
实现在 pkg/scheduler/algorithm/predicates/predicates.go 文件下
var (predicatesOrdering = []string{CheckNodeConditionPred, CheckNodeUnschedulablePred,GeneralPred, HostNamePred, PodFitsHostPortsPred,MatchNodeSelectorPred, PodFitsResourcesPred, NoDiskConflictPred,PodToleratesNodeTaintsPred, PodToleratesNodeNoExecuteTaintsPred, CheckNodeLabelPresencePred,CheckServiceAffinityPred, MaxEBSVolumeCountPred, MaxGCEPDVolumeCountPred, MaxCSIVolumeCountPred,MaxAzureDiskVolumeCountPred, MaxCinderVolumeCountPred, CheckVolumeBindingPred, NoVolumeZoneConflictPred,CheckNodeMemoryPressurePred, CheckNodePIDPressurePred, CheckNodeDiskPressurePred, EvenPodsSpreadPred, MatchInterPodAffinityPred}
)...func CheckNodeMemoryPressurePredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {...
}// CheckNodeDiskPressurePredicate checks if a pod can be scheduled on a node
// reporting disk pressure condition.
func CheckNodeDiskPressurePredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {...
}// CheckNodePIDPressurePredicate checks if a pod can be scheduled on a node
// reporting pid pressure condition.
func CheckNodePIDPressurePredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {...
}// CheckNodeConditionPredicate checks if a pod can be scheduled on a node reporting
// network unavailable and not ready condition. Only node conditions are accounted in this predicate.
func CheckNodeConditionPredicate(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulernodeinfo.NodeInfo) (bool, []PredicateFailureReason, error) {...
}...
一些预选算法的解释:
NoVolumeZoneConflict:pod 请求的 volume 是否能在节点所在的 Zone 使用。通过匹配 node 和 PV 的 failure-domain.beta.kubernetes.io/zone 和 failure-domain.beta.kubernetes.io/region 来决定
MaxEBSVolumeCount:请求的 volumes 是否超过 EBS(Elastic Block Store) 支持的最大值,默认是 39
MaxGCEPDVolumeCount:请求的 volumes 是否超过 GCE 支持的最大值,默认是 16
MatchInterPodAffinity:根据 inter-pod affinity 来决定 pod 是否能调度到节点上。这个过滤方法会看 pod 是否和当前节点的某个 pod 互斥。
NoDiskConflict:检查 pod 请求的 volume 是否就绪和冲突。如果主机上已经挂载了某个卷,则使用相同卷的 pod 不能调度到这个主机上。kubernetes 使用的 volume 类型不同,过滤逻辑也不同。比如不同云主机的 volume 使用限制不同:GCE 允许多个 pods 使用同时使用 volume,前提是它们是只读的;AWS 不允许 pods 使用同一个 volume;Ceph RBD 不允许 pods 共享同一个 monitor
GeneralPredicates:普通过滤函数,主要考虑 kubernetes 资源是否能够满足,比如 CPU 和 Memory 是否足够,端口是否冲突、selector 是否匹配
PodFitsResources:检查主机上的资源是否满足 pod 的需求。资源的计算是根据主机上运行 pod 请求的资源作为参考的,而不是以实际运行的资源数量
PodFitsHost:如果 pod 指定了 spec.NodeName,看节点的名字是否何它匹配,只有匹配的节点才能运行 pod
PodFitsHostPorts:检查 pod 申请的主机端口是否已经被其他 pod 占用,如果是,则不能调度
PodSelectorMatches:检查主机的标签是否满足 pod 的 selector。包括 NodeAffinity 和 nodeSelector 中定义的标签。
PodToleratesNodeTaints:根据 taints 和 toleration 的关系判断 pod 是否可以调度到节点上
CheckNodeMemoryPressure:检查 pod 能否调度到内存有压力的节点上。
CheckNodeDiskPressure:检查 pod 能否调度到磁盘有压力的节点上,目前所有的 pod 都不能调度到磁盘有压力的节点上
下面的 predicates.Ordering() 就是按照列表把所有的默认预选算法依次执行一遍!
func (g *genericScheduler) podFitsOnNode(pluginContext *framework.PluginContext, pod *v1.Pod, meta predicates.PredicateMetadata, info *schedulernodeinfo.NodeInfo, predicateFuncs map[string]predicates.FitPredicate, queue internalqueue.SchedulingQueue, alwaysCheckAllPredicates bool) (bool, []predicates.PredicateFailureReason, *framework.Status, error) {// 执行两次for i := 0; i < 2; i++ {...for _, predicateKey := range predicates.Ordering() {// 真正执行 predicate if predicate, exist := predicateFuncs[predicateKey]; exist {fit, reasons, err = predicate(pod, metaToUse, nodeInfoToUse)}}...}
}
到目前为止就讲完了调度的预选主要流程了!后续继续讲解 priority 流程
4. 参考
《K8s 源码剖析及debug实战(一):Minikube 安装及源码准备》
《K8s 源码剖析及debug实战(二):debug K8s 源码》
《K8s 源码剖析及debug实战之 Kube-Scheduler(一):启动流程详解》
《K8s 源码剖析及debug实战之 Kube-Scheduler(二):终于找到了调度算法的代码入口》
《K8s 源码剖析及debug实战之 Kube-Scheduler(三):debug 到预选算法门口了》
欢迎关注本人,我是喜欢搞事的程序猿; 一起进步,一起学习;
也欢迎关注我的wx公众号:一个比特定乾坤

相关文章:
K8s 源码剖析及debug实战之 Kube-Scheduler(四):预选算法详解
文章目录 0. 引言1. 回顾2. podFitsOnNode 为什么执行两次预选3. 预选算法有哪些4. 参考 0. 引言 欢迎关注本专栏,本专栏主要从 K8s 源码出发,深入理解 K8s 一些组件底层的代码逻辑,同时借助 debug Minikube 来进一步了解 K8s 底层的代码运行…...
ES6之解构赋值详解
✨ 专栏介绍 在现代Web开发中,JavaScript已经成为了不可或缺的一部分。它不仅可以为网页增加交互性和动态性,还可以在后端开发中使用Node.js构建高效的服务器端应用程序。作为一种灵活且易学的脚本语言,JavaScript具有广泛的应用场景&#x…...
UntiyShader(五)属性、内置文件和变量
目录 一、如何使用属性 例子 ShaderLab中的属性的类型和Cg中的变量的类型之间的匹配关系 二、Unity提供的内置文件和变量 内置的包含文件 内置的变量 一、如何使用属性 在一开始我们提到过,材质和UnityShader之间有着密切的练习,我们可以通过材质面…...
Pytorch简介
1.1 Pytorch的历史 PyTorch是一个由Facebook的人工智能研究团队开发的开源深度学习框架。在2016年发布后,PyTorch很快就因其易用性、灵活性和强大的功能而在科研社区中广受欢迎。下面我们将详细介绍PyTorch的发展历程。 在2016年,Facebook的AI研究团队…...
亚马逊云科技Amazon Q,一款基于生成式人工智能的新型助手
近日,亚马逊云科技宣布推出Amazon Q,这是一款基于生成式人工智能(AI)的新型助手,专为辅助工作而设计,可以根据您的业务量身定制。通过连接到公司的信息存储库、代码、数据和企业系统,可以使用Am…...
骑砍战团MOD开发(29)-module_scenes.py游戏场景
骑砍1战团mod开发-场景制作方法_哔哩哔哩_bilibilihttps://www.bilibili.com/video/BV1Cw411N7G4/ 一.骑砍游戏场景 骑砍战团中进入城堡,乡村,战斗地图都被定义为场景,由module_scenes.py进行管理。 scene(游戏场景) 天空盒(Skyboxes.py) 地形(terrain code) 场景物(scene_…...
ROS学习记录:ROS系统中的激光雷达消息包的数据格式
一、在工作空间中输入source ./devel/setup.bash 二、输入roslaunch wpr_simulation wpb_simple.launch打开机器人仿真环境 三、机器人仿真环境打开成功 四、给机器人围上一圈障碍物 五、再打开一个工作空间终端 六、输入roslaunch wpr_simulation wpb_rviz.launch打开RViz 七、…...
Vue.js和Node.js的关系--类比Java系列
首先我们看一张图 这里我们类比了Java的jvm和JavaScript的node.js。 可以看到,node.js是基础,提供了基础的编译执行的能力。vue,js是实际上定义了一种他自己的代码格式,以加速开发。...
我的笔记本电脑死机问题折腾记录
两年前,买了一台笔记本电脑。直到今年4月份,不到两年的时间,便出现了花屏的情况,然后就到官方售后去维修,换屏。然后在6月份,屏幕问题再次出现,又去售后维修。 经过两次维修,笔记本…...
uniApp中uView组件库的丰富布局方法
目录 基本使用 #分栏间隔 #混合布局 #分栏偏移 #对齐方式 API #Row Props #Col Props #Row Events #Col Events UniApp的uView组件库是一个丰富的UI组件库,提供了各种常用的UI组件和布局方法,帮助开发者快速构建美观、灵活的界面。下面给你写一…...
TDD-LTE 寻呼流程
目录 1. 寻呼成功流程 1.1 空闲态寻呼 1.2 连接态寻呼 2. 寻呼失败流程 2.1 Paging消息不可达 2.2 RRC建立失败 2.3 eNodeB未上发Initial UE message或达到超时 1. 寻呼成功流程 1.1 空闲态寻呼 寻呼成功:MME发起寻呼(S1 接口发送Paing 消息&…...
TCP中的三次握手和四次挥手
TCP中的连接和断开可以说是在面试中经常被问到的问题之一,正好有空就总结一下,首先回顾一下TCP的相关知识点 1. TCP的基础知识 1.1 TCP的基本概念 我们知道TCP是运输层的面向连接的可靠的传输协议。面向连接的,指的就是在两个进程发送数据…...
NAO.99b海潮模型的详解教程
NAO.99b模型是由日本国家天文台开发的全球潮汐模式,基于二维非线性浅水方程。该模型具有较高的分辨率,网格间距为0.50.5,网格数为720360,覆盖的经度范围为0.25~359.75E,纬度范围为89.75S~89.75N…...
Plantuml之JSON数据语法介绍(二十五)
简介: CSDN博客专家,专注Android/Linux系统,分享多mic语音方案、音视频、编解码等技术,与大家一起成长! 优质专栏:Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏:多媒…...
迅为龙芯2K1000开发板虚拟机 ubuntu 更换下载源
Ubuntu 系统软件的下载安装我们通常使用命令“apt-get” , 该命令可以实现软件自动下载, 安装, 配置。 该命令采用客户端/服务器的模式, 我们的 Ubuntu 系统作为客户端, 当需要下载软件的时候就向服务器发起请求&#…...
你好!Apache Seata
北京时间 2023 年 10 月 29 日,分布式事务开源项目 Seata 正式通过 Apache 基金会的投票决议,以全票通过的优秀表现正式成为 Apache 孵化器项目! 根据 Apache 基金会邮件列表显示,在包含 13 个约束性投票 (binding votes) 和 6 个…...
RFC6749-OAuth2.0
前言 最近在项目中需要实现SSO(单点登录)功能,以实现一处注册,即可在任何平台之间登录的功能。我们项目中并没有直接对接第三方认证系统而是通过集成keycloak 完成一系类安全协议的对接工作。如果我们在代码级别自己完成各种安全协议的对接是一项十分大的工程。不仅要走统一的…...
【代码解析】代码解析之生成token(1)
本篇文章主要解析上一篇:代码解析之登录(1)里的第8行代码调用 TokenUtils 类里的genToken 方法 https://blog.csdn.net/m0_67930426/article/details/135327553?spm1001.2014.3001.5501 genToken方法代码如下: public static S…...
牛客网SQL训练5—SQL大厂面试真题
文章目录 一、某音短视频1.各个视频的平均完播率2.平均播放进度大于60%的视频类别3.每类视频近一个月的转发量/率4.每个创作者每月的涨粉率及截止当前的总粉丝量5.国庆期间每类视频点赞量和转发量6.近一个月发布的视频中热度最高的top3视频 二、用户增长场景(某度信…...
kubeadm来搭建k8s集群。
我们采用了二进制包搭建出的k8s集群,本次我们采用更为简单的kubeadm的方式来搭建k8s集群。 二进制的搭建更适合50台主机以上的大集群,kubeadm更适合中小型企业的集群搭建 主机配置建议:2c 4G 主机节点 IP …...
Vue3 + Element Plus + TypeScript中el-transfer穿梭框组件使用详解及示例
使用详解 Element Plus 的 el-transfer 组件是一个强大的穿梭框组件,常用于在两个集合之间进行数据转移,如权限分配、数据选择等场景。下面我将详细介绍其用法并提供一个完整示例。 核心特性与用法 基本属性 v-model:绑定右侧列表的值&…...
PPT|230页| 制造集团企业供应链端到端的数字化解决方案:从需求到结算的全链路业务闭环构建
制造业采购供应链管理是企业运营的核心环节,供应链协同管理在供应链上下游企业之间建立紧密的合作关系,通过信息共享、资源整合、业务协同等方式,实现供应链的全面管理和优化,提高供应链的效率和透明度,降低供应链的成…...
Opencv中的addweighted函数
一.addweighted函数作用 addweighted()是OpenCV库中用于图像处理的函数,主要功能是将两个输入图像(尺寸和类型相同)按照指定的权重进行加权叠加(图像融合),并添加一个标量值&#x…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
【ROS】Nav2源码之nav2_behavior_tree-行为树节点列表
1、行为树节点分类 在 Nav2(Navigation2)的行为树框架中,行为树节点插件按照功能分为 Action(动作节点)、Condition(条件节点)、Control(控制节点) 和 Decorator(装饰节点) 四类。 1.1 动作节点 Action 执行具体的机器人操作或任务,直接与硬件、传感器或外部系统…...
WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)
一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解,适合用作学习或写简历项目背景说明。 🧠 一、概念简介:Solidity 合约开发 Solidity 是一种专门为 以太坊(Ethereum)平台编写智能合约的高级编…...
Unsafe Fileupload篇补充-木马的详细教程与木马分享(中国蚁剑方式)
在之前的皮卡丘靶场第九期Unsafe Fileupload篇中我们学习了木马的原理并且学了一个简单的木马文件 本期内容是为了更好的为大家解释木马(服务器方面的)的原理,连接,以及各种木马及连接工具的分享 文件木马:https://w…...
Python 包管理器 uv 介绍
Python 包管理器 uv 全面介绍 uv 是由 Astral(热门工具 Ruff 的开发者)推出的下一代高性能 Python 包管理器和构建工具,用 Rust 编写。它旨在解决传统工具(如 pip、virtualenv、pip-tools)的性能瓶颈,同时…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
JVM 内存结构 详解
内存结构 运行时数据区: Java虚拟机在运行Java程序过程中管理的内存区域。 程序计数器: 线程私有,程序控制流的指示器,分支、循环、跳转、异常处理、线程恢复等基础功能都依赖这个计数器完成。 每个线程都有一个程序计数…...
