调度分为几个部分:首先是过滤掉不满足条件的节点,这个过程称为 predicate ;然后对通过的节点按照优先级排序,这个是 priority ;最后从中选择优先级最高的节点。 NoDiskConflict:已经mount的volume和pod指定的volume不冲突,除非它们都是只读 如果在predicate过程中没有合适的节点,pod会一直在pending状态,不断重试调度
Scheduler是Kubernetes 的调度器,主要的任务是把定义的Pod分配到集群的节点上。 听起来非常简单,但有很多要考虑的问题: 公平:如何保证每个节点都能被分配资源 资源高效利用:集群所有资源最大化被使用 效率:调度的性能要好,能够尽快地对大批量的Pod完成调度工作 灵活:允许用户根据自己的需求控制调度的逻辑
你是否了解过她是怎么从众多的 node 节点中筛选出符合 pod 的调度节点,这里会从 k8s 的调度原理和流程开始结合源码内容带你了解整个调度过程,并配合一个小的调度实验,让你亲手实现一个简单的k8s PS:本文有些长,有兴趣的同学可以先收藏再阅读 k8s 调度器实现原理 k8s 中一个任务的创建流程 k8s 的 scheduler 和 controller manager,kubelet 这些是一样的 这里面的kube-scheduler调度器就是我们今天带大家了解的k8s基础组件之一 —— k8s的调度器。 pod 通过 pod 的 SchedulerName 判断是否属于这个调度器处理,kube-scheduler 的名字是 default-scheduler,因此 pod 没有专门指定调度器的都会被k8s 参考文献 配置多个调度器 k8s心跳 624调度框架提案
导语 | kubernetes调度器,通过watch机制来发现集群中新创建且未调度的pod,通过过滤node列表,打分策略,以及各个时机的插件调用机制,选择合适的node与之绑定。 注意:一个集群中可以有多个调度器,所以首先需要根据pod中的spec参数获取调度器名称 跳过pod:skipPodSchedule, 过滤调不需要调度的pod,比如正在删除中的pod,上个调度周期正在处理中的 在需要自定义调度的pod中,指定pod的spec.schedulerName 为自定义的调度器名称。 实现自定义调度器。部署自定义的调度器deployment。 在新版本1.19之后建议扩展自定义调度框架,如下例: import ( scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app
一、scheduler调度器 1、kube-scheduler简介 k8s实践(10) -- Kubernetes集群运行原理详解 介绍过kube-scheduler。 k8s Scheduler的调度流程是通过插件方式加载的“调度算法提供者”(AlgorithmProvider)具体实现的。 然后在创建pod的描述文件时指定对应标签,调度器就会将pod调度到符合标签选择器规则的工作节点上。 七、自定义调度器 如果 Kubernetes 调度器的众多特性还无法满足我们的独特调度需求,则还可以用自己开发的调度器进行调度。 但是如果在 Pod 中提供了自定义的调度器名称,那么默认的调度器会忽略该 Pod,转由指定的调度器完成 Pod 的调度。 1、创建自定义的调度器 下面看看如何创建一个自定义的调度器。
Kubernetes(简称K8s)是一个用于管理容器化应用程序的开源平台。 在K8s中,节点亲和度设置是一种调度分配策略,用于定义 Pod(一个或者多个容器的集合) 可以调度到哪些节点上以及基于怎样的规则分配 Pod 到各个节点。 前段时间在我们的 K8s 集群运行一些计算任务,但是发现好多 Pod 都会集中分配到一个节点上,这些计算任务比较依赖网速,同一个节点上执行非常影响任务的执行效率。 集群的默认调度方式是优先分配到到空闲资源比较多的节点上,但是我希望任务尽可能分配到不同的节点上,充分发挥多个节点的优势。 通过简单搜索发现可以配置调度器的调度亲和性来实现我的需求。 ,表示尽可能的满足配置的策略,当条件不满足时,它也能够接受编排于其它不符合条件的节点之上 podAffinityTerm:pod软亲和性使用它来挑选 Pod 标签 labelSelector:标签选择器 ️
如果调度器支持就绪状态切换到执行状态,同时支持执行状态切换为就绪状态,就称该调度器为抢占式调度器。 :普通进程的调度策略,使我们task以最低优先级选择CFS调度器来调度运行 SCHED_DEADLINE:限期进程调度策略,使我们task选择Deadline调度器来调度运行 注:stop调度器和DLE-task 调度器,仅使用于内核,用户没有办法进行选择 CFS调度器 完全公平调度算法体现在对待每个进程都是公平的,让每个进程都运行一段相同的时间片,这就是基于时间片轮询调度算法。 const struct sched_class *sched_class; // 表示该进程所属的调度器类 CFS:完全公平调度器。 周期性调度器:根据频率自动调用scheduler_tick函数,根据进程运行时间触发调度 上下文切换:主要做两个事情(切换地址空间、切换寄存器和栈空间) CFS调度器的
文章目录 一、调度子系统组件模块 二、主调度器、周期性调度器 三、调度器类 一、调度子系统组件模块 ---- 调度器 需要对 被调度的进程 进行 排序 和 调度管理 , 进程管理过程需要 调度器 的 组件模块 , 以及相关 算法 数据结构 来完成 , 如 : 执行队列 ; 二、主调度器、周期性调度器 ---- CPU 通过 " 上下文切换 " 选择 " 主调度器 " 或 " 周期性调度器 " , " 上下文切换 " 主要完成 切换地址空间 , 切换寄存器 , 切换栈空间 工作 ; " 主调度器 " 通过 调用 schedule() 方法 , 完成 进程的 调度 和 切换 ; " 周期性调度器 " 根据 相应频率 , 自动调用 scheduler_tick() 函数 , 完成调度 , 这是根据 进程 运行时间 , 自动触发进程调度 ; 三、调度器类 ---- 主调度器 或 周期性调度器 根据 不同的 " 选择进程 " 选择不同的 调度器类 , 可选的调度类参考 【Linux 内核】调度器 ⑦ ( 调度器类型 | 停机调度类 stop_sched_class | 限期调度类 dl_sched_class | 实时调度类
k8s scheduler 的主要职责是为新创建的 pod 寻找一个最合适的 node 节点, 然后进行 bind node 绑定, 后面 kubelet 才会监听到并创建真正的 pod。 • 调度器通过 Kubernetes 的监测机制来发现集群中新创建且尚未被调度到节点上的 Pod。 流程说明: • 1、默认调度器根据给定的参数启动。 上述设计在批调度器上就不是一定的,批调度器因为要支持gang scheduler,即比如一个 job 包含 5 个 pod,至少 3 个 pod 启动才可以正常工作,此时就不能一个 pod 一个pod 重试算法采用的是 指数退避机制,默认情况下最小为 1 秒,最大为 10 秒,例如,重试 3 次的 Pod 下一次的重试等待时间为 2^3 = 8 秒。
k8s 概述 定向调度 亲和性调度 污点和容忍 Pod的调度 概述 在默认情况下,一个Pod在哪个Node节点上运行,是由Scheduler组件采用相应的算法计算出来的,这个过程是不受人工控制的。 # 指定调度到k8s-node1节点上 强制性的 无论存不存在 • 创建Pod: kubectl create -f pod-nodename.yaml • 查看Pod: kubectl get pod Node,相当于软限制 (倾向) preference 一个节点选择器项,与相应的权重相关联 matchFields 按节点字段列出的节点选择器要求列表 matchExpressions labelSelector 标签选择器 matchExpressions 按节点标签列出的节点选择器要求列表(推荐) key 键 values # 将目标pod定向调度到k8s-node1 # 创建参照Pod: kubectl create -f pod-podaffinity-target.yaml # 查看参照Pod: kubectl
O(n) 调度器。 O(1) 调度器 在 linux 内核采用 O(n) 调度器的 4 年后,Linux2.6.0 采纳了 Rad Hat 公司设计的 O(1) 调度算法,这是一个基于上一篇文章中介绍的多级反馈队列算法的调度器实现 4.1 调度器分层思想 而事实证明,在公平策略调度器基础上改进设计的 CFS 确实是一款优秀的调度器,它的思想是将调度器进行模块化,从而让操作系统中可以有多种调度器以不同的策略和优先级来执行。 操作系统中,调度器由此分为四层: DL 调度器:采用 sched_deadline 策略; RT 调度器:采用 sched_rr 和 sched_fifo 策略; CFS 调度器:采用 sched_normal O(n) 调度器这类通过分配固定时间片的调度器所不能实现的。
文章目录 一、调度器 0、调度器概念 1、调度器目的 2、调度器主要工作 3、调度器位置 4、进程优先级 5、抢占式调度器 二、Linux 内核进程状态 API 简介 三、Linux 进程状态 一、调度器 ---- 0、调度器概念 Linux 内核的 " 进程调度 " 是按照 设计好的调度算法 安排的 , 该算法对应的功能模块 称为 " 调度器 " , 英文名称是 Scheduler ; 1、调度器目的 进程调度 目的是 最大限度利用 CPU 资源 , 也就是 CPU 时间片 ; 2、调度器主要工作 " 调度器 " 主要的工作 : ① 就绪 -> 执行 : 选择 " 就绪状态 " 的进程执行 ; ( " , 主要是 " 就绪状态 " 与 " 执行状态 " 这两个状态之间相互切换 ; 3、调度器位置 调度器 在 如下的 进程状态图 中的位置是 " 就绪状态 " 与 " 运行状态 " 之间 ; 就绪状态 " 抢占式调度器 " 概念 : 如果 " 调度器 " 支持 " 就绪状态 " 与 " 运行状态 " 之间可以相互转换 , 则该调度器称为 " 抢占式调度器 " ; 二、Linux 内核进程状态 API
在K8S集群中,调度器负责将客户提交的pod绑到某个node节点上,完成pod调度的调度工作。 在这个调度过程中,调度器的优选策略会对集群中的每个node节点都打上一个分数(score),得分最高的节点,调度器将调度pod到该节点上运行。 调度器的优选策略及相关说明 (基于k8s 1.18版本) 名称 权重(weight) 插件(plugin) 说明 默认 相关特性 取值 决定因素 SelectorSpreadPriority 1 DefaultPodTopologySpread 最小化同一节点或者zone上的Pod数量(属于同一服务或复制控制器) 是 否 0-100 无 InterPodAffinityPriority 1 InterPodAffinity pod应该或不应该与其他 调度pod到容忍了污点的node 是 否 0 节点是否有配置污点,且effect值为PreferNoSchedule ImageLocalityPriority 1 ImageLocality 优先调度
在k8s 1.18版本中默认开启。在该优选策略的实现中,使用的是DefaultPodTopologySpread打分插件。 用于在Score阶段,过滤出节点上与pod(待调度)同一个的其他pods对象。 Score 打分的统计阶段。 对于该优选策略,统计节点会给node上的pods做统计,统计的匹配条件是被调度pod的namespace和preScore推导出的selector,方法是遍历当前node节点上所有的pods,如果符合匹配条件 代码逻辑如下: image.png NormalizeScore 分数计算阶段,在该阶段,会计算出所有node的分数(在调度过程中起作用的分数值)。 image.png 由上图可以得出,node4000101的打分是16,node4000102的打分是0,node4000201的打分是61,所以在考虑其他策略打分一样的情况下,新扩容的pod会被调度到
上一篇文章《Go语言高阶:调度器系列(1)起源》,学goroutine调度器之前的一些背景知识,这篇文章则是为了对调度器有个宏观的认识,从宏观的3个角度,去看待和理解调度器是什么样子的,但仍然不涉及具体的调度原理 Scheduler的宏观组成 Tony Bai在《也谈goroutine调度器》中的这幅图,展示了goroutine调度器和系统调度器的关系,而不是把二者割裂开来,并且从宏观的角度展示了调度器的重要组成 Goroutine调度器和OS调度器是通过M结合起来的,每个M都代表了1个内核线程,OS调度器负责把内核线程分配到CPU的核上执行。 调度器的生命周期 接下来我们从另外一个宏观角度——生命周期,认识调度器。 所有的Go程序运行都会经过一个完整的调度器生命周期:从创建到结束。 ? 总结时刻 这篇文章,从3个宏观的角度介绍了调度器,也许你依然不知道调度器的原理,心里感觉模模糊糊,没关系,一步一步走,通过这篇文章希望你了解了: Go调度器和OS调度器的关系 Go调度器的生命周期/总体流程
上一篇文章《Go语言高阶:调度器系列(1)起源》,学goroutine调度器之前的一些背景知识,这篇文章则是为了对调度器有个宏观的认识,从宏观的3个角度,去看待和理解调度器是什么样子的,但仍然不涉及具体的调度原理 Scheduler的宏观组成 Tony Bai在《也谈goroutine调度器》中的这幅图,展示了goroutine调度器和系统调度器的关系,而不是把二者割裂开来,并且从宏观的角度展示了调度器的重要组成 Goroutine调度器和OS调度器是通过M结合起来的,每个M都代表了1个内核线程,OS调度器负责把内核线程分配到CPU的核上执行。 调度器的生命周期 接下来我们从另外一个宏观角度——生命周期,认识调度器。 所有的Go程序运行都会经过一个完整的调度器生命周期:从创建到结束。 ? 总结时刻 这篇文章,从3个宏观的角度介绍了调度器,也许你依然不知道调度器的原理,心里感觉模模糊糊,没关系,一步一步走,通过这篇文章希望你了解了: Go调度器和OS调度器的关系 Go调度器的生命周期/总体流程
2 调度器原理和设计 K8s 默认调度器的整体工作框架可以简单用下图概括: image.png 2.1 两个控制循环 1 . 而为了不在主流程路径中访问 Api Server 影响性能,调度器只会更新 Scheduler Cache 中的相关 pod 和 node 信息:这种基于乐观假设的 API 对象更新方式,在 K8s 中称为 3 大规模集群调度带来问题和挑战 K8s 默认调度器策略在小规模集群下有着优异表现,但是随着业务量级的增加以及业务种类的多样性变化,默认调度策略则逐渐显露出局限性:调度维度较少,无并发 K8s Serverless 为每一个 Job POD 单独申请了独立的 POD 运行 sanbox,也就是任务调度器,完整并行。 正常场景下,当一个 Pod 调度失败,这个 Pod 会保持在 pending 的状态,等待 Pod 更新或者集群资源发生变化进行重新调度,但是 K8s 调度器依然存在一个抢占功能,可以使得高优先级 Pod
这就涉及goroutine的G-P-M调度模型。 G-P-M调度模型 Golang能够拥有强大的并发能力需要归功于G-P-M调度模型,首先需要解释G、P、M分别代表什么: ? P 代表Processor,逻辑处理器。P维护Goroutine各种队列,mcache和状态。P的数量决定了最大可并行的Goroutine数量(前提:系统物理CPU核数>=P数量)。 调度逻辑 ? 从图中可以看出,一共有两个物理线程M,每个M都绑定一个处理器P,每个P维护一个就绪状态的Goroutine队列,灰色的表示在等待P调度,蓝色的G代表正绑定P在M中执行。 当执行的Goroutine(G0)调度阻塞的系统调度时,P会切到另外的M'中,如果没有可用的M'就会创建一个,继续执行队列中的G。 总结 文章介绍了Golang自带的goroutine调度器G-P-M调度模型,G-P-M调度算法最大限度的发挥了并发性能,同时在一些异常情况下也能正常快速调度。
SMP调度 多处理器系统上,内核必须考虑几个额外的问题,以确保良好的调度。 CPU负荷必须尽可能公平地在所有的处理器上共享。 特定于调度器类的函数接下来建立一个迭代器,使得核心调度器能够遍历所有可能迁移到另一个队列的备选进程,但各个调度器类的内部结构不能因为迭代器而暴露给核心调度器。 1.3 核心调度器的改变 除了上述增加的特性之外,在SMP系统上还需要对核心调度器的现存方法作一些修改。虽然到处都是一些小的细节变化,与单处理器系统相比最重要的差别如下所示。 完全公平调度器的调度粒度与CPU的数目是成比例的。系统中处理器越多,可以采用的调度粒度就越大。 调度域和控制组 在此前对调度器代码的讨论中,调度器并不直接与进程交互,而是处理可调度实体。这使得可以实现组调度:进程置于不同的组中,调度器首先在这些组之间保证公平,然后在组中的所有进程之间保证公平。
之所以不使用 channel 结构,是因为调度 pod 可能需要一些时间,k8s 不希望 pod 位于通道中变得陈旧。 Error:在出现错误的时候被调用。 k8s 中有各种类型的资源,包括自定义的。而 Informer 的实现就将调度和资源结合了起来。 在 k8s 中经过调度器调度后的 pod 结果会放入到 SchedulingQueue 中进行暂存,这些 pod 未来可能会经过后续调度流程运行在提议的 node 上,也可能因为某些原因导致最终没有运行 = nil { //扩展器的优先级错误可以忽略,让k8s/其他扩展器确定优先级。 因为 PostFilter 与过滤无关,是用来实现抢占的扩展点; 3.3 总结 Scheduler 调度器,在 k8s 的整个代码中处于一个承上启下的作用。