Kubernetes Scheduler Framework 扩展: 1. Coscheduling

简介: # 前言 ## 为什么Kubernetes需要Coscheduling功能? Kubernetes目前已经广泛的应用于在线服务编排,为了提升集群的的利用率和运行效率,我们希望将Kubernetes作为一个统一的管理平台来管理在线服务和离线作业。但是默认的调度器是以Pod为调度单元进行依次调度,不会考虑Pod之间的相互关系。但是很多数据计算类的作业具有All-or-Nothing特点,要求所有的

前言

为什么Kubernetes需要Coscheduling功能?

Kubernetes目前已经广泛的应用于在线服务编排,为了提升集群的的利用率和运行效率,我们希望将Kubernetes作为一个统一的管理平台来管理在线服务和离线作业。但是默认的调度器是以Pod为调度单元进行依次调度,不会考虑Pod之间的相互关系。但是很多数据计算类的作业具有All-or-Nothing特点,要求所有的任务都成功创建后才能正常运行,如果只是部分任务启动的话,启动的任务将持续等待剩余的任务被调度。

如下图所示,JobA需要4个Pod同时启动,才能正常运行。Kube-scheduler依次调度3个Pod并创建,到第4个Pod时,集群资源不足,则JobA的3个Pod处于空等的状态,导致集群资源浪费。

a7625e7e076ea1714d623c1d3bf0dfd1.png

如果出现更坏的情况的话,如下图所示,集群其他的资源刚好被JobB的3个Pod所占用,同时在等待JobB的第4个Pod创建,此时整个集群就出现了死锁。

ddfd5cc8d821e1b596d238c24d5c5107.png

社区相关的方案

社区目前有Kube-batch以及基于Kube-batch衍生的Vocalno 2个项目来解决上文中提到的痛点。实现的方式是通过开发新的调度器将Scheduler中的调度单元从Pod修改为PodGroup,以组的形式进行调度。使用方式是如果需要Coscheduling功能的Pod走新的调度器,其他的例如在线服务的Pod走Kube-scheduler进行调度。

这种情况虽然能够有效的解决Coscheduling的问题,但是同样引入了新的问题。如大家所知,对于同一集群资源,调度器需要中心化。但如果同时存在两个调度器的话,有可能会出现决策冲突,例如分别将同一块资源分配给两个不同的Pod,导致某个Pod调度到节点后因为资源不足,导致无法创建的问题。解决的方式只能是通过标签的形式将节点强行的划分开来,或者部署多个集群。这种方式通过同一个Kubernetes集群来同时运行在线服务和离线作业,势必会导致整体集群资源的浪费以及运维成本的增加。

Scheduler Framework

上文中两难的处境,使得大量数据计算类的任务无法迁移到Kubernetes上。与此同时,越来越多的特性被添加到Kubernetes scheduler中,使得scheduler的代码不断变大,逻辑也更复杂。系统越复杂,则问题的定位和修复就越困难。同时原有通过extender的方式扩展scheduler的方式存在扩展点有限、无法与scheduler共用Cache以及性能较差等问题。

为了解决如上问题,使scheduler扩展性更好、代码更简洁,社区提出Scheduler Framework的机制。

Scheduler Framework定义了一组扩展点,用户可以通过实现扩展点所定义的接口来定制自己的插件,并且将插件注册扩展点。Scheduler Framework在执行调度流程时,运行到相应的扩展点时,将调用用户注册的插件。

5ce4b6a50297400388a1c574eecd6374.png

我们基于Kube-scheduler framework基础上扩展实现Coscheduling的能力,解决原生调度器对于All-or-Nothing作业调度的问题。

scheduler-plugins

