zoukankan      html  css  js  c++  java
  • k8s调度器扩展机制

    在kube-scheduler有四种扩展机制:

    一、Multiple Scheduler

    若要部署第二调度器,可以直接修改kubernetes的源码
    git clone https://github.com/kubernetes/kubernetes.git
    cd kubernetes
    make
    使用如下Dockerfile构建成镜像:
    FROM busybox
    ADD ./_output/local/bin/linux/amd64/kube-scheduler /usr/local/bin/kibe-scheduler
    创建ServiceAccount并将其绑定到ClusterRole,使其与kube-scheduler具有相同的权限:
    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: my-scheduler
      namespace: kube-system
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: my-scheduler-as-kube-scheduler
    subjects:
    - kind: ServiceAccount
      name: my-scheduler
      namespace: kube-system
    roleRef:
      kind: ClusterRole
      name: system:kube-scheduler
      apiGroup: rbac.authorization.k8s.io
    ---
    apiVersion: rbac.authorization.k8s.io/v1
    kind: ClusterRoleBinding
    metadata:
      name: my-scheduler-as-volume-scheduler
    subjects:
    - kind: ServiceAccount
      name: my-scheduler
      namespace: kube-system
    roleRef:
      kind: ClusterRole
      name: system:volume-scheduler
      apiGroup: rbac.authorization.k8s.io
    部署该调度器:
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      labels:
        component: scheduler
        tier: control-plane
      name: my-scheduler
      namespace: kube-system
    spec:
      selector:
        matchLabels:
          component: scheduler
          tier: control-plane
      replicas: 1
      template:
        metadata:
          labels:
            component: scheduler
            tier: control-plane
            version: second
        spec:
          serviceAccountName: my-scheduler
          containers:
          - command:
            - /usr/local/bin/kube-scheduler
            - --address=0.0.0.0
            - --leader-elect=false
            - --scheduler-name=my-scheduler
            image: xxxxxx
            livenessProbe:
              httpGet:
                path: /healthz
                port: 10251
              initialDelaySeconds: 15
            name: kube-second-scheduler
            readinessProbe:
              httpGet:
                path: /healthz
                port: 10251
            resources:
              requests:
                cpu: '0.1'
            securityContext:
              privileged: false
            volumeMounts: []
          hostNetwork: false
          hostPID: false
          volumes: []
    启动时通过参数scheduler-name指定了第二调度器的名字
    Pod通过spec.schedulerName指定使用的调度器(默认调度器是default-scheduler)
     

    二、Multiple profiles

    无需部署第二调度器,1.18+的kube-scheduler默认支持多profile:
    apiVersion: kubescheduler.config.k8s.io/v1beta1
    kind: KubeSchedulerConfiguration
    profiles:  
      - schedulerName: default-scheduler  
      - schedulerName: no-scoring-scheduler    
        plugins:      
          preScore:        
            disabled:        
            - name: '*'      
          score:        
            disabled:        
            - name: '*'

    三、Schduler Extender

    在启动官方调度器之后,可以再启动一个扩展调度器Schedule Extender。
    Scheduler Extender实际上是一个额外的调度进程,用户需要实现自己的Filter方法、Prioritize方法、Bind方法
    策略文件的配置内容:
    apiVersion: v1
    kind: Policy
    alwaysCheckALLPredicates: false  # 不管每个prediacate的结果,所有的predicate都要走一遍
    predicates:['GeneralPredicates','...']  # 不配的话使用默认的predicates;为空列表则跳过所有配置
    hardPodAffinitySymmetricWeight:
    # 配置打分算法插件;不配的话使用默认的打分插件;为空列表则跳过所有配置
    priorities:
    - name: LeastRequestedPriority
      weight: 1
    extenders:
    - urlPrxfix: "http://xxx:xxx/scheduler-gpu-extender"
      filterVerb: filter
      exableHttps: false
      nodeCacheCapable: true  # 服务是否已经有NodeCache,为true则调度器传递nodeName列表而不是整个nodeinfo完整结构
      ignorable: false   # 调用扩展调度器不成功时(如报错或网络问题),是否可忽略扩展调度器
      managedResources:
      - name: "example/gpu-mem"    # 官方调度器在遇到这个Resource时会用扩展调度器
        ignoredByScheduler: false  # resourceFit阶段是否忽略这个资源的校验
    这里可以看到配置的过滤器predicates、配置的打分器 priorities、配置的扩展调度器。
     
    以Filter阶段举例,执行过程会经过2个阶段:
    (1)scheduler会先执行内置的Filter策略。如果执行失败,会直接标识Pod调度失败;
    (2)如果内置的Filter策略执行成功,scheduler通过http调用Extender注册的webhook,将调度所需要的Pod和Node的信息发送到Extender,根据返回Filter结果作为最终结果。
    Schedule Extender存在以下问题:
    (1)调用Extender的接口是HTTP请求,性能远低于本地的函数调用。同时每次调用都需要将Pod和Node的信息进行marshaling和unmarshalling的操作,会进一步降低性能;
    (2)用户可以扩展的点比较有限,位置比较固定,无法支持灵活的扩展,例如只能在执行完默认的Filter策略后才能调用。
    因此,Extender在集群规模较小,调度效率要求不高的情况下,是一个灵活可用的扩展方案。但是在正常生产环境的大型集群中,Extender无法支持高吞吐量,性能较差。
     

    四、Scheduling Framework

    基于scheduler framework进行out-of-tree的scheduler plugins开发示例:
    kubernetes-sigs团队实现了两个插件示例

    1、Qos的插件

    调度过程中如果Pod的优先级相同,根据Pod的Qos来决定调度顺序
    (1)插件构造
    定义插件的对象和构造函数:
    type Sort struct {}
    // 新初始化一个插件,返回它
    func New(_ *runtime.Unknown, _ framework.FrameworkHandle) (framework.Plugin, error){
        return &Sort{}, nil
    }
    然后,实现QueueSort接口的Less函数,改为在优先级相同的情况下,通过比较Qos来决定优先级。
    func (*Sort) Less(pInfo1, pInfo2 *framework.PodInfo) bool{
        p1 := pod.GetPodPriority(pInfo1.Pod)
        p2 := pod.GetPodPriority(pInfo2.Pod)
        return (p1 > p2) || (p1 == p2 && compQOS(pInfo1.Pod, pInfo2.Pod))
    }
    func compQOS(p1, p2 *v1.Pod) bool{
        p1QOS, p2QOS := v1qos.GetPodQOS(p1), v1qos.GetPodQOS(p2)
        if p1QOS == v1.PodQOSGuaranteed {
            return true
        } else if p1QOS == v1.PodQOSBurstable {
            return p2QOS != v1.PodQOSGuaranteed
        } else{
            return p2QOS == v1.PodQOSBestEffort
        }
    }
    (2)插件注册在main函数中注册自定义插件和相应的构造函数:
    func main() {    
        rand.Seed(time.Now().UnixNano())    // 向scheduler framework注册用户自定义插件    
        command := app.NewSchedulerCommand(        
            app.WithPlugin(qos.Name, qos.New),        
            app.WithPlugin(qos.Name, qos.New),    
        )    
        if err := command.Execute(); 
        err != nil {        
            os.Exit(1)    
        }
    }
    (3)通过make命令进行代码编译
    (4)配置scheduler-config.yaml
    apiVersion: kubescheduler.config.k8s.io/v1alpha2
    kind: KubeSchedulerConfiguration
    leaderElection:
      leaderElect: false
    clientConnection:
      kubeconfig: "REPLACE_ME_WITH_KUBE_CONFIG_PATH"
    profiles:
    - schedulerName: default-scheduler
      plugins:
        queueSort:
          enabled:
          - name: QOSSort
          disabled:
          - name: "*"
    启动kube-scheduler时传入集群的kubeconfig文件以及插件的配置文件即可
    $ kube-scheduler --kubeconfig=scheduler.conf --config=scheduler-config.yaml

    2、Coscheduling插件

    在并发系统中将多个相关联的进程调度到不同处理器上同时运行,需要保证所有相关联的进程能够同时启动。
    部分进程的异常,可能导致整个关联进程组的阻塞。这种导致阻塞的部分异常进程,称之为碎片(fragement)。
    Coscheduling的具体实现过程中,根据是否允许碎片存在,可以细分为完全不允许有碎片存在的Explicit Coscheduling(Gang Scheduling)、Local Coscheduling和Implicit Coscheduling。
    对应到Kubernetes中,Coscheduling的含义就是:一个批任务(关联进程组)包括了N个Pod(进程),Kubernetes调度器负责将这N个Pod组成的PodGroup调度到M个节点(处理器)上同时运行。
    如果这个批任务需要部分Pod同时启动即可运行,称需启动Pod的最小数量为min-available。
    特别地,当min-available=N时,批任务要求满足Gang Scheduling。
     
    插件通过给Pod打label的形式来定义PodGroup:
        pod-group.scheduling.sigs.k8s.io/name:xxx用于表示PodGroup的Name;
        pod-group.scheduling.sigs.k8s.io/min-available:"2" 表示PodGroup能够运行所需要的最小副本数
    备注:要求属于同一个PodGroup的Pod必须保持相同的优先级
     
    Permit阶段使用了延迟绑定功能,当属于同一个PodGruop的Pod数量不够时,进行等待;积累的Pod数目足够时,才会将所有Pod全部绑定并创建。
    如果某个Pod在Permit阶段等待超时了,则会进入到UnReserve阶段。
    QueueSort阶段,由于默认的Scheduler队列并不能感知 PodGroup 的信息,同一个PodGroup中的Pod在队列中是混乱无序的。
    一旦某个PodGroup在 Permit 阶段处于等待状态,其它的PodGroup也会因此处于等待状态,从而导致死锁。
    此处自定义的Less方法继承了默认的基于优先级的比较方式,高优先级的Pod会排在低优先级的Pod之前。如果两个Pod的优先级相同,则采用新的排队逻辑,以保证队列中属于同一个PodGroup的Pod排列在一起:  
    • 如果两个Pod 都是普通的Pod,则谁先创建谁在队列里边排在前边;
    • 如果两个Pod 一个是普通的Pod,另一个是属于某个PodGroup的Pod,则比较的是前者的创建时间和后者所属PodGroup的创建时间;
    • 如果两个Pod 都是属于某个PodGroup的Pod,比较两个 PodGroup 的创建时间,则谁先创建谁在队列里排在前边;
    • 如果两个PodGroup 的创建时间相同,谁的PodGroup 的自增Id谁小谁在队列里排在前边
    Prefilter 阶段增加一个过滤条件,当一个Pod调度时,会计算该Pod所属PodGroup的Pod的Sum(包括Running状态的),如果Sum小于min-available时,则肯定无法满足min-available要求,则直接在该阶段拒绝掉,不再进入调度的主流程。
    UnReserve 阶段会直接拒绝掉所有跟Pod属于同一个PodGroup的Pod,避免剩余的Pod进行长时间的无效等待。
     
    Coscheduling插件和原生调度器代码已经统一构建成一个容器镜像。可以通过helm chart包ack-coscheduling来自动安装。它会启动一个任务,自动用Coscheduling scheduler替换原生的kube-scheduler,并且会修改相关Config文件,使scheduling framework正确地加载Coscheduling 插件。
     
    下载 helm chart包,执行命令安装:
    $  wget http://kubeflow.oss-cn-beijing.aliyuncs.com/ack-coscheduling.tar.gz
    $  tar zxvf ack-coscheduling.tar.gz
    $  helm install ack-coscheduling -n kube-system ./ack-coscheduling
    NAME: ack-coscheduling
    LAST DEPLOYED: Mon Apr 13 16:03:57 2020
    NAMESPACE: kube-system
    STATUS: deployed
    REVISION: 1
    TEST SUITE: None
    在 Master 节点上,使用helm命令验证是否安装成功。
    $ helm get manifest ack-coscheduling -n kube-system | kubectl get -n kube-system -f -
    NAME                           COMPLETIONS   DURATION   AGE
    scheduler-update-clusterrole   1/1           8s         35s
    scheduler-update               3/1 of 3      8s         35s
    使用Coscheduling时,只需要在创建任务的yaml描述中配置两个描述任务状态的label即可。
    通过 helm 卸载,将kube-scheduler的版本及配置回滚到集群默认的状态:
    $ helm uninstall ack-coscheduling -n kube-system
     
     
    阿里云实现的插件:

    3、RequestedToCapacityRatio插件

    用户自己定义的资源利用率与得分间的线性关系、根据哪些资源进行打分、每种资源的权重:
    apiVersion: kubescheduler.config.k8s.io/v1alpha1
    kind: KubeSchedulerConfiguration
    leaderElection:
      leaderElect: false
    clientConnection:
      kubeconfig: "REPLACE_ME_WITH_KUBE_CONFIG_PATH"
    plugins:
      score:
        enabled:
        - name: RequestedToCapacityRatio
          weight: 100
        disabled:
        - name: LeastRequestedPriority
    pluginConfig:
    - name: RequestedToCapacityRatio
      args:
        functionshape:
          - utilization: 0
            score: 0
          - utilization: 100
            score: 100
        resourcetoweightmap: # 定义具体根据哪种资源类型进行binpack操作,多种资源时可以设置weight来进行比重设置
          "cpu": 1
          "nvidia.com/gpu": 1
    在打分过程中,会通过计算(pod.Request + node.Allocated)/node.Total的结果得到对应资源的利用率,并且将利用率带入上文中所述的打分函数中,得到相应的分数。
    最后将所有的资源根据weight值,加权得到最终的分数。
  • 相关阅读:
    可实现B站 蒙版弹幕 效果的前端组件 —— Barrage UI
    C# 中的"yield"使用
    不遮挡人物弹幕是怎么实现的——图片蒙版效果-webkit-mask
    使用eslint检查代码质量
    vue 项目中assets 和static的区别
    快速生成html文本文档——typora
    VsCode中好用的git源代码管理插件GitLens
    C# 根据前台校验的值,决定是否执行后台方法
    C# 从字符串中取出英文字母
    C# 科学计数法转换成数字
  • 原文地址:https://www.cnblogs.com/yangyuliufeng/p/14257928.html
Copyright © 2011-2022 走看看