带你畅游 Kubernetes 调度器

标签: k8s  kubernetes  docker  容器

在这里插入图片描述

kubernetes 调度器,通过 watch 机制来发现集群中新创建且未调度的 pod,通过过滤 node 列表,打分策略,以及各个时机的插件调用机制,选择合适的 node 与之绑定。

一、调度队列

同一时刻会有多个 pod 等待调度,会把等待调度的 pod 放到 activeQ 中(PriorityQueue),然后周期性(1s)的进行调度,对于调度超时( DefaultPodMaxInUnschedulablePodsDuration 5m)会放入队列中,再次重新调度。

二、单次调度

用下图来说明单个调度的流转逻辑。

注意:一个集群中可以有多个调度器,所以首先需要根据 pod 中的 spec 参数获取调度器名称

跳过 pod:skipPodSchedule, 过滤调不需要调度的 pod,比如正在删除中的 pod,上个调度周期正在处理中的 pod

筛选 pod:SchedulePod,计算并预选出适合的 node

如果筛选失败,则调用 RunPostFilterPlugins; 如果筛选成功,则调用插件:RunXXXPlugins,开始调用配置的插件列表,从 Reserve 插件到 MultiPoint 依次按照埋点调用。

对于大规模集群,单此调度要遍历所有的 node 么?这是一个值得思考的问题。默认调度器给出的答案是根据集群规模自适应调度数量。

  • 对于小规模集群,node 数小于 100, 遍历所有 node。

  • 对于大规模集群,node 数大于 100,且配置的百分比小于 100% 时:按照 node 数量的一定百分比遍历,区间范围是 [5,100]。

  • 计算公式是

prePercent:=50-numAllNodes/125

percent:=max(5,prePercent)

三、调度过程

调度过程分为 3 个步骤:过滤,打分,筛选,代码步骤如下:

省略非必要代码

// node快照
  if err := sched.Cache.UpdateSnapshot(sched.nodeInfoSnapshot); err != nil {
    return result, err
  }
  
    // 过滤
  feasibleNodes, diagnosis, err := sched.findNodesThatFitPod(ctx, fwk, state, pod)
  if err != nil {
    return result, err
  }
    
    // 打分
  priorityList, err := prioritizeNodes(ctx, sched.Extenders, fwk, state, pod, feasibleNodes)
  if err != nil {
    return result, err
  }
    
    // 随机筛选
  host, err := selectHost(priorityList)

(一)过滤

可用的 node 列表:

  • 插件过滤:RunPreFilterPlugins 如果插件执行失败,那么返回所有 node 可用,如果插件返回不可调度,则返回失败,终止本次调度。

  • 获取 node allNodes,err:=sched.nodeInfoSnapshot.NodeInfos(). 列表()

  • 抢占式 pod 的 status 字段中 NominatedNodeName 设置后,会优先抢占同名的 node。

  • allNode 和 preFilter 返回的 node 求交集。

(二)打分

根据优先级选择合适的 node 列表:prioritizeNodes

  • 如果没有开启打分插件,返回所有 node list。

  • 打分插件逐次调用 RunPreScorePlugins–>RunScorePlugins

(三)筛选

相同优先级列表下,获取 score 最大值的 node,如果存在多个相同分数,则随机一个。

四、插件机制

插件分为了调度和绑定两大类,划分成了多个时机调用,如下图:

(一)插件类型

对于 pod 的调度过程,划分了多个点,每个点调用对应的插件列表,目前支持如下多种类型插件:

// QueueSort is a list of plugins that should be invoked when sorting pods in the scheduling queue.
QueueSort PluginSet `json:"queueSort,omitempty"`

// PreFilter is a list of plugins that should be invoked at "PreFilter" extension point of the scheduling framework.
PreFilter PluginSet `json:"preFilter,omitempty"`