Kubernetes负责Kube-scheduler的小组sig-scheduler为了更好的管理调度相关的Plugin,新建了项目scheduler-plugins管理不同场景的Plugin。我们实现的Coscheduling的Plugin将会成为该项目的第一个插件。目前Kep已经merge,代码在Review阶段(https://github.com/kubernetes-sigs/scheduler-plugins/pull/4)

技术方案

总体架构

70f3b96659d7b7abfebff19d6ee6219a.png

PodGroup

我们通过label的形式来定义PodGroup的概念,拥有同样label的Pod同属于一个PodGroup。min-available是用来标识该PodGroup的作业能够正式运行时所需要的最小副本数。

labels:
     pod-group.scheduling.sigs.k8s.io/name: nginx
     pod-group.scheduling.sigs.k8s.io/min-available: "2"

备注: 要求属于同一个PodGroup的Pod必须保持相同的优先级

Permit

Framework的Permit插件提供了延迟绑定的功能,即Pod进入到Permit阶段时,用户可以自定义条件来允许Pod通过、拒绝Pod通过以及让Pod等待状态(可设置超时时间)。Permit的延迟绑定的功能,刚好可以让属于同一个PodGruop的Pod调度到这个节点时,进行等待,等待积累的Pod数目满足足够的数目时,再统一运行同一个PodGruop的所有Pod进行绑定并创建。

举个实际的例子,当JobA调度时,需要4个Pod同时启动,才能正常运行。但此时集群仅能满足3个Pod创建,此时与Default Scheduler不同的是,并不是直接将3个Pod调度并创建。而是通过Framework的Permit机制进行等待。

8bb1e6e8487120259de158d7894b0667.png

此时当集群中有空闲资源被释放后,JobA的中Pod所需要的资源均可以满足。

2baf07ba046f3cf500bbb9108ede99ac.png

则JobA的4个Pod被一起调度创建出来,正常运行任务。

5f864bec0b6827252fb45a7dff129705.png

QueueSort

由于Default Scheduler的队列并不能感知PodGroup的信息,所以Pod在出队时处于无序性(针对PodGroup而言)。如下图所示,a和b表示两个不同的PodGroup,两个PodGroup的Pod在进入队列时,由于创建的时间交错导致在队列中以交错的顺序排列。

bf0350e5c47b8c80849b563a32c037a1.png

当一个新的Pod创建后,入队后,无法跟与其相同的PodGroup的Pod排列在一起,只能继续以混乱的形式交错排列。

47f27c8933d14ee55dbe2e93cde3a103.png

这种无序性就会导致如果PodGroupA在Permit阶段处于等待状态,此时PodGroupB的Pod调度完成后也处于等待状态,相互占有资源使得PodGroupA和PodGroupB均无法正常调度。这种情况即是把死锁现象出现的位置从Node节点移动到Permit阶段,无法解决前文提到的问题。

针对如上所示的问题,通过实现QueueSort插件, 保证在队列中属于同一个PodGroup的Pod能够排列在一起。我们通过定义QueueSort所用的Less方法,作用于Pod在入队后排队的顺序:

func  Less(podA *PodInfo, podB *PodInfo) bool

首先,继承了默认的基于优先级的比较方式,高优先级的Pod会排在低优先级的Pod之前。
然后,如果两个Pod的优先级相同,我们定义了新的排队逻辑来支持PodGroup的排序。

  1. 如果两个Pod都是regularPod(普通的Pod),则谁先创建谁在队列里边排在前边。
  2. 如果两个Pod一个是regularPod,另一个是pgPod(属于某个PodGroup的Pod), 我们比较的是regularPod的创建时间和pgPod所属PodGroup的创建时间,则谁先创建谁在队列里边排在前边。
  3. 如果两个Pod都是pgPod,我们比较两个PodGroup的创建时间,则谁先创建谁在队列里边排在前边。同时有可能两个PodGroup的创建时间相同,我们引入了自增Id,使得PodGroup的Id谁小谁排在前边(此处的目的是为了区分不同的PodGroup)。

通过如上的排队策略,我们实现属于同一个PodGroup的Pod能够同一个PodGroup的Pod能够排列在一起。

df7e1a6f74c31a72fb963ba70681b93f.png

当一个新的Pod创建后,入队后,会跟与其相同的PodGroup的Pod排列在一起。

7e3b1a5c8d7978fd4af34a4ce9657be7.png

Prefilter

为了减少无效的调度操作,提升调度的性能,我们在Prefilter阶段增加一个过滤条件,当一个Pod调度时,会计算该Pod所属PodGroup的Pod的Sum(包括Running状态的),如果Sum小于min-available时,则肯定无法满足min-available的要求,则直接在Prefilter阶段拒绝掉,不再进入调度的主流程。

UnReserve

如果某个Pod在Permit阶段等待超时了,则会进入到UnReserve阶段,我们会直接拒绝掉所有跟Pod属于同一个PodGroup的Pod,避免剩余的Pod进行长时间的无效等待。

Coscheduling试用

安装部署

前提条件

  1. 目前仅支持标准专有集群,不支持托管版集群
  2. 目前仅支持Kubernetes 1.16版本
  3. 集群节点可以访问公网
  4. helm v3:ACK在master节点上默认安装helm,请确认版本是否为helm v3,如果是helm v2请升级值helm v3,安装helm v3请参考helm v3 安装

部署Coscheduling

安装ack-coscheduling时,会用增强后的调度器替换原生的Scheduler以支持Coscheduling功能,并且会修改Scheduler的相关Config文件。用户可通过下文提示的卸载功能恢复集群及相关配置。

下载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

验证Coscheduling

在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
通过helm卸载服务,将kube-scheduler的版本及配置回归到安装之前的状态

# helm uninstall ack-coscheduling -n kube-system

使用方式

使用Coscheduling时,在创建的Pod处通过label的形式配置好min-available和name

labels:
    pod-group.scheduling.sigs.k8s.io/name: nginx
    pod-group.scheduling.sigs.k8s.io/min-available: "3"

name:用于表示PodGroup的Name

min-available: 用于表示当前集群资源至少满足min-available个pod时,才能统一调度创建

备注: 要求属于同一个PodGroup的Pod必须保持相同的优先级

Demo展示

当前集群资源为10核, 仅足够满足如下3个Nginx pod运行,我们把minAvailable的值设置为3

apiVersion: apps/v1
kind: ReplicaSet
metadata:
  name: nginx
  labels:
    app: nginx
spec:
  replicas: 6
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      name: nginx
      labels:
        app: nginx
        pod-group.scheduling.sigs.k8s.io/name: nginx
        pod-group.scheduling.sigs.k8s.io/min-available: "3"
    spec:
      containers:
      - name: nginx
        image: nginx
        resources:
          limits:
            cpu: 3000m
            memory: 500Mi
          requests:
            cpu: 3000m
            memory: 500Mi

集群中运行3个Nginx Pod

# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-4jw2m   0/1     Pending   0          55s
nginx-4mn52   1/1     Running   0          55s
nginx-c9gv8   1/1     Running   0          55s
nginx-frm24   0/1     Pending   0          55s
nginx-hsflk   0/1     Pending   0          55s
nginx-qtj5f   1/1     Running   0          55s

如果此时minAvailable设置为4,则因为资源不满足minAvailable的要求,所有的Nginx Pod均处于Pending状态

# kubectl get pods
NAME          READY   STATUS    RESTARTS   AGE
nginx-4vqrk   0/1     Pending   0          3s
nginx-bw9nn   0/1     Pending   0          3s
nginx-gnjsv   0/1     Pending   0          3s
nginx-hqhhz   0/1     Pending   0          3s
nginx-n47r7   0/1     Pending   0          3s
nginx-n7vtq   0/1     Pending   0          3s

未来展望

通过Scheduler Framework的不断优化,我们相信未来会释放更大的潜力,用户可以通过插件的扩展就可以满足自身的需求,再也不用陷入自定义调度器的困境中。同时为了更好的支持数据计算类型的任务迁移到Kubernetes平台中,我们也在努力将数据计算类型中常用Capacity Scheduling、Dominant Resource Fairness和多队列管理等特性,通过Scheduler Framework的机制来融入到原生的Kube-scheduler的中,敬请期待。

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
3月前
|
运维 Kubernetes Cloud Native
OpenKruise是一个基于Kubernetes的扩展套件
OpenKruise是一个基于Kubernetes的扩展套件【1月更文挑战第14天】【1月更文挑战第68篇】
19 2
|
4月前
|
Kubernetes 负载均衡 Cloud Native
猿创征文|云原生|kubernetes二进制1.18单master扩展为多master
猿创征文|云原生|kubernetes二进制1.18单master扩展为多master
54 0
|
弹性计算 Kubernetes 安全
在K8S上部署可扩展的基于Occlum的安全推理实例
机密计算是指通过在基于硬件的可信执行环境(TEE)中执行计算来保护数据应用中的隐私安全,是目前最火热的隐私保护技术之一。在云上运行TEE应用也得到了云厂商的广泛支持,包括阿里云,微软Azure云,都提供了基于SGX技术的机密安全实例服务。用户可以在这些云上申请带SGX支持的安全实例,然后部署自己的机密安全服务,既可以避免隐私数据泄露,也无需操心繁琐的基础架构层的配置。无论哪种云,最流行的分布式部署
在K8S上部署可扩展的基于Occlum的安全推理实例
|
27天前
|
Kubernetes API 调度
总结归纳Kubernetes | 一站式速查知识,助您轻松驾驭容器编排技术(水平扩展控制)
总结归纳Kubernetes | 一站式速查知识,助您轻松驾驭容器编排技术(水平扩展控制)
60 0
|
1月前
|
Kubernetes 监控 调度
|
2月前
|
监控 关系型数据库 MySQL
利用容器编排工具实现员工电脑监控软件系统的横向扩展
随着企业规模的不断扩大,员工电脑监控软件系统的横向扩展成为一项迫切的需求。为了更有效地管理和监控员工的工作环境,容器编排工具的运用成为一种值得考虑的解决方案。在本文中,我们将探讨如何利用容器编排工具实现监控软件系统的横向扩展,并通过一些实际的代码示例来说明。
184 0
|
5月前
|
Kubernetes Cloud Native 测试技术
在云计算平台上部署Kubernetes:无缝管理和弹性扩展
Kubernetes已成为云计算平台上部署和管理容器化应用程序的首选解决方案。无论您选择使用Google Cloud Platform(GCP)、Amazon Web Services(AWS)、Microsoft Azure或其他云计算提供商,Kubernetes都为您提供了一种灵活、可移植且可扩展的方式来管理容器化应用程序。本文将深入探讨如何在云计算平台上部署Kubernetes,并为您提供一些实际的示例。
|
8月前
|
存储 Kubernetes Cloud Native
全面掌握 Kubernetes:部署、管理和扩展云原生应用
Kubernetes 是一个强大的云原生应用部署、管理和扩展平台,提供了丰富的功能和工具。通过本文的介绍,您应该能够了解 Kubernetes 的基本概念、核心组件,以及如何使用 Kubernetes 部署、管理和扩展云原生应用。同时,了解到 Kubernetes Dashboard 作为一个图形化工具,可以更方便地管理集群中的资源和应用程序。在实际应用中,深入学习和实践 Kubernetes 将有助于更好地掌握云原生应用的部署和管理。
189 1
全面掌握 Kubernetes:部署、管理和扩展云原生应用
|
9月前
|
运维 负载均衡 Kubernetes
基于 Stork 和 Quarkus 扩展 Kubernetes 服务发现
在传统的单体架构中,应用程序已经通过静态主机名、IP 地址和端口知道后端服务的存在位置。IT运维团队为服务可靠性和系统稳定性维护静态配置。自从微服务开始在分布式网络系统中运行以来,其维护发生了显著变化。之所以发生这种变化,是因为微服务需要与多个后端服务进行通信,以提高负载均衡和服务弹性。
84 0
|
10月前
|
Kubernetes 应用服务中间件 nginx
【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新(下)
【探索 Kubernetes|作业管理 Deployment 篇 系列 12】水平扩展 / 收缩、滚动 / 回滚更新(下)
122 0