• 如何实现schedule水平扩展


    基于kubernetes调度框架的自定义调度器实现

    kube-scheduler 是 kubernetes 的核心组件之一,主要负责整个集群资源的调度功能,根据特定的调度算法和策略,将 Pod 调度到最优的工作节点上面去,从而更加合理、更加充分的利用集群的资源,这也是我们选择使用 kubernetes 一个非常重要的理由。如果一门新的技术不能帮助企业节约成本、提供效率,我相信是很难推进的。

    调度流程

    默认情况下,kube-scheduler 提供的默认调度器能够满足我们绝大多数的要求,我们前面和大家接触的示例也基本上用的默认的策略,都可以保证我们的 Pod 可以被分配到资源充足的节点上运行。但是在实际的线上项目中,可能我们自己会比 kubernetes 更加了解我们自己的应用,比如我们希望一个 Pod 只能运行在特定的几个节点上,或者这几个节点只能用来运行特定类型的应用,这就需要我们的调度器能够可控。

    kube-scheduler 的主要作用就是根据特定的调度算法和调度策略将 Pod 调度到合适的 Node 节点上去,是一个独立的二进制程序,启动之后会一直监听 API Server,获取到 PodSpec.NodeName 为空的 Pod,对每个 Pod 都会创建一个 binding。

     

    kube-scheduler structrue

    这个过程在我们看来好像比较简单,但在实际的生产环境中,需要考虑的问题就有很多了:

    • 如何保证全部的节点调度的公平性?要知道并不是所有节点资源配置一定都是一样的

    • 如何保证每个节点都能被分配资源?

    • 集群资源如何能够被高效利用?

    • 集群资源如何才能被最大化使用?

    • 如何保证 Pod 调度的性能和效率?

    • 用户是否可以根据自己的实际需求定制自己的调度策略?

    考虑到实际环境中的各种复杂情况,kubernetes 的调度器采用插件化的形式实现,可以方便用户进行定制或者二次开发,我们可以自定义一个调度器并以插件形式和 kubernetes 进行集成。

    kubernetes 调度器的源码位于 kubernetes/pkg/scheduler 中,大体的代码目录结构如下所示:(不同的版本目录结构可能不太一样)

    kubernetes/pkg/scheduler
    -- scheduler.go         //调度相关的具体实现
    |-- algorithm
    |   |-- predicates      //节点筛选策略
    |   |-- priorities      //节点打分策略
    |-- algorithmprovider
    |   |-- defaults         //定义默认的调度器

    其中 Scheduler 创建和运行的核心程序,对应的代码在 pkg/scheduler/scheduler.go,如果要查看kube-scheduler 的入口程序,对应的代码在 cmd/kube-scheduler/scheduler.go

    自定义调度器

    一般来说,我们有4种扩展 Kubernetes 调度器的方法。

    1. 一种方法就是直接 clone 官方的 kube-scheduler 源代码,在合适的位置直接修改代码,然后重新编译运行修改后的程序,当然这种方法是最不建议使用的,也不实用,因为需要花费大量额外的精力来和上游的调度程序更改保持一致。

    2. 第二种方法就是和默认的调度程序一起运行独立的调度程序,默认的调度器和我们自定义的调度器可以通过 Pod 的 spec.schedulerName 来覆盖各自的 Pod,默认是使用 default 默认的调度器,但是多个调度程序共存的情况下也比较麻烦,比如当多个调度器将 Pod 调度到同一个节点的时候,可能会遇到一些问题,

      1. 因为很有可能两个调度器都同时将两个 Pod 调度到同一个节点上去,但是很有可能其中一个 Pod 运行后其实资源就消耗完了;
      2. 并且维护一个高质量的自定义调度程序也不是很容易的,因为我们需要全面了解默认的调度程序,整体 Kubernetes 的架构知识以及各种 Kubernetes API 对象的各种关系或限制。
    3. 第三种方法是调度器扩展程序,这个方案目前是一个可行的方案,可以和上游调度程序兼容,所谓的调度器扩展程序其实就是一个可配置的 Webhook 而已,里面包含 过滤器 和 优先级 两个端点,分别对应调度周期中的两个主要阶段(过滤和打分)。在我们现在的 v1.16 版本中上面的 调度器扩展程序 也已经被废弃了,2022年4月1日后也被移除了。

    Kubernetes 开始只提供了 Extender ,通过部署一个 Web 服务实现无侵入式扩展 scheduler插件,但其存在以下几个问题:

    1. **Extender 扩展点的数量是有限的:**在调度期间只有“Filter”和“Prioritize”扩展点。 “Preempt”扩展点在运行默认抢占机制后被调用。“Bind”扩展点用于绑定Pod,且 Bind 扩展点只能绑定一个扩展程序,扩展点会替换掉调度器的 bind 操作。Extender 不能在其他点被调用,例如,不能在运行 predicate 函数之前被调用。
    2. **性能问题:**对扩展程序的每次调用都涉及 JSON 的编解码。调用 webhook(HTTP 请求)也比调用原生函数慢。
    3. **调度器无法通知 Extender 已中止 Pod 的调度。**例如,如果一个 Extender 提供了一个集群资源,而调度器联系了 Extender 并要求它为正在调度的 pod 提供资源的实例,然后调度器在调度 pod 时遇到错误并决定中止调度,那么将很难与扩展程序沟通错误并要求它撤消资源的配置。
    4. 由于当前的Extender作为一个单独的进程运行,因此不能使用调度器的缓存。要么从 API Server构建自己的缓存,要么只处理他们从调度器接收到的信息。
    1. 第四种方法是通过调度框架(Scheduling Framework),Kubernetes v1.15 版本中引入了可插拔架构的调度框架,使得定制调度器这个任务变得更加的容易。调库框架向现有的调度器中添加了一组插件化的 API,该 API 在保持调度程序“核心”简单且易于维护的同时,使得大部分的调度功能以插件的形式存在,而且在我们现在的 v1.16 版本中上面的 调度器扩展程序 也已经被废弃了,2022年4月1日后也被移除了,所以以后调度框架才是自定义调度器的核心方式。

      Scheduling Framework 调度框架是一组新的“插件”API,通过这些 API 允许将许多调度功能使用插件实现,同时保持调度器“核心”简单和可维护。调度器插件必须用 Go 编写,并使用 Kubernetes 调度器代码编译,有一定学习成本。

    这里我们可以简单介绍下调度框架(Scheduling Framework)方式的实现。

     
     
  • 相关阅读:
    C# WinForm编程TabControl控件的标签TabPage怎么做成图片
    javascript 用面向对象自写前端验证工具
    javascript 用面向对象自写stringbuffer工具
    java socket 深入学习tomcat 自写动态服务器 tomcat
    java socket 自写静态服务器 apache
    java socket 实现多个客户端通过服务器一对一聊天并实现文件传输
    java socket 实现多个客户端向服务器上传文件
    java socket 实现多个一对一聊天
    java 读取文件,内容方置Person 序列化到磁盘,在读入程序并写到另外地址
    java 读取文件,内容方置Person 并写到另外地址
  • 原文地址:https://www.cnblogs.com/gaoyuechen/p/16528329.html
Copyright © 2020-2023  润新知