// Filter is a list of plugins that should be invoked when filtering out nodes that cannot run the Pod.
Filter PluginSet `json:"filter,omitempty"`

// PostFilter is a list of plugins that are invoked after filtering phase, but only when no feasible nodes were found for the pod.
PostFilter PluginSet `json:"postFilter,omitempty"`

// PreScore is a list of plugins that are invoked before scoring.
PreScore PluginSet `json:"preScore,omitempty"`

// Score is a list of plugins that should be invoked when ranking nodes that have passed the filtering phase.
Score PluginSet `json:"score,omitempty"`

// Reserve is a list of plugins invoked when reserving/unreserving resources
// after a node is assigned to run the pod.
Reserve PluginSet `json:"reserve,omitempty"`

// Permit is a list of plugins that control binding of a Pod. These plugins can prevent or delay binding of a Pod.
Permit PluginSet `json:"permit,omitempty"`

// PreBind is a list of plugins that should be invoked before a pod is bound.
PreBind PluginSet `json:"preBind,omitempty"`

// Bind is a list of plugins that should be invoked at "Bind" extension point of the scheduling framework.
// The scheduler call these plugins in order. Scheduler skips the rest of these plugins as soon as one returns success.
Bind PluginSet `json:"bind,omitempty"`

// PostBind is a list of plugins that should be invoked after a pod is successfully bound.
PostBind PluginSet `json:"postBind,omitempty"`

// MultiPoint is a simplified config section to enable plugins for all valid extension points.
MultiPoint PluginSet `json:"multiPoint,omitempty"`

(二)插件列表

默认调度器,实现了多种插件不用特性的插件,目前支持的列表如下, 下面举几个例子说明。

"PrioritySort" : 
"DefaultBinder"
"DefaultPreemption"
"ImageLocality"
"InterPodAffinity"
"NodeAffinity"
"NodeName"
"NodePorts"
"NodeResourcesBalancedAllocation"
"NodeResourcesFit"
"NodeUnschedulable"
"NodeVolumeLimits"
"AzureDiskLimits"
"CinderLimits"
"EBSLimits"
"GCEPDLimits"
"PodTopologySpread"
"SelectorSpread"
"ServiceAffinity"
"TaintToleration"
"VolumeBinding"
"VolumeRestrictions"
"VolumeZone"

对于打分插件,必须实现如下接口,且每个插件打分范围是 [0, 100]

type ScorePlugin interface {
  Plugin
  // Score is called on each filtered node. It must return success and an integer
  // indicating the rank of the node. All scoring plugins must return success or
  // the pod will be rejected.
  Score(ctx context.Context, state *CycleState, p *v1.Pod, nodeName string) (int64, *Status)

  // ScoreExtensions returns a ScoreExtensions interface if it implements one, or nil if does not.
  ScoreExtensions() ScoreExtensions
}

(三)插件特性

  • 图像定位

ImageLocality:本地镜像打分插件,计算分数规则如下:

sumScore:=(拥有镜像的 node 数 / node 总数)* 镜像大小

得分:= (总和分数容器数 - 23mb)/(1000mb 3-23mb)

注意:这里不是指单个 containner,而是一个 pod 中的所有 container 的打分之和。为什么范围是 23mb 到 1000mb?可以想一想。

  • 节点关联

NodeAffinity:node 亲和性和反亲和性,提供了两种策略配置。

  • 对于必选策略 RequiredDuringSchedulingIgnoredDuringExecution,如果匹配未成功,则在 PreFilter 阶段返回失败,终止调度。

  • 对于首先策略 PreferredDuringSchedulingIgnoredDuringExecution,如果匹配未成功,则尝试其他 node 也失败,调度器仍然会调度改 pod。亲和性,反亲和性是用来影响打分数值(正负分)weight

逻辑代码如下:

