12.3 Pod的垂直扩缩容

除了HPA(Pod水平扩展功能),Kubernetes仍在继续开发一些新的互补的Pod自动扩缩容功能,将其统一放在Kubernetes Autoscaler的GitHub代码库进行维护。目前有以下几个正在开发的项目。

◎ ClusterAutoScaler:主要用于公有云上的Kubernetes集群,目前已经覆盖常见的公有云,包括GCP、AWS、Azure、阿里云、华为云等,其核心功能是自动扩容Kubernetes集群的节点,以应对集群资源不足或者节点故障等情况。

◎ Vertical Pod Autoscaler:简称VPA,目前仍在快速演进,主要与HPA互补,提供Pod垂直扩缩容的能力,这也是本节讲解的主要内容。

◎ Addon Resizer:是VPA的简化版,可方便我们体验VPA的新特性。

12.3.1 VPA详解

若更深入地理解VPA,则可以从HPA开始。为了实施HPA,我们需要提前做很多准备工作,包括:

◎ 运行、观测并正确设定目标Pod的资源请求,包括CPU和内存的初始值,满负荷情况下单一Pod的CPU和内存上限值;

◎ 测试Pod的副本数量与请求负载之间的关系,用来设定HPA情况下Pod的合理副本数的范围;

◎ 观察HPA的实际效果,并继续调整相关参数。

如果要实施HPA并发挥它的真正效果,则首先需要大量的配置和运维管理工作;此外,在现实情况下,我们手动设置一个Pod资源配额基本靠猜,导致集群资源的无谓浪费。那么,有没有一种工具或手段,可以自动化并且精确完成该工作呢?如果能实现,整个集群的资源利用率就可以得到更好的提升,这就是VPA的目的所在。下面是VPA要实现的目标:

◎ 通过自动配置Pod的资源请求(CPU/Memory Request &Limit)来降低运维的复杂度和人工成本;

◎ 在努力提高集群资源利用率的同时避免出现容器资源不足的风险,例如出现内存不足或CPU饥饿。

简单来说,VPA主要是想办法找出目标Pod在运行期间所需的最少资源,并且将目标Pod的资源请求改为它所建议的数值,这样一来,容器既不会有资源不足的风险,又最大程度地提升了资源利用率。其设计思路也不难理解,如下所述。

(1)VPA会通过Metrics Server获取目标Pod运行期间的实时资源度量指标,主要是CPU和内存使用指标。

(2)将这些数据汇聚处理后存放在History Storage组件中。

(3)History Storage组件中的历史数据与Metrics Server里的实时数据会一起被VPA的Recommender组件使用。Recommender组件会结合推荐模型Recommendation model推导出目标Pod资源请求的合理建议值。目前实现的推荐模型比较简单:假设内存和CPU使用率是独立的随机变量,其分布等于在过去N天中观察到的分布(推荐N=8,以捕获每周峰值)。未来更先进的模型可能会尝试检测趋势、周期性及其他与时间相关的模式。

(4)一旦Recommender计算出目标Pod的新推荐值,若这个推荐值与Pod当前实际配置的资源请求明显不同,VPA Updater组件就可以决定更新Pod。Pod的更新有以下两种方式。

◎ 通过Pod驱逐(Pod Eviction),让Pod控制器如Deployment、ReplicaSet等来决定如何销毁目标Pod并重建Pod副本。

◎ 原地更新Pod实例(In-place updates),目标Pod并不销毁,而是直接修改目标Pod的资源配置数据并立即生效。这也是VPA的一个亮点特性。

为了追踪目标Pod并实施垂直伸缩功能,VPA定义了一个全新的CRD“VerticalPodAutoscaler”,它的定义包括一个匹配目标Pod的选择器、计算资源的资源策略(Resources policy)、Pod的更新策略(Update policy)等。下面给出一个示例:

这里对其中的关键信息解释如下。

(1)targetRef:用于匹配目标Pod的选择器。这里选择名为frontend的Deployment控制的Pod。

