Kubernetes代码贡献者谈Kubernetes的发展动态
作者:互联网
何思玫 分布式实验室
2015年7月,Kubernetes发布了1.0版本,宣布其已经正式进入production-ready的状态。2016年3月中旬,Kubernetes发布了1.2.0版本。目前,Kubernetes在GitHub上的star数量超过了14000,社区的活跃程度也是远超想象。他们带来了来自生产环境的诉求,一些呼声极高的feature的加入也让Kubernetes的功能日益完善。另外,在以Google团队为核心开发者的主导下,非常多的组织与个人都加入到了Kubernetes开发者的行列,contributor已经超过了700人。
所以,无论是从使用者还是从开发者的角度而言,Kubernetes都是一个值得着手尝试的项目。有基于此,我希望能给大家带来一些当前被纳入Kubernetes开发计划或者是已经在着手进行开发的项目动态。
相信大家已经对Kubernetes的基本概念非常熟悉了,常见的术语,如pod/node/replication controller/volume等等,都不再展开说明。
今天分享的内容将分为三个部分,分别围绕pod的调度/重调度与自动扩展来展开。
众所周知,在Kubernetes诞生之初,其预设的服务场景基本上围绕long-running service展开,例如Web Service。现在,Kubernetes已经有了专门支持batch job的资源——Job,我们可以简单地将其理解为run to terminate的任务。
提及batch job和long-running service混合部署,恐怕大家都会聚焦到调度器的调度策略上来。Kubernetes的调度框架是plugin形式的,也就是说,用户可以容易地实现定制化的调度策略。
例如,当集群中有两种优先级不同的pod(如批处理作业和实时响应程序)均在等待调度时,我们往往希望其中优先级较高的pod,即实时响应程序被优先调度。但是,如果我们只采用一个默认的default调度器,显然是不足以支撑这个需求的。包括Omega、Mesos在内的多种集群调度框架都衍生出了多个调度器同时工作的模式或者丰富的两级调度框架。有鉴于实际生产环境中对于不同调度策略乃至于调度器的需求,社区也将multi-scheduler的工作稳步推进。
我们知道,一个pod应当被一个且只被一个调度器调度到某个工作节点上,否则就会发生pod运行失败或者调度工作节点冲突等状况。所以,实现multi-scheduler的关键在于,如何将pod与其对应的scheduler match起来。
社区目前采用了annotations
来实现这一需求。所谓annotations
,可以看作是一组非结构化的key-value对,在这里我们用到的key值为scheduler.alpha.kubernetes.io/name
,用于为用户提供自定义使用调度器的自由。若用户没有指定该字段,则系统自动将其指派给默认的调度器进行调度。
遗憾的是,这一方案还没有解决用户指定无效调度器(如拼写错误等)的问题,一旦发生这一状况,对应的pod将会一直处于Pending
的状态。所以,在未来的工作中,可能会考虑引入一个admission controller来辅助完善annotation定义部分的工作。例如,根据pod所在的Namespace来指定annotation,标记出潜在的冲突规则(如指定了两个以上的running scheduler),reject那些可能因为typo或者用户掌握了过时的信息而被指定到一个没有work的scheduler等。
聊完了Multiple Scheduler,我们继续来看另一个与调度相近的话题。
我们知道,Kubernetes依靠Scheduler来将pod与适宜的node进行binding,并且力图通过优化调度策略等方面的努力使得调度决策试图达到运行时最优。
然而不可忽视的是,随着时间的推移,由于种种因素的影响,如工作节点上资源变化、其他pod的创建与删除,在创建pod时做出的调度决策可能已经变得不再适用。在这种情况下,我们希望能够将pod进行重新调度,使得从pod或者从集群的宏观角度来看重新达到更优。
当然,在Kubernetes v1.2.0版本中,从一个pod被调度到某个工作节点开始,直至其生命周期结束,它都不会在节点之间发生迁移。所以重新调度这个术语,在严格意义上来说并不十分准确。社区目前将其称为重调度,是出于易于理解的需要。这里所谓的重新调度,实际上是指controller自行将某个处于运行中的pod终止,并且在其他更适合的工作节点上创建一个pod来作为它的替代,不存在热迁移。
重调度的使用场景可能比你想象到的要多得多,如:
一,将一个运行中的pod“移动”到一个与调度规则匹配程度更高的新的工作节点上,例如资源更充足的工作节点,或者更符合pod预定义的节点亲和性或反亲和性要求。
二,基于可预知的事件推断,将一个运行中的pod从旧的工作节点移除。
旧的工作节点即将因为运维、节点自动scale down等原因停止工作,此前应该将该节点上运行的所有pod均预先移动到其他节点。
将某个运行中的pod停止,从而在其释放资源的配给后,另一个Pending状态的pod能调度到当前pod工作的节点上。
将运行的pod移动到相对集中的一部分节点上,使得在将来出现对于资源使用量要求较高的pod时,该pod能够顺利地被调度。这个使用场景类似于文件系统中的碎片回收的工作。这个使用场景与上一个的区别在于,它是主动发生的投机行为,此时并不存在某个既定的pending的pod在等待调度。
三,运行中的pod在其依附的node上工作状态较差。
社区打算为重调度的实现引入一个专门的Rescheduler,然而毫无疑问的是,整个流程会涉及到多个系统组件协同工作,而不仅仅由Rescheduler单独完成。具体的设计方案还尚未完全敲定,在这里列出一些引起热议的问题。
一个pod如何描述对于系统主动终止其运行的容忍程度,而系统又将如何处理主动终止pod的实施限度。用户可能不希望系统过分干预pod的运行,即便系统声称这是出于全局的利益,甚至可能对单个pod的运行也有好处。如何定义这个界限并保证系统不越界,显然是一个重要的议题。
对于每个具体场景,由什么组件来具体判定重调度合适的时间点与合适的pod?重要的是各个组件能够分工明确,各司其职。
Rescheduler需要在多大程度上了解pod的调度策略,以及Rescheduler如何描述它的重调度决策。 可能的选项是,Rescheduler仅声明移除某个pod,或者进一步加上对于新的替代pod被调度到的工作节点的偏好,更甚者Rescheduler可以明确指定重调度到的节点。
Rescheduler是否考虑级联影响。例如,一个pod的重调度可能会导致其他pod发生重调度,造成一定面积的连锁反应。又或,Rescheduler是否考虑一次性移动多个pod。
可见,在重调度的设计这一议题上,显然还有很多复杂的问题需要权衡。我们也有理由对其实现拭目以待。
自动扩展作为一个经久不衰的议题,一直为人们津津乐道。系统能够根据负载的变化对计算资源的分配进行自动的扩增或者收缩无疑是一个非常吸引人的特征。
自动扩展主要分为两种,其一为Horizontal,针对于实例数目的增减;其二为vertical,即单个实例可以使用的资源的增减。horizontal pod autoscaling属于前者。
那么horizontal pod autoscaling是如何工作的呢?目前pod autoscaling的操作对象是ReplicationController、ReplicaSet或Deployment对应的pod,根据观察到的CPU实际使用量与用户的期望值进行比对,做出是否需要增减实例数量的决策。controller使用heapster来检测CPU使用量。
虽然目前horizontal pod autoscaling的决策依据仅考量了CPU的使用量,但是在将来其他的一些影响因子也可能会被纳入范畴,如内存使用量、网络流量、QPS甚至是用户自定义的metric。
标签:贡献者,Kubernetes,工作,代码,调度,Rescheduler,pod,节点 来源: https://blog.51cto.com/u_15127630/2809423