ACK的自动伸缩能力是通过节点自动伸缩组件实现的,可以按需弹出普通实例、GPU实例、竞价付费实例,支持多可用区、多实例规格、多种伸缩模式,满足不同的节点伸缩场景。
工作原理
在Kubernetes中,节点自动伸缩的工作原理与传统意义上基于使用率阈值的模型有所差别,这也是很多开发者在从传统的IDC或者其他编排系统迁移到Kubernetes后最难理解的地方。例如,将Swarm集群迁移至ACK集群。
传统的弹性伸缩模型是基于使用率的,例如:一个集群中有3个节点,当集群中的节点CPU、内存使用率超过特定的阈值时,此时弹出新的节点。但当深入思考时会发现以下几个问题:
在一个集群中,部分热点节点的利用率会较高,而另外一个节点的利用率会很低。如果选择平均利用率的话可能会造成弹性伸缩的不及时。如果使用最低的节点的利用率,那么也会造成弹出资源的浪费。
在Kubernetes中,应用是以Pod为最小单元,部署在集群的不同节点上的。当一个Pod资源利用率较高的时候,即便此时所在的节点或者集群的总量触发了弹性扩容,但是该应用的Pod数目,以及Pod对应的Limit没有任何变换,那么负载的压力是无法转移到新扩容出的节点上的。
如果基于资源利用率的方式判断节点是否缩容,那么很有可能出现,Request很大,但是Usage很小的Pod被驱逐,当集群中这种类型的Pod较多时,会导致集群的调度资源被占满,部分Pod无法调度。
Kubernetes节点伸缩是怎么解决以上问题的呢?Kubernetes是通过调度与资源解耦的两层弹性模型来解决的。
基于资源的使用率来触发应用副本的变化,也就是调度单元的变化。而当集群的调度水位达到100%的时候会触发资源层的弹性扩容,当资源弹出后,无法调度的单元会自动调度到新弹出的节点上,从而降低整个应用的负载状况。以下介绍Kubernetes弹性伸缩的技术细节:
cluster-autoscaler是通过对处在Pending的Pod进行监听而触发的。当Pod处在Pending的原因是调度资源不足的时候,会触发cluster-autoscaler的模拟调度,模拟调度器会计算在配置的伸缩组中哪个伸缩组弹出节点后可以调度这些Pending的Pod。如果有伸缩组可以满足,那么就弹出相应的节点。
模拟调度就是将一个伸缩组当成一个抽象的Node,伸缩组中配置的机型规格对应会成为Node的CPU/内存/GPU的容量,然后设置伸缩组上面的Label、Taint,也就是Node的Label与Taint。模拟调度器会在调度模拟的时候,将该抽象的Node纳入调度参考。如果Pending的Pod可以调度到抽象的Node,那么就会计算所需的Node的数目,驱动伸缩组弹出节点。
首先只有弹性伸缩弹出的节点会被缩容,静态的节点是无法被cluster-autoscaler接管的。缩容的判断是通过每个节点单独判断的。当任意一个节点的调度利用率低于所设置的调度阈值时,会触发节点的缩容判断。此时cluster-autoscaler会尝试模拟驱逐节点上面的负载,判断当前节点是否可以排水彻底。有些特殊的Pod(kube-system命名空间的非DaemonSet Pod、PDB控制的Pod等),则会跳过该节点而选择其他的候选节点。当节点发生驱逐时,会先进行排水,将节点上的Pod驱逐到其他的节点,然后再下线该节点。
不同分组之间,实际上相当于不同的虚拟的Node之间的选择,和调度策略一样,这里也存在一个打分的机制。首先符合调度策略的Node会先过滤出来,在符合调度策略的Node中,会根据affinity等亲和性的策略进行选择。如果上述的策略都不存在,默认情况下cluster-autoscaler会通过least-waste的策略来进行抉择。least-waste的策略的核心就是模拟弹出节点后,剩余的资源最少。此外,有一个特别的场景,当有一个GPU的伸缩组和CPU的伸缩组同时可以弹出生效时,默认CPU会优先于GPU弹出。
弹性伸缩的成功率主要取决如下两个因素:
- 调度策略是否满足
首先在配置好伸缩组后,开发者需要先确认下该伸缩组可以承载的Pod的调度策略范围。如果无法直接判断,最简单的方式是通过nodeSelector直接选择伸缩组的Label进行预弹模拟。
- 资源配置是否充分
当模拟调度通过后,会选择伸缩组进行弹出,但是伸缩组中配置的ECS规格是否有库存会直接决定是否可以成功弹出实例。因此配置多个可用区、多个不同机型组合可以大大提高弹出成功率。
- 方法一:可以通过极速模式加速弹出速度,当伸缩组预热后(已完成一次扩容和缩容),伸缩组即可进入极速伸缩模式。
- 方法二:使用自定义镜像的方式,通过Alibaba Cloud Linux 2(原Aliyun Linux 2)作为基础镜像,可以大大提升IaaS层的资源交付速度(50%)。
注意事项
- 默认单个用户每个区域按量付费实例的配额是50 vCPU,在专有网络下创建的单个路由表可创建的自定义路由数限额是48条。如需更大的配额,请提交工单申请。
- 单一规格的ECS库存容量波动较大,建议在伸缩组中配置多种同规格的实例类型,提高节点伸缩成功率。
- 极速弹出模式在节点进入停机回收状态时,节点将进行停机,并处在NotReady状态,当再次伸缩弹出时,节点状态会变为Ready。
- 极速弹出模式的节点处在停机回收状态时,只收取磁盘的费用,不收取计算费用(不包含拥有本地盘的机型系列,例如,ecs.d1ne.2xlarge),在库存充裕的前提下可以极速启动。
- 选择绑定EIP时,通过ECS控制台直接删除自动伸缩组或者扩容出的ECS节点会导致弹性公网EIP(Elastic IP Address)无法自动释放。
步骤一:执行自动伸缩
- 登录容器服务管理控制台,在左侧导航栏中选择集群。
- 在目标集群右侧的操作列下,选择 。
步骤二:授权
自动弹性伸缩的授权操作分以下三种场景:
节点权限被收敛的集群
- 开通ESS服务。
- 单击提示对话框中的第一个链接,进入弹性伸缩服务ESS页面。
- 单击开通ESS服务,进入云产品开通页。
- 选中我已阅读并同意复选框,单击立即开通。
- 开通成功后,在开通完成页签,单击管理控制台,进入弹性伸缩服务ESS页面。
- 单击前往授权,进入云资源访问授权页面,配置对云资源的访问权限。
- 单击同意授权。
- 单击提示对话框中的第一个链接,进入弹性伸缩服务ESS页面。
- 授权角色。
节点权限未被收敛的集群
自动伸缩节点池需要绑定EIP的集群
如果自动伸缩组需要绑定EIP,授权步骤如下。
步骤三:配置自动伸缩
预期结果
常见问题
- 为什么节点自动伸缩组件无法弹出节点?
请检查是否存在如下几种场景:
- 配置伸缩组的实例类型无法满足Pod的资源申请(Request)。默认节点会安装系统组件,Pod的申请资源要小于实例的规格。
- 是否完整按照步骤执行了授权操作。授权操作是集群维度的,需要每个集群操作一次。
- 为什么节点自动伸缩组件无法缩容节点?
请检查是否存在如下几种场景:
- 所有的节点Pod的资源申请(Request)阈值高于设置的缩容阈值。
- 节点上运行kube-system命名空间的Pod。
- 节点上的Pod包含强制的调度策略,导致其他节点无法运行此Pod。
- 节点上的Pod拥有PodDisruptionBudget,且到达了PodDisruptionBudget的最小值。
您可以在开源社区得到更多关于节点自动伸缩组件的常见问题与解答。
- 多个伸缩组在弹性伸缩的时候是如何被选择的?
在Pod处在无法调度时,会触发弹性伸缩组件的模拟调度逻辑,会根据伸缩组配置的标签和污点以及实例规格等信息进行判断。当配置的伸缩组可以模拟调度Pod的时候,就会被选择进行节点弹出。当同时有多个伸缩组满足模拟调度条件的时候,默认采用的是最少浪费原则,即根据模拟弹出后节点上剩余的资源最小为原则进行抉择。