(2)ResourcePolicy:用于指定资源计算的策略,如果这一字段被省略,则将会为在targetRef中指定的控制器生成的所有Pod的容器进行资源测算,并根据UpdatePolicy的定义进行更新。

◎ ContainerName:容器名称,如果为“*”,则对所有没有设置资源策略的容器都生效。

◎ Mode:为Auto时,表示为指定的容器启用VPA;为Off时,表示关闭指定的容器的VPA。

◎ MinAllowed:最小允许的资源值。

◎ MaxAllowed:最大允许的资源值。

(3)UpdatePolicy:用于指定监控资源需求时的操作策略,有以下几个选项。

◎ UpdateMode:默认值为Auto。

◎ Off:仅监控资源状况并提出建议,不进行自动修改。

◎ Initial:在创建Pod时为Pod指派资源。

◎ Recreate:在创建Pod时为Pod指派资源,并可以在Pod的生命周期中通过删除、重建Pod,将其资源数量更新为Pod申请的数量。

◎ Auto:目前相当于Recreate。

如果我们不放心VPA自动修改Pod的资源配置信息,则可以将UpdateMode设置为Off,这时可以通过命令行得到VPA给出的建议值。VPA还有一个重要的组件——VPA Admission Controller,它会拦截Pod的创建请求,如果该Pod对应的UpdateMode不是Off,则它会用Recommender推荐的值改写Pod中对应的Spec内容。在目前的版本中,Pod不必通过VPA的准入控制“修正”就能被正常调度,但在未来的版本中可能考虑增加强制性要求,比如某种Pod必须要经过VPA的修正才能被调度,如果该Pod没有定义对应的VerticalPodAutoscaler,则VPA Admission Controller可以拒绝该Pod的创建请求。

VPA与HPA是否可能共同作用在同一个Pod上?从理论上来说,的确存在这种可能性,比如:CPU密集的负载(Pod)可以通过CPU利用率实现水平扩容,同时通过VPA缩减内存使用量;I/O密集的负载(Pod)可以基于I/O吞吐量实现水平扩容,同时通过VPA缩减内存和CPU使用量。

但是,实际应用是很复杂的,因为Pod副本数量的变动不仅影响到瓶颈资源的使用情况,也影响到非瓶颈资源的使用情况,其中有一定的因果耦合关系。此外,VPA目前的设计实现没有考虑到多副本的影响,在未来扩展后有可能达到HPA与VPA双剑合璧的新境界。

12.3.2 安装Vertical Pod Autoscaler

在安装Autoscaler前要先启动Metrics Server,首先使用Git获取Autoscaler的源码:

下载结束之后,运行如下脚本启动VPA:

可以看到,在安装过程中生成了常见的Deployment、Secret、Service及RBAC内容,还生成了两个CRD,接下来会用新生成的CRD设置Pod的垂直扩缩容。

12.3.3 为Pod设置垂直扩缩容

在下载的Git代码中包含一个子目录example,可以使用其中的redis.yaml来尝试使用VPA功能。

查看其中的redis.yaml文件,可以看到VPA的定义:

该定义非常简短:对名称为redis-master的Deployment进行自动垂直扩缩容。

通过kubectl将测试文件提交到集群上运行:

在创建结束之后,VPA会监控资源状况,大约5min后重新获取VPA对象的内容:

可以看到,在VPA对象中已经有了新的推荐设置。接下来查看Redis的Pod资源请求:

不难看出,Pod的资源状况和Deployment中的原始定义已经不同,和VPA中的推荐数量一致。

12.3.4 注意事项

注意事项如下。

◎ VPA对Pod的更新会造成Pod的重新创建和调度。

◎ 对于不受控制器支配的Pod,VPA仅能在其创建时提供支持。

◎ VPA的准入控制器是一个Webhook,可能会和其他同类Webhook存在冲突,从而导致无法正确执行。

◎ VPA能够识别多数内存不足的问题,但并非全部。

◎ 尚未在大规模集群上测试VPA的性能。

◎ 如果多个VPA对象都匹配同一个Pod,则会造成不可预知的后果。

◎ VPA目前不会设置limits字段的内容。