// 亲和性,反亲和性判定判定
if hasPreferredAffinityConstraints || hasPreferredAntiAffinityConstraints {
    for _, existingPod := range podsToProcess {
      pl.processExistingPod(state, existingPod, nodeInfo, pod, topoScore)
    }
    
  topoScores[atomic.AddInt32(&index, 1)] = topoScore
}

比如我们业务逻辑中的配置如下图,期望是一个 node 上只调度一个这种 pod,但是配置了首选策略。所以当 node 数小于 pod 数时,是会出现一个 node 上有多个此类 pod,会有一定的影响。

  • 污点耐受

TaintToleration:污点插件,提供了过滤,预打分,打分,打分标准化(平行扩展到 0 到 100)接口。

污点标记提供了 3 种类型

// 尽可能不调度
  TaintEffectPreferNoSchedule TaintEffect = "PreferNoSchedule"    
  
  // 一定不调度
  TaintEffectNoSchedule TaintEffect = "NoSchedule"
  
  // 一定不调度且驱逐
  TaintEffectNoExecute TaintEffect = "NoExecute"

比如我们业务中打了污点,那么一般 pod 是不会调度到此 pod 上的。

五、调度器配置

一般情况下,scheduler 会起多副本进行容灾。

{
      "name": "BalancedResourceAllocation",
      "weight": 1
    },
    {
      "name": "EvenPodsSpreadPriority",
      "weight": 1
    },
    {
      "name": "InterPodAffinityPriority",
      "weight": 1
    },
    {
      "name": "LeastRequestedPriority",
      "weight": 1
    },
    {
      "name": "NodeAffinityPriority",
      "weight": 1
    },
    {
      "name": "NodePreferAvoidPodsPriority",
      "weight": 10000
    },
    {
      "name": "SelectorSpreadPriority",
      "weight": 1
    },
    {
      "name": "TaintTolerationPriority",
      "weight": 1
    }

六、如何自定义 pod 调度

目前有 2 种常用方法:

(一)扩展模式

实现 type Extender struct 接口,并且在策略文件 scheduler-policy-config 中配置扩展访问方式

"extenders": [{
    "urlPrefix": "http://xxx/prefix",
    "filterVerb": "filter",
    "weight": 1,
    "bindVerb": "bind",
    "enableHttps": false
}]

(二)多调度器

在需要自定义调度的 pod 中,指定 pod 的 spec.schedulerName 为自定义的调度器名称。实现自定义调度器。部署自定义的调度器 deployment。

在新版本 1.19 之后建议扩展自定义调度框架,如下例:

import (
    scheduler "k8s.io/kubernetes/cmd/kube-scheduler/app"
)

func main() {
    command := scheduler.NewSchedulerCommand(
            scheduler.WithPlugin("my-plugin", MyPlugin))
    if err := command.Execute(); err != nil {
        fmt.Fprintf(os.Stderr, "%v\n", err)
    }
}

七、总结

在深入 schedule 源码之后,对于调度器有了剖丝抽茧的理解,了解背后的设计初衷。对于高性能,提供了自适应集群规模的调度策略。对于可靠性,kube-scheduler 提供了多副本选主机制,由 master 提供调度功能。对于扩展性,它提供了丰富的扩展接口和时机用,且提供了灵活而实用插件策略配置。

版权声明:本文为agonie201218原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/agonie201218/article/details/126359881

智能推荐

图解kubernetes调度器SchedulingQueue核心源码实现

SchedulingQueue是kubernetes scheduler中负责进行等待调度pod存储的对,Scheduler通过SchedulingQueue来获取当前系统中等待调度的Pod,本文主要讨论SchedulingQueue的设计与实现的各种实现, 了解探究其内部实现与底层源码,本系列代码基于kubernets1.1.6分析而来,图解主要位于第二部分 SchedulingQueue设计 ...

图解kubernetes调度器预选设计实现学习

