基于kubernetes调度框架的自定义调度器实现-优化篇

发布时间:2022-06-27 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了基于kubernetes调度框架的自定义调度器实现-优化篇脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。

目录
  • 简介
  • framework.Handle
  • kubectl top
  • 实现

简介

上一篇中实现了一个kubernetes调度框架的调度插件。虽然功能已经可用,但是其核心打分阶段使用了裸奔的http库直接去请求prometheus api,没有充分地利用kubernetes集群的能力,稍显笨拙。本文在上篇所实现的调度插件基础上,探索利用kubernetes原生能力获取节点内存用量,优化调度插件。

framework.Handle

首先查看一下默认调度器插件,观察它们是如何获取集群资信息的。比如在pkg/scheduler/framework/plugins/nodevolumelimITs/csi.go中,可以看到插件实例化时,实例化了一个framework.HandleSharedInformerFactory,然后构造出了core/v1组下一些核心资源的informer。

func NewCSI(_ runtime.Object, handle framework.Handle) (framework.Plugin, error) {
	informerFactory := handle.SharedInformerFactory()
	pvLister := informerFactory.Core().V1().PErsistentVolumes().Lister()
	pvcLister := informerFactory.Core().V1().PersistentVolumeClaims().Lister()
	csiNodesLister := informerFactory.Storage().V1().CSINodes().Lister()
	scLister := informerFactory.Storage().V1().StorageClasses().Lister()

	return &CSILimits{
		csinodelister:        csiNodesLister,
		pvLister:             pvLister,
		pvcLister:            pvcLister,
		scLister:             scLister,
		randomVolumeiDPRefix: rand.String(32),
		translator:           csitrans.New(),
	}, nil
}

接下来在实际调度阶段,可以直接使用调度插件属性里的informer获取集群对象,比如

pvc, err := pl.pvcLister.PersistentVolumeClaims(namespace).Get(pvcName)

不幸的是,查看k8s.io/client-go/informers/factory.go里的SharedInformerFactory接口,没有发现支持metrics相关的api组和资源。

kubectl top

既然informer无法使用,突然想到kubectl top命令可以获取到由metrics-server提供的位于metrics.k8s.io/v1beta1组里的节点资源用量信息,那么我们的调度插件必然也是可以参考其实现的。因此观察kubectl top的代码,可以总结其主体流程如下。

  1. kubectl 默认flag生成,用户flag整合,flag版本匹配。

    //staging/src/k8s.io/kubectl/pkg/cmd/cmd.go
    func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.COMmand {
      ...
    	kubeconfigFlags := genericclioptions.NewConfigFlags(true).WithDeprecatedPassworDFlag()
    	kubeConfigFlags.AddFlags(flags)
    	matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags)
    	matchVersionKubeConfigFlags.AddFlags(cmds.PersistentFlags())
      ...
    }
    
  2. 用MatchVersionKubeConfigFlags实例化一个factoryImpl。

    //staging/src/k8s.io/kubectl/pkg/cmd/cmd.go
    func NewKubectlCommand(in io.Reader, out, err io.Writer) *cobra.Command {
      ...
    	f := cmdutil.NewFactory(matchVersionKubeConfigFlags)  
      ...
    }
    
  3. 调用factoryImpl的ToRESTConfig()方法拿到client-go中各种client连接集群使用的参数对象config(k8s.io/client-go/rest.Config)。

    //staging/src/k8s.io/kubectl/pkg/cmd/top/top_node.go
    func (o *TopNodeOptions) complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
      ...
    	config, err := f.ToRESTConfig()  
      ...
    }
    
  4. 用上一步的config即可构造一个metricsClientSet,这是一个基于client-go RESTClient包装出的用于访问metrics.k8s.io/v1beta1组监控数据的client。

    //staging/src/k8s.io/kubectl/pkg/cmd/top/top_node.go
    import(
      ...
      metricsclientset "k8s.io/metrics/pkg/client/clientset/versioned"
      ...
    )
    
    func (o *TopNodeOptions) Complete(f cmdutil.Factory, cmd *cobra.Command, args []string) error {
    	...
    	o.MetricsClient, err = metricsclientset.NewForConfig(config)
    	...
    	return nil
    }
    
  5. 最后,使用上一步的metricsRestClient,即可拿到集群节点metrics。

    //staging/src/k8s.io/kubectl/pkg/cmd/top/top_node.go
    func getNodeMetricsFromMetricsAPI(metricsClient metricsclientset.Interface, resourceName string, selector labels.Selector) (*metricsapi.NodeMetricsList, error) {
    	...
    	mc := metricsClient.MetricsV1beta1()
    	nm := mc.NodeMetricses()
    	...
    }
    

实现

综上,我们可以在调度插件的调度打分过程中,像执行kubectl top命令一样使用基于client-go的metricsClientSet获取节点的实际内存信息,从而代替上一版本中从prometheus获取节点内存信息的过程。

具体实现细节

  1. 为插件参数结构体增加一个属性,使其实例能够持有一个metricsClientSet实例。

    type NodeAvailableMemoryPluginArg struct {
    	PrometheusEndpoint string `json:"prometheus_endpoint,omitempty"`
    	MaXMemory          int    `json:"max_memory,omitempty"`
    	MetricsClientSet   *metricsClientSet.Clientset
    
  2. 在插件的New方法中,构造一个config实例(同时支持集群外kubeconfig和集群内serviceaccount),再用config构造出metricsClientSet实例,赋值给NodeAvailableMemoryPluginArg的实例。

  3. 打分阶段根据PrometheusEndpoint参数的配置,决定从哪里获取节点内存信息:如果PrometheusEndpoint为空则使用metrics server,否则仍然从prometheus获取。

脚本宝典总结

以上是脚本宝典为你收集整理的基于kubernetes调度框架的自定义调度器实现-优化篇全部内容,希望文章能够帮你解决基于kubernetes调度框架的自定义调度器实现-优化篇所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。