基于业务团队(Cloud BU 应用平台)在开发Serverless引擎框架的过程中完成的K8s Cluster Autoscaler华为云插件。 目前该插件已经贡献给了K8s开源社区,见下图:
本文将会涉及到下述内容:
直入主题,这里不再赘述K8s的基本概念。
什么是弹性伸缩?
顾名思义是根据用户的业务需求和策略,自动调整其弹性计算资源的管理服务,其优势有:
在具体解释CA概念之前,咋们先从宏观上了解一下K8s所支持的几种弹性伸缩方式(CA只是其中的一种)。
K8s支持的几种弹性伸缩方式:
注: 为了描述精确性,介绍下面几个关键概念时,先引用K8S官方解释镇一下场 :)。"简而言之"部分为作者本人的解读。
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,对其进行扩缩容(由于使用场景不多,不做过多介绍)
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。
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,达到集群扩缩容的目的。
前面做了这么多铺垫,是时候切入本文主题了。下面我将主要从架构和代码两个维度来揭开CA模块的神秘面纱,并配合FAQ的形式解答常见的问题。
CA整体架构及所含子模块
如上图所示, CA模块包含以下几个子模块, 详见K8S CA模块在Github的源码:
通过对K8s 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主要逻辑是遵循如下几步:
通过上面的介绍结合代码片段,我们了解到何时ScaleUp/ScaleDown函数会被调用。接下来,我们来看看当这两个核心函数被调用时,里面具体都发生了什么。
先来看一下ScaleUp:
从上图代码片段,以及我里面标注的注释,可以看到,这里发生了下面几件事:
CA的cloudprovider子模块
与具体的云提供商(i.e. AWS, GCP, Azure, Huawei Cloud)对接来对对应云平台上的Node Group(有的云平台叫Node Pool)里的Node进行增删操作已达到扩缩容的目的。其代码对应于与之同名的cloudprovider package。详见Github代码。 没个云提供商,都需要按照k8s约定的方式进行扩展,开发自家的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,我也有加微信群。总之, 对于开源项目,一定要找到高效的和组织沟通的方式。
另外,对于贡献代码过程中,如果使用到了三方开源代码,由于版权和二次分发的问题,尽量避免直接包含三方源代码, 如果实在需要,可以对其进行扩展,并在新扩展的文件附上华为的版权信息与免责声明。 关于公司的具体要求和政策请参阅文件: 对外开源代码出口自检标准与指导书 以及 对外开源流程指导