105 - kube-scheduler源码分析 - predicate算法注册 go 第1张

一、predicate注册过程 

今天我们来聊聊predicate函数是怎么被注册进去的,也就是要执行的一堆predicate是怎么成为“选中的孩子”。  代码位置:pkg/scheduler/factory/plugins.go:111 105 - kube-scheduler源码分析 - predicate算法注册 go 第2张 105 - kube-scheduler源码分析 - predicate算法注册 go 第3张 这个函数注册一个predicate函数,返回predicate名。   第二个参数: type FitPredicate func(pod *v1.Pod, meta PredicateMetadata, nodeInfo *schedulercache.NodeInfo) (bool, []PredicateFailureReason, error)   这个函数(RegisterFitPredicate)的被调用场景如下,第一个参数是一个字符串常量,第二个参数是一个函数类型 105 - kube-scheduler源码分析 - predicate算法注册 go 第4张 105 - kube-scheduler源码分析 - predicate算法注册 go 第5张 RegisterFitPredicate的2个参数其实长这个样子,如下: 105 - kube-scheduler源码分析 - predicate算法注册 go 第6张 105 - kube-scheduler源码分析 - predicate算法注册 go 第7张   105 - kube-scheduler源码分析 - predicate算法注册 go 第8张 105 - kube-scheduler源码分析 - predicate算法注册 go 第9张   RegisterFitPredicate中调用的是RegisterFitPredicateFactory完成注册逻辑,RegisterFitPredicateFactory定义如下: 105 - kube-scheduler源码分析 - predicate算法注册 go 第10张 105 - kube-scheduler源码分析 - predicate算法注册 go 第11张 这个函数的参数是:
  • name string
  • predicateFactory FitPredicateFactory
返回值是:
  • string
  其中FitPredicateFactory是一个函数类型,签名是: func(PluginFactoryArgs) algorithm.FitPredicate   PluginFactoryArgs是一堆factory函数: 105 - kube-scheduler源码分析 - predicate算法注册 go 第12张 105 - kube-scheduler源码分析 - predicate算法注册 go 第13张   RegisterFitPredicateFactory的第二个参数比较复杂,是一个函数类型,这个类型的参数在RegisterFitPredicate中的实参用了: func(PluginFactoryArgs) algorithm.FitPredicate { return predicate } 这个地方相比上面的类型定义只多了“{ return predicate }”,也就是加了一个函数体,函数体里只有一个return,好理解,也就是一个匿名函数。   RegisterFitPredicateFactory中除了锁操作外只有2行: 105 - kube-scheduler源码分析 - predicate算法注册 go 第14张 105 - kube-scheduler源码分析 - predicate算法注册 go 第15张
  • 第一行:正则匹配判断name是否合法,规则是: "^[a-zA-Z0-9]([-a-zA-Z0-9]*[a-zA-Z0-9])$"
  • 第二行:fitPredicateMap的类型是map[string]FitPredicateFactory,一个包级变量;也就是把predicate的名字当做key,把一个以PluginFactoryArgs为参数,algorithm.FitPredicate为返回值的函数当做value.
  也就是说RegisterFitPredicateFactory函数是把predicate函数注册到包(factory)级别的fitPredicateMap中;换言之开头提到的RegisterFitPredicate函数最终是把predicate注册到factory.fitPredicateMap   到这里可能还不太理解PluginFactoryArgs的作用,但是我们关注到RegisterFitPredicate的输入值是predicate的名字和具体的实现函数,结果是fitPredicateMap这个map里加了一个元素,key是predicate名,value是一个FitPredicateFactory类型数据,这个类型是一个func,这个func定义是:func(PluginFactoryArgs) algorithm.FitPredicate,也就是给一个PluginFactoryArgs就可以返回一个具体的predicate function.后面我们对照具体使用PluginFactoryArgs的地方再来理解它的实际含义。  

二、ApplyFeatureGates入口

cmd/kube-scheduler/app/server.go:297 Run()这个函数中有这样一步: 105 - kube-scheduler源码分析 - predicate算法注册 go 第16张 105 - kube-scheduler源码分析 - predicate算法注册 go 第17张 这个Run是在最开头的地方被调用的,如下位置: 105 - kube-scheduler源码分析 - predicate算法注册 go 第18张 105 - kube-scheduler源码分析 - predicate算法注册 go 第19张 ApplyFeatureGates函数的定义如下: 105 - kube-scheduler源码分析 - predicate算法注册 go 第20张 105 - kube-scheduler源码分析 - predicate算法注册 go 第21张 这里调用的ApplyFeatureGates的位置是: pkg/scheduler/algorithmprovider/defaults/defaults.go:180 这个go文件在defaults包下,这个包内包含这些东西: 105 - kube-scheduler源码分析 - predicate算法注册 go 第22张 105 - kube-scheduler源码分析 - predicate算法注册 go 第23张 这里的函数基本都是小写字母开头的,换言之都是包内访问的。另外有一个init()函数,这里的逻辑在调用ApplyFeatureGates()函数之前执行。所以下面看一下defaults包。  

