关于服务:重磅解读K8s-Cluster-Autoscaler模块及对应华为云插件Deep-Dive

42次阅读

共计 5916 个字符,预计需要花费 15 分钟才能阅读完成。

摘要:本文将解密 K8s Cluster Autoscaler 模块的架构和代码的 Deep Dive,及 K8s Cluster Autoscaler 华为云插件。

背景信息

基于业务团队 (Cloud BU 利用平台) 在开发 Serverless 引擎框架的过程中实现的 K8s Cluster Autoscaler 华为云插件。目前该插件曾经奉献给了 K8s 开源社区,见下图:

本文将会波及到下述内容:

  1. 对 K8s Cluster Autoscaler 模块的架构和代码的 Deep Dive,尤其是外围性能点的所波及的算法的介绍。
  2. K8s Cluster Autoscaler 华为云插件模块的介绍。
  3. 作者自己参加 K8s 开源我的项目的一点心得。(如:何从开源社区获取信息和求助,在奉献开源过程中须要留神的点)

直入主题,这里不再赘述 K8s 的基本概念。

什么是 K8s Cluster Autoscaler (CA)?

什么是弹性伸缩?

顾名思义是依据用户的业务需要和策略, 主动调整其弹性计算资源的治理服务,其劣势有:

  1. 从利用开发者的角度:可能让应用程序开发者专一实现业务性能,无需过多思考零碎层资源
  2. 从零碎运维者的角度:极大的升高运维累赘,如果零碎设计正当能够实现“零运维”
  3. 是实现 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)。
  1. 在扩容时候:其 ScaleUp 函数会调用 estimator 模块来评估所需节点数
  2. 在缩容时:其 ScaleDown 函数会调用 simulator 模块来评估缩容的节点数
  • estimator: 负责计算扩容须要多少 Node (对应 Github 里 estimator Package)
  • simulator: 负责模仿调度,计算缩容节点 (对应 Github 里 simulator Package)
  • expander: 负责扩容时,抉择适合的 Node 的算法 (对应 Github 里 expander Package),能够减少或定制化本人的算法
  • cloudprovider: CA 模块提供给具体云提供商的接口 (对应 Github 里cloudprovider Package)。对于这个子模块前面也会着重介绍,也是咱们华为云 cloudprovider 的扩大点。
  1. autoscaler 通过该模块与具体云提供商对接(如上图右下角方框所示 AWS, GCE 等云提供商),并能够调度每个云提供商提供的 Node.

通过对 K8s CA 模块的架构和源码的织构造的介绍,我总结有以下几点最佳实际值得学习和借鉴,能够实用在任何编程语言上:

  1. SOLID 设计准则无处不在,具体反映在:
  2. 每个子模块仅负责解决某一特定问题 – 繁多职责
  3. 每个子模块都预留有扩大点 – 开闭准则
  4. 每个子模块的接口隔离做的很清晰 – 接口拆散准则

清晰的子模块包的组织构造

对于 CA 模块的用户常见问题

  1. VPA 更新曾经存在的 Pod 应用的 resources
  2. HPA 更新曾经存在的 Pod 正本数
  3. 如果没有足够的节点在可伸缩性事件后运行 POD,则 CA 会扩容新的 Node 到集群中,之前处于 Pending 状态的 Pods 将会被调度到被新治理的 node 上

2. CA 何时调整 K8S 集群大小?

  1. 何时扩容: 当资源有余,Pod 调度失败,即存在始终处于 Pending 状态的 Pod(见下页流程图),从 Cloud Provider 处增加 NODE 到集群中
  2. 何时缩容: Node 的资源利用率较低,且 Node 上存在 Pod 都能被从新调度到其它 Node 下来

3. CA 多久查看一次 Pods 的状态?

CA 每隔 10s 查看是否有处于 pending 状态的 Pods

4. 如何管制某些 Node 不被 CA 在缩容时删除?

  1. Node 上有 Pod 被 PodDisruptionBudget 控制器限度。PodDisruptionBudgetSpec
  2. Node 上有命名空间是 kube-system 的 Pods。
  3. Node 上 Pod 被 Evict 之后无处安放,即没有其余适合的 Node 能调度这个 pod
  4. Node 有 annotation:“http://cluster-autoscaler.kubernetes.io/scale-down-disabled”:“true”
  5. 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 次要逻辑是遵循如下几步:

  1. 找出潜在的利用率低的 Nodes(即代码里的 scaleDownCandidates 数组变量)
  2. 而后为 Nodes 里的 Pods 找到“下家”(即能够被安放的 Nodes,对应代码里的 podDestinations 数组变量)
  3. 而后就是上面截图所示,几个 if/else 判断合乎 ScaleDown 条件,就执行 TryToScaleDown 函数

通过下面的介绍联合代码片段,咱们理解到何时 ScaleUp/ScaleDown 函数会被调用。接下来,咱们来看看当这两个外围函数被调用时,外面具体都产生了什么。

先来看一下 ScaleUp:

从上图代码片段,以及我外面标注的正文,能够看到,这里产生了上面几件事:

  1. 通过cloudprovider 子模块(上面专门介绍这个子模块)从具体云提供商处获取能够进行扩容的的 NodeGroups
  2. 把那些 Unschedulable Pods 依照扩容需要进行分组(对应下面代码里的对 buildPodEquivalenceGroups 函数的调用)
  3. 把第 1 步失去的所有可用的 NodeGroups 和第 2 步失去的待调配的 Pods, 作为输出,送入给estimator 子模块的装箱算法(该调用产生对上图中 computeExpansionOption 函数调用外部),失去一些候选的 Pods 调度 / 调配计划。因为 estimator 子模块的外围就是装箱算法,下图就是实现了装箱算法的 Estimate 函数,这里实现有个小技巧,就是算法开始之前,先调用 calculatePodScore 把两维问题降为一维问题(即 Pod 对 CPU 和 Memory 的需要),而后就是传统的装箱算法,两个 for loop 来给 Pods 找到适合的 Node. 至于具体如何降维的,详见 binpacking.estimator.go 里的 calculatePodScore 函数源码。

  1. 把第 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,我也有加微信群。总之,对于开源我的项目,肯定要找到高效的和组织沟通的形式。

另外,对于奉献代码过程中,如果应用到了三方开源代码,因为版权和二次散发的问题,尽量避免间接蕴含三方源代码,如果切实须要,能够对其进行扩大,并在新扩大的文件附上华为的版权信息与免责申明。

点击关注,第一工夫理解华为云陈腐技术~

正文完
 0