前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >K8s调度框架引入PreEnqueue设计

K8s调度框架引入PreEnqueue设计

作者头像
zouyee
发布2022-05-25 10:08:41
4160
发布2022-05-25 10:08:41
举报
文章被收录于专栏:Kubernetes GO

去年zouyee为大家带来《kubernetes调度系统系列文章》, 近期看到社区在调度方面的一些有趣的设计文档,分享给各位。

文|Wei Huang, Yuan Chen, Yibo Zhuang

编辑|zouyee

提案阶段|评审

在Kubernetes调度器框架中提供一个PreEnqueue 钩子,使插件能够在将Pod添加到调度器的内部活动队列之前运行自定义逻辑。如果该插件返回false,则调度器不会将该Pod入队。

需求说明

当前Kubernetes调度器无条件地将待调度的Pod(即spec.nodeName为空)添加到调度队列中。在Pod入队前,插件无法得知,同样也不能决定Pod是否应该入队。

PreEnqueue钩子的缺失将导致工作负载的生命周期管理的不完善,并且也会因无需调度的Pod扰动调度器的内部队列。例如,一些Pod在创建时可能还没有准备好立即被调度,控制器可能有定制的逻辑来决策Pod的Ready时机,并更新它们。因此,让 unready的Pod入队是不可取的,其浪费了宝贵的调度时间。另外,如果一个 unready的Pod被过早的调度,并在事后被抢占,这将浪费集群资源。此外,PreEnqueue钩子可以作为一种信息传输的途径,使插件能够实现更为精准的QueueSort计算,以及更高级的调度举措。

注意:这里unready Pod是指没有准备好立即被调度的Pod

使用场景

  • Spot instance:只有在集群有富余的可用资源或集群当前利用率较低时,Spot instance pod才会被调度。
  • 有状态的工作负载:使用PersistentVolume的pod先不入队,直到PVC已经成功绑定到PV(在PVC即时绑定模式下)。
  • 无效的secrets/configmaps:pod中指定的secrets/configmaps不存在或无效时不入队。目前,此类pod将被调度,可能抢占其他pod,但在容器启动时因此而失败。

目标提出一个扩展方式,以针对即将入队的Pod执行自定义逻辑。非目标管理未被插件PreEnqueue处理的已调度Pod。

用户画像

  • 作为一个集群容量规划者,想控制Pod的入队速度。例如,具体的逻辑可能取决于一些SLO相关的指标,如调度队列的饱和度,集群的整体利用率,或特定的业务需求。
  • 作为一个插件的开发者,想在Pod入队(进入activeQ)时得到简单的通知,这样就可以在之后的其他插件中利用自定义逻辑。

方案设计

API设计

核心逻辑是为插件开发者提供一个无状态且不可变的PreEnqueue钩子,它被注册在内部调度器activeQ中,在指定的Pod入队之前被调用。

实现方式 1. 添加一个新的插件EnqueuePlugin

在该设计中,引入了一个新的插件,叫做EnqueuePlugin。该插件中Admit()方法可以根据定制的配置文件,以判定一个pod准入/拒入activeQ。

注意:如非目标部分所述,如果Admin()返回错误,则需要由插件开发者来实现重新入队的逻辑。例如,更新Pod的spec/annotation,以便调度器的Pod处理程序会自动触发入队。

代码语言:javascript
复制
type EnqueuePlugin interface {
  Plugin
  // Admit is invoked every time a Pod is about to be added to activeQ.
  // The given Pod won't be enqueued if a `false` value is returned.
  Admit(*QueuedPodInfo) bool
}

优点:自定义入队逻辑通过新的扩展点被隔离出来,从而与其他插件实现隔离。对那些不关心此功能的调度器插件没有任何影响。

缺点:对API(KubeSchedulerConfiguration)和代码有较大改动。

实现方式2. 在EnqueueExtensions接口中添加Admit()

在这个方式中,Admit()并不会与一个新的插件产生关联。相反,它拓展了现有的EnqueueExtensions接口。

代码语言:javascript
复制
type EnqueueExtensions interface {
  // EventsToRegister returns a series of possible events that may cause a Pod
  // failed by this plugin schedulable.
  // The events will be registered when instantiating the internal scheduling queue,
  // and leveraged to build event handlers dynamically.
  // Note: the returned list needs to be static (not depend on configuration parameters);
  // otherwise it would lead to undefined behavior.
  EventsToRegister() []ClusterEvent
  // Admit is invoked every time a Pod is about to be added to activeQ.
  // The given Pod won't be enqueued if a `false` value is returned.
  Admit(*QueuedPodInfo) bool
}

优点:API上没有变化。(EnqueueExtensions更像是一个SDK,由插件开发者使用,而不是SRE/Devops等最终用户使用)

缺点:EnqueueExtensions是一个可选的接口,它需要成为具体插件的一部分。这意味着如果只想实现Admit()方法,仍然需要实现一个(无实际意义)的插件来与之关联。当前实现EnqueueExtension接口的插件需要被修改以实现Admit(),当然可以通过植入一个 AlwaysAdmit函数以复用。

实现

无论选择哪种方式,Admit()都可以在NewFramework()处构建SchedulerProfile后获得,最终传递给internalqueue.NewSchedulingQueue。

将引入一个新的结构体,叫做activeQ,其中包含heap.Heap和一个map,其映射关系为{profileName: admitFn}。

代码语言:javascript
复制
type activeQ struct {
  heap.Heap
  // Keyed with profile name, valued with AdminFunc
  admitFuncMap map[string]framework.AdminFunc
}

func (aq *activeQ) Add(qInfo *framework.QueuedPodInfo) error {
  if fn, ok := aq.admitFuncMap[qInfo.Pod.Spec.SchedulerName]; !ok || !fn(qInfo) {
    return nil
  }
  return aq.Heap.Add(qInfo)
}

有了这个结构体,能够确保原先调用activeQ.XYZ()逻辑保持不变。

由于笔者时间、视野、认知有限,本文难免出现错误、疏漏等问题,期待各位读者朋友、业界专家指正交流。

参考文献

1.https://github.com/kubernetes/kubernetes/issues/93591

2.https://github.com/kubernetes/kubernetes/issues/102271

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-05-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 DCOS 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 需求说明
  • 方案设计
  • 实现
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档