Scheduler中在进行node选举的时候会首先进行一轮预选流程,即从当前集群中选择一批node节点,本文主要分析k8s在预选流程上一些优秀的筛选设计思想,欢迎大佬们指正 1. 基础设计 1.1 预选场景 预选顾名思义就是从当前集群中的所有的node中,选择出满足当前pod资源和亲和性等需求的node节点,如何在集群中快速选择这样的节点,是个复杂的问题 1.2 平均分布 平均分布主要是通过让一个...

新发的日常小实验——使用IETester测试不同IE版本的浏览器,测试网页JS的兼容性(console未定义兼容测试)

文章目录 一、痛点:IE兼容测试 二、关于IETester 三、IETester下载 四、写个html测试js的console接口 五、测试结果 六、js兼容处理 一、痛点:IE兼容测试 之前使用.Net的Winform桌面应用框架做了一个PC版的迷你浏览器(使用IE内核),方便拉起网页支付。 有用户反馈打开支付页面报了如下的错:“console”未定义 到底是多么老旧的I...

linux下搭建nginx及配置

文章目录 下载nginx 解压nginx资源包 准备编译环境 安装编译 查找安装路径并启动nginx 浏览器访问 下载nginx 下载地址:https://nginx.org/en/download.html 这里用的是nginx-1.16.1版本 解压nginx资源包 准备编译环境 安装编译 查找安装路径并启动nginx 浏览器访问 http://IP...

猜你喜欢

腾讯云+tipask快速搭建基于laravel的CMS网站

一、购买腾讯云服务器,服务市场->基础环境->选择WordPress平台镜像 二、按照tipask教程安装 tipask官方教程地址https://wenda.tipask.com/article/22 官方教程对新手不太友好,我整理如下: 1.ftp上传文件 云服务器镜像装载完毕后,浏览器访问服务器公网ip,点击获取权限后会下载服务器相关的文件 浏览器访问host url,根据所给的...

ElasticSearch入门教程

什么是ElasticSearch 基于Apache Lucene构建的开源搜索引擎 采用Java编写,提供简单易用的RESTFul API 轻松的横向扩展,可支持BP级的结构化和非结构化的数据处理 可应用场景 海量数据分析引擎 站内搜索引擎 数据仓库 一线公司实际应用场景 英国卫报 - 实时分析公众对文章的回应 维基百科、GitHub-站内实时搜索 百度 - 实时日志监控平台 安装 Windows...

小程序明明已经分包了,为啥没有大小没有变???

为什么要分包 真机预览时出现大于2M,无法预览。 对项目进行规整划分 如何分包 实际操作 先将需要分包的文件拷贝到小程序根目录下 在app.json中配置分包结构(如图) 修改被分包中的引用路径,如图片资源、导航URL 可以设置分包的在哪个页面加载 图中表示在进入login页面进行下载设置的分包,all表示在所有网络下。 失败解决!分包了为啥还是提示大小超过2M 分包的文件内所引用的外部文件也必须...

js pixi框架 极其详细到位(入门)-----转载

pixi是一个js 的轻量级的游戏类库框架,很适用于做H5的一些canvas动画特效。 这篇文章是关于pixi的入门教程 ,里面的讲解非常的到位细致,是我看到过的文章里讲解的算是最好的了。  去年快过年看的教程 ,今天再想看的时候发现没找到,不过经过不懈的搜索还是找到 ,那就赶紧给转过来吧。   pixi(入门) Pixi教程 基于官方教程翻译;水平有限,如有错误欢迎提PR,转...

sklearn支持向量机(SVM)多分类问题

模型 sklearn.svm中的支持向量机: Classify:SVC、nuSVC、LinearSVC Regression:SVR、nuSVR、LinearSVR OneClassSVM 本文采用Classify系列,classify三个模型的区别;参数详解 预处理 建模 训练 多种SVC、核函数对比 对比的结果: 优化linear核函数的SVC的惩罚系数 惩罚系数(C=)越高,对错误分类的惩罚...


http://www.vxiaotou.com