三、defaults包

pkg\scheduler\algorithmprovider\defaults\defaults.go中的init()函数 init()函数前面调用了registerAlgorithmProvider函数,参数是defaultPredicates()和defaultPriorities(),明显是注册默认的predicates和priorities.我们先关注predicate默认有哪些 (pkg/scheduler/algorithmprovider/defaults/defaults.go:112): 105 - kube-scheduler源码分析 - predicate算法注册 go 第24张 105 - kube-scheduler源码分析 - predicate算法注册 go 第25张 这里用紫色的常量名来统计有12个:
  1. NoVolumeZoneConflictPred
  2. MaxEBSVolumeCountPred
  3. MaxGCEPDVolumeCountPred
  4. MaxAzureDiskVolumeCountPred
  5. MatchInterPodAffinityPred
  6. NoDiskConflictPred
  7. GeneralPred
  8. CheckNodeMemoryPressurePred
  9. CheckNodeDiskPressurePred
  10. CheckNodeConditionPred
  11. PodToleratesNodeTaintsPred
  12. CheckVolumeBindingPred
init()函数中接着注册了4个predicate(name->func):
  1. PodFitsHostPorts -> predicates.PodFitsHostPorts
  2. PodFitsResources -> predicates.PodFitsResources
  3. HostName -> predicates.PodFitsHost
  4. MatchNodeSelector -> predicates.PodMatchNodeSelector
然后注册一个获取等价pod的函数: 105 - kube-scheduler源码分析 - predicate算法注册 go 第26张 105 - kube-scheduler源码分析 - predicate算法注册 go 第27张 函数名很直观:RegisterGetEquivalencePodFunction;这个函数的参数是一个匿名函数,匿名函数的参数前面见过很多次了,先关注一下返回值是什么:algorithm.GetEquivalencePodFunc;这个类型其实也是一个函数类型,签名是:func(pod *v1.Pod) interface{},也就是以pod信息为参数,返回任意类型。接着看一下前面这个匿名函数的return部分写的是什么:predicates.NewEquivalencePodGenerator(args.PVCInfo) 105 - kube-scheduler源码分析 - predicate算法注册 go 第28张 105 - kube-scheduler源码分析 - predicate算法注册 go 第29张 这里的g是这样定义的: 105 - kube-scheduler源码分析 - predicate算法注册 go 第30张 105 - kube-scheduler源码分析 - predicate算法注册 go 第31张 return部分调用了一个方法,这个方法长这个样子: 105 - kube-scheduler源码分析 - predicate算法注册 go 第32张 105 - kube-scheduler源码分析 - predicate算法注册 go 第33张 这个方法返回一个EquivalencePod,也就是等价pod,定义如下: 105 - kube-scheduler源码分析 - predicate算法注册 go 第34张 105 - kube-scheduler源码分析 - predicate算法注册 go 第35张 这个OwnerReference包含判断一个资源身份所需要的足够的信息: 105 - kube-scheduler源码分析 - predicate算法注册 go 第36张 105 - kube-scheduler源码分析 - predicate算法注册 go 第37张 RegisterGetEquivalencePodFunction函数在注册的时候把传进来的匿名函数注册到了哪里呢? 105 - kube-scheduler源码分析 - predicate算法注册 go 第38张 105 - kube-scheduler源码分析 - predicate算法注册 go 第39张 这里的getEquivalencePodFuncFactory明显又是一个包级变量,定义位置是:pkg/scheduler/factory/plugins.go:95. 所以总结下来就是说init()中的factory.RegisterGetEquivalencePodFunction函数把一个获取等价pod的函数注册到了factory包的包级变量getEquivalencePodFuncFactory中 再看defaults.go中唯一一个可导出函数ApplyFeatureGates; 105 - kube-scheduler源码分析 - predicate算法注册 go 第40张 105 - kube-scheduler源码分析 - predicate算法注册 go 第41张 这个函数在TaintNodesByCondition特性打开的情况下调整了几个predicate,特性的定义跟进去可以看到(pkg/features/kube_features.go:140): 105 - kube-scheduler源码分析 - predicate算法注册 go 第42张 105 - kube-scheduler源码分析 - predicate算法注册 go 第43张 这里的Feature类型其实很简单,跟一下可以看到这一行定义:type Feature string.可以发现这里定义了很多的alpha或者beta的特性,明显这里是做了开关,各种未稳定发布的特性可以选择性放出来。其实在scheduler组件启动的时候有一个命令行参数是:--feature-gates=...,TaintNodesByCondition=true,也就是可以通过这种方式打开一个feature.特性开关的事情后面再详细介绍,关于predicate算法注册的内容今天就讲到这里! 105 - kube-scheduler源码分析 - predicate算法注册 go 第44张

 

 

 

SRE实战 互联网时代守护先锋,助力企业售后服务体系运筹帷幄!一键直达领取阿里云限量特价优惠。

扫码关注我们
微信号:SRE实战
拒绝背锅 运筹帷幄