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 …...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...

树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
React Native 开发环境搭建(全平台详解)
React Native 开发环境搭建(全平台详解) 在开始使用 React Native 开发移动应用之前,正确设置开发环境是至关重要的一步。本文将为你提供一份全面的指南,涵盖 macOS 和 Windows 平台的配置步骤,如何在 Android 和 iOS…...

关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

DingDing机器人群消息推送
文章目录 1 新建机器人2 API文档说明3 代码编写 1 新建机器人 点击群设置 下滑到群管理的机器人,点击进入 添加机器人 选择自定义Webhook服务 点击添加 设置安全设置,详见说明文档 成功后,记录Webhook 2 API文档说明 点击设置说明 查看自…...

在Mathematica中实现Newton-Raphson迭代的收敛时间算法(一般三次多项式)
考察一般的三次多项式,以r为参数: p[z_, r_] : z^3 (r - 1) z - r; roots[r_] : z /. Solve[p[z, r] 0, z]; 此多项式的根为: 尽管看起来这个多项式是特殊的,其实一般的三次多项式都是可以通过线性变换化为这个形式…...
xmind转换为markdown
文章目录 解锁思维导图新姿势:将XMind转为结构化Markdown 一、认识Xmind结构二、核心转换流程详解1.解压XMind文件(ZIP处理)2.解析JSON数据结构3:递归转换树形结构4:Markdown层级生成逻辑 三、完整代码 解锁思维导图新…...
【HarmonyOS 5】鸿蒙中Stage模型与FA模型详解
一、前言 在HarmonyOS 5的应用开发模型中,featureAbility是旧版FA模型(Feature Ability)的用法,Stage模型已采用全新的应用架构,推荐使用组件化的上下文获取方式,而非依赖featureAbility。 FA大概是API7之…...
raid存储技术
1. 存储技术概念 数据存储架构是对数据存储方式、存储设备及相关组件的组织和规划,涵盖存储系统的布局、数据存储策略等,它明确数据如何存储、管理与访问,为数据的安全、高效使用提供支撑。 由计算机中一组存储设备、控制部件和管理信息调度的…...