摘要:本文将解密K8s Cluster Autoscaler模块的架构和代码的Deep Dive,及K8s Cluster Autoscaler 华为云插件。
背景信息
基于业务团队(Cloud BU 利用平台)在开发Serverless引擎框架的过程中实现的K8s Cluster Autoscaler华为云插件。 目前该插件曾经奉献给了K8s开源社区,见下图:
本文将会波及到下述内容:
- 对K8s Cluster Autoscaler模块的架构和代码的Deep Dive,尤其是外围性能点的所波及的算法的介绍。
- K8s Cluster Autoscaler 华为云插件模块的介绍。
- 作者自己参加K8s开源我的项目的一点心得。(如:何从开源社区获取信息和求助,在奉献开源过程中须要留神的点)
直入主题,这里不再赘述K8s的基本概念。
什么是K8s Cluster Autoscaler (CA)?
什么是弹性伸缩?
顾名思义是依据用户的业务需要和策略,主动调整其弹性计算资源的治理服务,其劣势有:
- 从利用开发者的角度:可能让应用程序开发者专一实现业务性能,无需过多思考零碎层资源
- 从零碎运维者的角度:极大的升高运维累赘, 如果零碎设计正当能够实现“零运维”
- 是实现Serverless架构的基石,也是Serverless的次要个性之一
在具体解释CA概念之前,咋们先从宏观上理解一下K8s所反对的几种弹性伸缩形式(CA只是其中的一种)。
K8s反对的几种弹性伸缩形式:
注: 为了形容精确性,介绍上面几个要害概念时,先援用K8S官网解释镇一下场 :)。"简而言之"局部为作者自己的解读。
VPA (Vertical Pod Autoscaler)
A set of components that automatically adjust the amount of CPU and memory requested by Pods running in the Kubernetes Cluster. Current state - beta.
简而言之: 对于某一个POD,对其进行扩缩容(因为应用场景不多,不做过多介绍)
HPA(Horizontal Pod Autoscaler) - Pod级别伸缩
A component that scales the number of pods in a replication controller, deployment, replica set or stateful set based on observed CPU utilization (or, with beta support, on some other, application-provided metrics).
简而言之: 对于某一Node, 依据事后设置的伸缩策略(如CPU, Memory使用率某设定的阀值),减少/删减其中的Pods。
HPA伸缩策略:
HPA依赖metrics-server组件收集Pod上metrics, 而后依据事后设定的伸缩策略(如:CPU使用率大于50%),来决定扩缩容Pods。计算CPU/Memory使用率时,是取所有Pods的平均值。对于具体如何计算的,点击此处有具体算法介绍。
注:metrics-server默认只反对基于cpu和memory监控指标伸缩策略
图中下半部门Prometheus监控零碎和K8s Prometheus Adapter组件的引入是为了可能应用自定义的metrics来设置伸缩策略,因为不是本文的重点,这里不做过多介绍, K8s官网文档有个Walkthrough案例一步一步在实操中把握和了解该模块。如果用户只须要根据cpu/memory的监控指标来设置伸缩策略,只有deploy默认的metrics-server组件(其装置对K8s来说就是一次deployment,十分不便, 下面的链接里有装置步骤)
CA (Cluster Autoscaler)- Node级别伸缩
A component that automatically adjusts the size of a Kubernetes Cluster so that: all pods have a place to run and there are no unneeded nodes.
简而言之: 对于K8S集群,减少/删除其中的Nodes,达到集群扩缩容的目标。
Kubernetes(K8s) Cluster Autoscaler(CA)模块源码解析:
后面做了这么多铺垫,是时候切入本文主题了。上面我将次要从架构和代码两个维度来揭开CA模块的神秘面纱,并配合FAQ的模式解答常见的问题。
CA整体架构及所含子模块
如上图所示, CA模块蕴含以下几个子模块, 详见K8S CA模块在Github的源码:
- autoscaler: 外围模块,蕴含外围Scale Up和Scale Down性能(对应Github里 core Package)。
- 在扩容时候:其ScaleUp函数会调用estimator模块来评估所需节点数
- 在缩容时:其ScaleDown函数会调用simulator模块来评估缩容的节点数
- estimator: 负责计算扩容须要多少Node (对应Github里 estimator Package)
- simulator: 负责模仿调度,计算缩容节点 (对应Github里 simulator Package)
- expander: 负责扩容时,抉择适合的Node的算法 (对应Github里 expander Package),能够减少或定制化本人的算法
- cloudprovider: CA模块提供给具体云提供商的接口 (对应Github里cloudprovider Package)。对于这个子模块前面也会着重介绍,也是咱们华为云cloudprovider的扩大点。
- autoscaler通过该模块与具体云提供商对接(如上图右下角方框所示 AWS, GCE等云提供商),并能够调度每个云提供商提供的Node.
通过对K8s CA模块的架构和源码的织构造的介绍,我总结有以下几点最佳实际值得学习和借鉴, 能够实用在任何编程语言上:
- SOLID设计准则无处不在,具体反映在:
- 每个子模块仅负责解决某一特定问题 - 繁多职责
- 每个子模块都预留有扩大点 - 开闭准则
- 每个子模块的接口隔离做的很清晰 - 接口拆散准则
…
清晰的子模块包的组织构造
对于CA模块的用户常见问题
- VPA更新曾经存在的Pod应用的resources
- HPA更新曾经存在的Pod正本数
- 如果没有足够的节点在可伸缩性事件后运行POD,则CA会扩容新的Node到集群中,之前处于Pending状态的Pods将会被调度到被新治理的node上
2. CA何时调整K8S集群大小?
- 何时扩容: 当资源有余,Pod调度失败,即存在始终处于Pending状态的Pod(见下页流程图), 从Cloud Provider处增加NODE到集群中
- 何时缩容: Node的资源利用率较低,且Node上存在Pod都能被从新调度到其它Node下来
3. CA多久查看一次Pods的状态?
CA每隔10s查看是否有处于pending状态的Pods
4. 如何管制某些Node不被CA在缩容时删除?
- Node上有Pod被PodDisruptionBudget控制器限度。PodDisruptionBudgetSpec
- Node上有命名空间是kube-system的Pods。
- Node上Pod被Evict之后无处安放,即没有其余适合的Node能调度这个pod
- Node有annotation: “http://cluster-autoscaler.kubernetes.io/scale-down-disabled”: “true”
- Node上存有如下annotation的Pod:“http://cluster-autoscaler.kubernetes.io/safe-to-evict”: “false”.点击见详情
若想更进一步理解和学习,请点击这里查看更残缺的常见问题列表及解答。
CA模块源码解析
因为篇幅关系,只对外围子模块深刻介绍,通过联合外围子模块与其余子模块之间如何协调和单干的形式顺带介绍一下其余的子模块。
CA模块整体入口处
程序启动入口处:kubernetes/autoscaler/cluster-autoscaler/main.go
CA的autoscaler子模块
如上图所示,autoscaler.go是接口,其默认的实现是static_autoscaler.go, 该实现会别离调用scale_down.go和scale_up.go里的ScaleDown以及ScaleUp函数来实现扩缩容。
那么问题来了,适合ScaleUp和ScaleDown办法会被调用呢,咋们依照程序一步一步来捋一下, 回到CA整体入口,那里有一个RunOnce(在autoscaler接口的默认实现static_autoscaler.go里)办法,会启动一个Loop 始终运行listen和watch零碎外面是否有那些处于pending状态的Pods(i.e. 须要帮助找到Node的Pods), 如上面代码片段(static_autoscaler.go里的RunOnce函数)所示, 值得注意的是,在理论调用ScaleUp之前会有几个 if/else 判断是否合乎特定的条件:
对于ScaleDown函数的调用,同理,也在RunOnce函数里, ScaleDown次要逻辑是遵循如下几步:
- 找出潜在的利用率低的Nodes (即代码里的scaleDownCandidates数组变量)
- 而后为Nodes里的Pods找到“下家”(即能够被安放的Nodes,对应代码里的podDestinations数组变量)
- 而后就是上面截图所示,几个if/else判断合乎ScaleDown条件,就执行TryToScaleDown函数
通过下面的介绍联合代码片段,咱们理解到何时ScaleUp/ScaleDown函数会被调用。接下来,咱们来看看当这两个外围函数被调用时,外面具体都产生了什么。
先来看一下ScaleUp:
从上图代码片段,以及我外面标注的正文,能够看到,这里产生了上面几件事:
- 通过cloudprovider子模块(上面专门介绍这个子模块)从具体云提供商处获取能够进行扩容的的NodeGroups
- 把那些Unschedulable Pods依照扩容需要进行分组(对应下面代码里的对buildPodEquivalenceGroups函数的调用)
- 把第1步失去的所有可用的NodeGroups和第2步失去的待调配的Pods, 作为输出,送入给estimator子模块的装箱算法(该调用产生对上图中computeExpansionOption函数调用外部) ,失去一些候选的Pods调度/调配计划。因为estimator子模块的外围就是装箱算法,下图就是实现了装箱算法的Estimate函数,这里实现有个小技巧,就是算法开始之前,先调用calculatePodScore把两维问题降为一维问题(即Pod对CPU和Memory的需要),而后就是传统的装箱算法,两个for loop来给 Pods找到适合的Node. 至于具体如何降维的,详见binpacking.estimator.go里的calculatePodScore函数源码。
- 把第3步失去的一些计划,送入给 expander子模块,失去最优的调配计划(对应代码片段中ExpanderStrategy.BestOption的函数调用)expander提供了上面截图中的集中策略,用户能够通过实现expander接口的BestOption函数,来实现本人的expander策略
CA的cloudprovider子模块
与具体的云提供商(i.e. AWS, GCP, Azure, Huawei Cloud)对接来对对应云平台上的Node Group(有的云平台叫Node Pool)里的Node进行增删操作已达到扩缩容的目标。其代码对应于与之同名的cloudprovider package。详见Github代码。 没个云提供商,都须要依照k8s约定的形式进行扩大,开发自家的cloudprovider插件,如下图:
下文会专门介绍华为云如何扩大该模块的。
华为云cloudprovider插件开发及开源奉献心得
华为云cloudprovider插件如何扩大和开发的?
下图是华为cloudprovider插件的大抵的代码构造, 绿色框里是SDK理论是对CCE(云容器引擎 CCE) 进行必要操作所须要的 (对Node Pool/Group里的Node 进行减少和删除)。 按理说咱们不须要本人写这一部分,不过因为咋们云CCE 团队的SDK切实是不欠缺,所以咱们开发了一些必要的对CCE进行操作的SDK。重点是红色框中的代码:
huaweicloud_cloud_provider.go是入口处,其负责总huaweicloud_cloud_config.go读取配置,并实例化huaweicloud_manager.go对象。huaweicloud_manager.go对象里通过调用蓝色框部门里的CCE SDK来获取CCE整体的信息。 CCE整体的信息被获取到后,能够调用huaweicloud_node_group.go 来实现对该CCE绑定的Node Group/Pool进行Node的扩缩容已达到对整体CCE的Node伸缩。
如何从开源社区获取所需资源及开源过程中须要留神的点?
我刚开始承受该项目标时候,一头雾水,不晓得该如何下手。K8s对于这一块的文档写的又不是很分明。以往的教训以及K8s Github README中提供的信息,我退出他们的Slack组织,找到相应的趣味组channel( 对应我的状况就是sig-autoscaling channel),提出了我的问题(如上面截图)。 基于K8s代码仓的大小,如果没找到适合的扩大点,简直无奈改变和扩大的。
划重点: 当初简直所有的开源组中都有Slack群组,退出找到相应的趣味组,外面大牛很多,提出问题,个别会有人热心解答的。 邮件列表也能够,不过我认为Slack高效实时一点,强烈推荐。对于我自己平时接触到的开源我的项目,我个别都会退出到其 Slack中,有问题随时发问。 当然,中国奉献的开源我的项目,好多以微信群的形式沟通 :)譬如咋们华为开源进来的微服务框架我的项目 ServiceComb,我也有加微信群。总之, 对于开源我的项目,肯定要找到高效的和组织沟通的形式。
另外,对于奉献代码过程中,如果应用到了三方开源代码,因为版权和二次散发的问题,尽量避免间接蕴含三方源代码, 如果切实须要,能够对其进行扩大,并在新扩大的文件附上华为的版权信息与免责申明。
点击关注,第一工夫理解华为云陈腐技术~