10月13, 2017

kubernetes资源概览接口的研究

背景

借鉴以前openstack调度的经验,单纯根据基础资源(如cpu、memory等使用量)来计算机房资源的剩余情况会有偏差,有时候剩余资源满足flavor并不一定能在node成功创建虚拟机,因为openstack的调度算法并不是单纯根据资源来筛选那么简单。对于kubernetes来说,pod好比虚拟机,因为scheduler有很多算法来筛选出最合适的node,所以我们并不能单纯通过计算cpu、memory来判断某个pod是否能创建成功。

现有的k8s并没有一个类似的模块,因此,我们需要基于现有k8s的机制实现一个满足我们需求的、更灵活的子系统–-资源统计接口,能够在增加应用副本的时候,提前告诉用户该扩容的过程是否能够完成,如果可以完成再最终创建。

scheduler模块工作流程

在kubernetes中,scheduler模块负责pod的调度,为了说明scheduler工作原理,我们将scheduler模块中调度的核心部分的流程图整理出来,如下图:

image

首先,scheduler中维护了一个需要调度的pod队列--podQueue,scheduler从podQueue中pop出需要调度的pod(NextPod()),然后进入调度部分,分为预选和优选两个阶段。经过这两个阶段后,选出最合适的node,然后进入assume过程(图中AssumePod()),将node上面的资源先预先占取,最后是node和pod的绑定过程(bind, bind过程为真正将pod在node上创建的过程),完成一个pod的调度。

kubernetes中scheduler组件负责为新创建的pod选择合适的node,并将该pod和选择的node进行绑定,node的kubelet watch到绑定信息后拉起该pod。scheduler的目的是为pod筛选合适的node,那么在pod中能否指定node呢? 调度的过程分为预选(predict)和优选(priority)两个阶段:

  • 预选策略,是强制性规则,遍历所有的Node,按照具体的预选策略筛选出符合要求的Node列表,如没有Node符合Predicates策略规则,那该Pod就会被挂起,直到有Node能够满足;

  • 优选策略,在第一步筛选的基础上,按照优选策略为待选Node打分排序,获取最优者;

经过预选和优选过程后,我们会得到一个最优的node。

资源概览接口实现思路

http接口改造

在scheduler模块中,启动主程序时,同时启动了一个http服务器,该服务器对外提供了一些http接口:

/debug/pprof/
/metrics
/healthz
/configz

我们可以在该基础上自己的一个路由,通过url传入的参数,经过处理以后返回结果。中间处理的过程最重要的需要经过预选和assume的过程(后面会重点分析)。和scheduler模块不同的是,scheduler调度的pod是从podQueue中获取的,而http服务器提供的资源统计接口的pod是通过参数传递的,两者有本质的区别。

流程图

下图是资源统计接口的架构图:

image

调度算法

通过参数获取到pod的配置后,我们首先要做的是将pod配置转化为scheduler模块可以识别的*v1.Pod类型。此时,我们已经拿到了需要调度的pod,则需要进入调度函数。

预选过程得到的是符合条件的一些node,优选再根据算法为每个node去“打分”,从而选出分数最高的一个node。为了解决用户端扩容和管理端资源统计的问题,我们并不需要精确到优选到某个node,只需要直到该pod能否调度到集群,所以预选过程得到的node足以直到调度是否能够完成。

占用资源

如果通过预选得到的host数目大于0,则说明集群中还有“坑”(资源),可以“容纳”该pod。然后将进入assume和bind过程,无论是用户端的扩容还是管理端资源统计,我们并没有真正将pod调度到集群中的node上,所以bind过程应该去掉。

由于每次请求需要获取到集群中还有多少个“坑”,所以我们需要将资源临时占用(马上会释放掉),assume应该被保留(因为是深拷贝了一份缓存,所以不会影响真正的调度过程)。

资源概览接口实现方法

实现方法

为了防止用户在扩容或者创建dp时候调度失败的问题,在真正调度之前,需要向用户端返回一个能否创建的应答,告知用户当前能真正使用的资源量。如果资源满足需求则可以创建,否则不提示用户资源不足(此时用户可以根据当前可用资源做出抉择)。scheduler通过函数starthttp,建立了一个http服务器,我们可以利用该思想,添加一个http路由,来向外暴露接口。

为了实现该功能,我们提供了一个接口:

hostname:port/statistics?pod_config=pod的配置参数
返回:可调度机器的数目

该接口接收1个pod配置,返回当前集群可以创建该pod的总量。

在OpenStack中调度的单位是虚拟机,那在kubernetes中调度的基本单位是pod,所以在这里我们在预估资源量时也是使用pod来进行的。 使用“完整”的pod,基于如下考虑:

  • 符合原生kubernetes调度的处理逻辑;

  • 只有使用用户当前应用的pod配置才能准确的预估满足该pod的资源量;

我们对pod配置做了精简,保留跟调度有关的配置,pod模板如下:

{
    "apiVersion": "v1",
    "kind": "Pod",
    "metadata": {
        "name": "podDemo",
        "namespace": "default"
    },
    "spec": {
        "containers": [
            {
                "image": "xxx",
                "name": "xxxx",
                "resources": {
                    "limits": {
                        "cpu": "1",
                        "memory": "2000Mi"
                    },
                    "requests": {
                        "cpu": "1",
                        "memory": "2000Mi"
                    }
                },
            },
            {
                "image": "xxx",
                "name": "xxxx",
                "resources": {
                    "limits": {
                        "cpu": "1",
                        "memory": "2000Mi"
                    },
                    "requests": {
                        "cpu": "1",
                        "memory": "2000Mi"
                    }
                }
            }
        ],
        "nodeSelector": {        
          "group": "default",
          "environment": "xx"
        }
    }
}

可扩展性

为了减轻服务端计算的压力,也为了后期资源统计模块的可扩展性,我们在之前介绍的statistic http服务器的基础上包装一层http服务器,如下图:

image

http服务器接口整理:

//获取集群中可调度pod的数目
GET方式
http://hostname:port/statistics/user/add_pod/pod_config=***
返回可创建pod的数目

本文链接:https://www.opsdev.cn/post/k8s-resource-overview.html

-- EOF --

Comments

评论加载中...

注:如果长时间无法加载,请针对 disq.us | disquscdn.com | disqus.com 启用代理。