摘要:本文将解密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监控指标伸缩策略
  • HPA架构图:

图中下半部门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.

2. cloudprovider预先设定了一些列接口,供具体的云提供商实现,来完成调度其提供的Node的目的

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

1. SOLID设计原则无处不在,具体反映在:

1. 每个子模块仅负责解决某一特定问题 - 单一职责

2. 每个子模块都预留有扩展点 - 开闭原则

3. 每个子模块的接口隔离做的很清晰 - 接口分离原则

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

插件式的扩展点设计

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

1. CA和k8s其他弹性伸缩方式的关系?

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在缩容时删除?

0. Node上有Pod被PodDisruptionBudget控制器限制。PodDisruptionBudgetSpec

1. Node上有命名空间是kube-system的Pods。

2. Node上Pod被Evict之后无处安放,即没有其他合适的Node能调度这个pod

3. Node有annotation: “cluster-autoscaler.kubernetes.io/scale-down-disabled”: “true”

4. Node上存有如下annotation的Pod:“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函数源码

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

另外,对于贡献代码过程中,如果使用到了三方开源代码,由于版权和二次分发的问题,尽量避免直接包含三方源代码, 如果实在需要,可以对其进行扩展,并在新扩展的文件附上华为的版权信息与免责声明。

点击关注,第一时间了解华为云新鲜技术~

重磅解读:K8s Cluster Autoscaler模块及对应华为云插件Deep Dive的更多相关文章

  1. Python-Excel 模块哪家强 #华为云·寻找黑马程序员#

    python操作excel 最原始的莫过于两位老牌黄金搭档xlrd xlwt了,针对二者的封装有如下模块: xlutils & xlrd & xlwt 为什么把这三个一起说? 首先,x ...

  2. 第三章 k8s cluster环境创建

    1  用如下方法安装指定版本的docker,但是我的环境会报错 # 安装rpm apt install rpm # 下载 RPM 包, docker 版本 wget https://download. ...

  3. 重磅!K8S 1.18版本将内置支持SideCar容器。

    作者:justmine 头条号:大数据与云原生 微信公众号:大数据与云原生 创作不易,在满足创作共用版权协议的基础上可以转载,但请以超链接形式注明出处. 为了方便阅读,微信公众号已按分类排版,后续的文 ...

  4. rke安装k8s cluster配置

    rke安装k8s cluster配置 最简配置 cluster.yml nodes: - address: 192.168.0.103 user: lishikai role: [controlpla ...

  5. Spring Boot 最流行的 16 条实践解读!【华为云技术分享】

    置顶:华为云618大促火热进行中,全场1折起,免费抽主机,消费满额送P30 Pro,点此抢购. Spring Boot是最流行的用于开发微服务的Java框架.在本文中,将与大家分享自2016年以来笔者 ...

  6. 大海航行靠舵手 华为云靠什么征服K8S?

    Kubernetes 是Google开源的容器集群管理系统或者称为分布式操作系统.它构建在Docker技术之上,为容器化的应用提供资源调度.部署运行.服务发现.扩容缩容等整一套功能,本质上可看作是基于 ...

  7. paper 159:文章解读:From Facial Parts Responses to Face Detection: A Deep Learning Approach--2015ICCV

    文章链接:https://arxiv.org/pdf/1509.06451.pdf 1.关于人脸检测的一些小小总结(Face Detection by Literature) (1)Multi-vie ...

  8. 解读Nodejs多核处理模块cluster

    来源: http://blog.fens.me/nodejs-core-cluster/ 从零开始nodejs系列文章,将介绍如何利Javascript做为服务端脚本,通过Nodejs框架web开发. ...

  9. 傻瓜式解读koa中间件处理模块koa-compose

    最近需要单独使用到koa-compose这个模块,虽然使用koa的时候大致知道中间件的执行流程,但是没仔细研究过源码用起来还是不放心(主要是这个模块代码少,多的话也没兴趣去研究了). koa-comp ...

随机推荐

  1. VS中OpenCV用imread读取不到图片

    转自:https://blog.csdn.net/u012423865/article/details/78116059 在VS中OpenCV用imread读取不到图片 今天在Visual Studi ...

  2. vue的二级联动,数据是从php获取到的

    1.首先,一级要有change改变事件的关键字,v-on:change="selectarr($event)" 这是created(){}函数里面的自动调用一级分类的数据 html ...

  3. 获取Jetbrain全家桶激活码

    支持正版,本KEY仅用于体验软件 激活码 激活码一: 2GCA2ZHNKP-eyJsaWNlbnNlSWQiOiIyR0NBMlpITktQIiwibGljZW5zZWVOYW1lIjoi5r+A5r ...

  4. Java安全之Javassist动态编程

    Java安全之Javassist动态编程 0x00 前言 在调试CC2链前先来填补知识盲区,先来了解一下Javassist具体的作用.在CC2链会用到Javassist以及PriorityQueue来 ...

  5. 为什么在M3架构中 PC总是返回加4

    由于CPU是3级流水线的方式运行.在执行第一条指令时候,已经对第二条指令译码,对第三条指令取值. PC总是指向正在取值的指令.由于在M3架构中,采用Thumb-2指令,每个指令占据2个字节,所以PC总 ...

  6. 【数位DP】SCOI2014 方伯伯的商场之旅

    题目内容 方伯伯有一天去参加一个商场举办的游戏.商场派了一些工作人员排成一行.每个人面前有几堆石子. 说来也巧,位置在 \(i\) 的人面前的第 \(j\) 堆的石子的数量,刚好是 \(i\) 写成 ...

  7. PS文字

    点文本 直接单击鼠标可输点文字 输完后在离文字较远的地方出现白色箭头单击可结束输入,也可选择其他图层结束输入 再次修改文字可双击文字缩览图 出现黑色小箭头可以在输入到的情况下拖动文字,文字工具下按Ct ...

  8. redis 各种数据结构的encoding实现

    redis 各种数据结构的encoding实现 Redis type命令实际返回的就是当前键的数据结构类型,它们分别是:string(字符串).hash(哈希).list(列表).set(集合).zs ...

  9. spring boot:用redis+lua限制短信验证码的发送频率(spring boot 2.3.2)

    一,为什么要限制短信验证码的发送频率? 1,短信验证码每条短信都有成本制约, 肯定不能被刷接口的乱发 而且接口被刷会影响到用户的体验, 影响服务端的正常访问, 所以既使有图形验证码等的保护, 我们仍然 ...

  10. spring boot:发送带附件的邮件和html内容的邮件(以163.com邮箱为例/spring boot 2.3.2)

    一,网站哪些情况下需要发送电子邮件? 作为一个电商网站,以下情况需要发邮件通知用户: 注册成功的信息 用邮箱接收验证码 找回密码时发链接 发送推广邮件 下单成功后的订单通知 给商户的对账单邮件 说明: ...