作者:毕宏伟,华云数据CTO中心-研发中心-公有云产品线
责编:周建丁(zhoujd@csdn.net)
Docker是一个开源的应用容器引擎,让开发者可以打包应用以及依赖包到一个可移植的容器中,然后发布到Linux机器上。容器使用沙箱机制,相互之间不会有任何接口,几乎没有性能开销,可以很容易地在主机和数据中心中运行。
Kubernetes容器集群管理系统的主要功能包括:使用Docker对应用程序进行打包、实例化及运行;以集群的方式运行及管理跨主机的容器;解决位于不同主机之间所运行的容器之间的通信问题等等。其中,Scheduler(调度器)是Kubernetes容器集群管理系统中加载并运行的调度程序,其负责收集、统计分析容器集群管理系统中所有Node的资源使用情况,然后以此为依据将新建的Pod发送到优先级最高的可用Node上去建立。
在新增Pod的过程中,调度器的调度策略被分成两个阶段:Predicates阶段和Priorities阶段。其中,Predicates阶段回答“能不能”的问题,即能否将Pod调度到特定的Node上运行,这一阶段输出的所有满足要求的Node将被记录并作为第二阶段的输入。Priorities阶段是回答“哪个更适合的问题”,即再次对节点进行筛选,筛选出最适合运行Pod的节点。
Predicates阶段包括五个调度策略:PodFitsPorts、PodFitsResources、NoDiskConflict、MatchNodeSelector和HostName,即需要经过上述5个Predicates的检验,才能确定为“能被调度到的Node”。如其中的PodFitsPorts规则,它所评估的依据就是端口是否冲突,即检测待调度的Pod中所有容器要用到的端口集对应的HostPort集与Node上已使用的端口是否冲突。而Priorities则是在Predicates的基础上回答“哪个可用Node最优先”的问题。
Priorities阶段包括三个调度策略:LeastRequestedPriority(最少请求资源优先调度策略)、ServiceSpreadingPriority(最小相同服务优先调度策略)和EqualPriority(平等优先调度策略)。即按照LeastRequestedPriority、ServiceSpreadingPriority和EqualPriority三个调度策略,给Predicates阶段筛选出来的所有Node打分,并评出优先级,优先级最高的Node作为Pod被调度的目的节点。
具体如下:LeastRequestedPriority的计算原则是尽量将需要新创建的Pod调度到计算资源占用比较小的Node上,这里的“计算资源”指 CPU 资源和Memory资源;ServiceSpreadingPriority的计算原则是使同一个Node上属于相同服务的Pod数量尽量少,这样调度的Pod能够尽可能地实现服务的高可用性和流量负载均衡;EqualPriority的计算原则是平等对待Predicates阶段筛选出来的每一个可用Node。
目前,LeastRequestedPriority是最主要的评分依据。其计算过程如下:
- 遍历所有可用Node,对每个可用Node上已经调度运行的所有Pod请求所需的Memory资源和CPU资源进行求和;
- 对待创建的Pod请求所需的Memory资源和CPU资源进行求和,加上S11中得出的对应的Memory和CPU的值,并以int64型的整数totalMemory和int64型的整数totalMilliCPU进行返回;
- 再次遍历所有可用Node,并计算每个可用Node的Memory资源和CPU资源的总量,并以int64型的整数capacityMemory和int64型的整数capacityMilliCPU进行返回;
- 分别计算每个可用Node 的CPU得分和Memory得分;其中,CPU得分=int(((capacityMilliCPU - totalMilliCPU) * 10) / capacityMilliCPU);Memory得分= int(((capacityMemory - totalMemory) * 10) / capacityMemory);如果totalMilliCPU的值大于capacityMilliCPU或者totalMemory的值大于capacityMemory的值,则直接返回CPU得分为0或者Memory得分为0。将得分和最高的节点做为Pod的启动节点。
Kubernetes的调度器实现了插件化,用户可以开发自己的调度策略并以插件的形式集成到Kubernetes中,以便调度不同类型的任务。然而随着时间的推移,由于种种因素的影响,如工作节点上资源变化、其他Pod的创建与删除,原有已经被调度的Pod可能已经不适合调度策略了。在这种情况下,社区提出了“重调度”的概念,即控制器将某个处于运行中的Pod终止,并在不中断服务的情况下,将此Pod重新调度到适合的节点上。