应对资源浪费的场景,阿里云服务容器提供kubernetes-cronhpa-controller组件,实现资源定时扩容。本文介绍如何实现容器的定时伸缩,及介绍定时伸缩CronHPA兼容HPA的原理。

前提条件

背景信息

kubernetes-cronhpa-controller是一个Kubernetes HPA controller,按照类似Crontab的策略定时地对容器服务Kubernetes集群进行扩缩容。您可以把CronHorizontalPodAutoscaler(以下简称CronHPA)用在任何Kubernetes中定义的对象上,只要该对象支持伸缩子资源(如Deployment和StatefulSet)的项目已在GitHub开源。

以下举例对CronHPA的各字段进行解释说明。
apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
  labels:
    controller-tools.k8s.io: "1.0"
  name: cronhpa-sample
  namespace: default 
spec:
   scaleTargetRef:
      apiVersion: apps/v1
      kind: Deployment
      name: nginx-deployment-basic
   excludeDates:
   # exclude November 15th
   - "* * * 15 11 *"
   # exclude every Friday 
   - "* * * * * 5"
   jobs:
   - name: "scale-down"
     schedule: "30 */1 * * * *"
     targetSize: 1
   - name: "scale-up"
     schedule: "0 */1 * * * *"
     targetSize: 3
     runOnce: true
字段 说明
scaleTargetRef scaleTargetRef指定去扩缩容对象。如果对象支持scale子资源,CronHPA即可支持。
excludeDates excludeDates是日期数组。当遇到符合excludeDates描述的日期时任务将会被跳过。
说明 最小单位为

- "* * * * * *"表示-"<seconds> <minutes> <hours> <days of month> <months>"。

如您想在11月15日不运行任务,可像以下示例一样指定excludeDates
excludeDates:
  - "* * * 15 11 *"
jobs 支持在一个spec中设定多个CronHPA任务。每个CronHPA任务可以配置以下字段:
  • name:它在一个CronHPA中应是唯一的,这样就可以通过name来区分不同的任务。
  • schedule:它的策略和crontab类似。kubernetes-cronhpa-controller使用了Golang库(go-cron)功能更强大的cron,它支持更多表示规则。创建时请严格按照以下格式说明进行设置,否则将导致创建失败。
    cron表达式的格式如下:
    Field name   | Mandatory? | Allowed values  | Allowed special characters
      ----------   | ---------- | --------------  | --------------------------
      Seconds      | Yes        | 0-59            | * / , -
      Minutes      | Yes        | 0-59            | * / , -
      Hours        | Yes        | 0-23            | * / , -
      Day of month | Yes        | 1-31            | * / , - ?
      Month        | Yes        | 1-12 or JAN-DEC | * / , -
      Day of week  | Yes        | 0-6 or SUN-SAT  | * / , - ?
  • targetSize:到调度时间时,您想扩缩容到的Pod的数目。
  • runOnce:如果runOnce设置为true,那么任务将只执行一次,第一次执行完则exit。

安装CronHPA组件

您可以通过以下三种方式安装CronHPA组件ack-kubernetes-cronhpa-controller。

方式一:通过组件管理入口安装CronHPA组件。

  1. 登录容器服务管理控制台
  2. 在控制台左侧导航栏中,单击集群
  3. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情
  4. 在集群管理页左侧导航栏中,选择运维管理 > 组件管理
  5. 组件管理页面单击其他页签,找到ack-kubernetes-cronhpa-controller,然后单击安装

方式二:通过系统组件管理入口安装CronHPA组件。

  1. 登录容器服务管理控制台
  2. 在控制台左侧导航栏中,单击集群
  3. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情
  4. 集群列表页面,选择目标集群,并在目标集群右侧操作列下,选择更多 > 系统组件管理
  5. 组件管理页面单击其他页签,找到ack-kubernetes-cronhpa-controller,然后单击安装

方式三:通过应用目录入口安装CronHPA组件。

  1. 登录容器服务管理控制台
  2. 在控制台左侧导航栏中,选择市场 > 应用目录
  3. 应用目录页面名称文本框中输入kubernetes-cronhpa-controller,然后单击ack-kubernetes-cronhpa-controller组件。
  4. 应用目录-ack-kubernetes-cronhpa-controller页面右侧的创建区域,选择目标集群,然后单击创建

如果您无需使用容器定时伸缩功能,可以删除CronHPA组件。关于删除CronHPA组件ack-kubernetes-cronhpa-controller的具体步骤,请参见管理组件删除发布

创建定时伸缩CronHPA任务

为应用创建和运行CronHPA前,请确保集群中的CronHPA组件已正常运行,且当前应用只有一个HPA对象。关于CronHPA和HPA的兼容策略,请参见下文的定时伸缩CronHPA兼容HPA。您可以在以下两种场景中创建CronHPA任务。

场景一:在创建应用时创建CronHPA任务。

在创建应用的高级配置页面的伸缩配置区域,选中定时伸缩右侧开启为应用创建定时伸缩任务。关于创建应用的详细步骤,请参见创建无状态工作负载Deployment或者创建有状态工作负载StatefulSetcronhpa
容器服务管理控制台会自动检查是否已安装CronHPA组件。如果CronHPA组件未被安装,页面提示点击安装。安装CronHPA组件后,页面显示定时伸缩任务的创建配置。配置参数的详细描述如下:
表 1. 定时伸缩配置说明
参数 描述
定时任务名称 为定时任务定义名称。每个任务的名称是唯一的,不能与其他任务名称重复。
目标副本数 当到达设定计划时间时,应用副本数自动伸缩至该值。
调度周期 设置调度周期。

关于为定时伸缩任务设置调度周期的详细描述,请参见AliyunContainerService/kubernetes-cronhpa-controller

场景二:为已有应用创建CronHPA任务。

本文以为无状态应用创建定时伸缩任务为例,说明如何为已有应用创建CronHPA任务。

  1. 登录容器服务管理控制台
  2. 在控制台左侧导航栏中,单击集群
  3. 集群列表页面中,单击目标集群名称或者目标集群右侧操作列下的详情
  4. 在集群管理页左侧导航栏中,选择工作负载 > 无状态
  5. 无状态页面,单击应用右侧操作列下的详情
  6. 单击容器伸缩页签,配置定时伸缩任务。
    • 如果CronHPA组件未被安装,页面提示点击安装。单击点击安装后,然后进行以下步骤。
    • 如果CronHPA组件已被安装,直接进行以下步骤。
  7. 单击定时伸缩(CronHPA)右侧创建,然后在创建对话框中,设置定时伸缩任务的创建参数。create
    关于创建定时伸缩任务的配置信息,请参见上文的表 1

添加或修改定时伸缩任务

  1. 请参见上文的为已有应用创建CronHPA任务的步骤进入容器伸缩页面。
  2. 容器伸缩页签的定时伸缩(CronHPA)区域,单击目标任务右侧操作下的任务添加或编辑
  3. 编辑对话框中,单击添加任务进行任务创建或者点击已有CronHPA任务中进行修改,然后单击确定
    modify
您可以进行以下操作删除CronHPA任务。
  1. 编辑对话框中,单击任务名称右上角的删除图标,然后单击确定
    delete

定时伸缩CronHPA兼容HPA

定时伸缩CronHPA通过设置定时的方式触发容器的水平副本伸缩。为了防止突发的流量冲击等状况,您可能已经或者打算配置HPA保障应用的正常运行。如果同时检测到了HPA和CronHPA的存在,阿里云容器服务ACK会将HPA作为定时伸缩CronHPA的扩缩容对象,从而实现对该HPA定义的Deployment对象的定时扩缩容。

CronHPA和HPA的定义模板如下。

apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
  labels:
    controller-tools.k8s.io: "1.0"
  name: cronhpa-sample
spec:
   scaleTargetRef:
      apiVersion: apps/v1
      kind: Deployment
      name: nginx-deployment-basic
   jobs:
   - name: "scale-down"
     schedule: "30 */1 * * * *"
     targetSize: 1
   - name: "scale-up"
     schedule: "0 */1 * * * *"
     targetSize: 11	
	
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: php-apache
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-deployment-basic
  minReplicas: 4
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50	
	

对比上述CronHPA和HPA资源的定义模板,可以看出:
  • CronHPA和HPA都是通过scaleTargetRef字段来获取伸缩对象。
  • CronHPA通过jobscrontab规则定时伸缩副本数。
  • HPA通过资源利用率判断伸缩的情况。

设想如果同时设置CronHPA和HPA,那么会出现CronHPA和HPA同时操作一个scaleTargetRef的场景。因为CronHPA和HPA相互独立无法感知,所以就会出现两个Controller各自工作,后执行的操作会覆盖先执行的操作。

CronHPA和HPA的兼容解决方案

从上文可知,CronHPA和HPA同时使用会导致后执行的操作覆盖先执行操作的本质原因是两个controller无法相互感知,那么只需要让CronHPA感知HPA的当前状态就能解决冲突问题。HPA的定义将Deployment配置在scaleTargetRef字段下,然后Deployment通过自身定义查找ReplicaSet,最后通过ReplicaSet调整真实的副本数目。阿里云容器服务ACK将CronHPA中的scaleTargetRef设置为HPA对象,然后通过HPA对象来寻找真实的scaleTargetRef,从而让CronHPA感知HPA的当前状态。

cronhpa
CronHPA兼容HPA的定义模板如下。
apiVersion: autoscaling.alibabacloud.com/v1beta1
kind: CronHorizontalPodAutoscaler
metadata:
  labels:
    controller-tools.k8s.io: "1.0"
  name: cronhpa-sample
spec:
   scaleTargetRef:
      apiVersion: autoscaling/v1
      kind: HorizontalPodAutoscaler
      name:  nginx-deployment-basic-hpa
   jobs:
   - name: "scale-down"
     schedule: "30 */1 * * * *"
     targetSize: 1
     runOnce: true
   - name: "scale-up"
     schedule: "0 */1 * * * *"
     targetSize: 3
     runOnce: true

通过上述CronHPA的定义,CronHPA可以明确知晓HPA中的minReplicasmaxReplicasdesiredReplicas的数值,但是同时也知晓HPA中scaleTargetRef所对应的当前Relicas值。CronHPA会通过调整HPA的方式感知HPA。CronHPA通过识别要达到的副本数与当前副本数两者间的较大值,判断是否需要扩缩容及修改HPA的上限;CronHPA通过识别CronHPA要达到的副本数与HPA的配置间的较小值,判断是否需要修改HPA的下限。

以下根据不同的场景,解释CronHPA兼容HPA的规则。
HPA(min/max) Cronhpa Deployment 扩缩结果 兼容规则说明
1/10 5 5
  • HPA(min/max):1/10
  • Deployment:5
当CronHPA中的目标副本数和当前副本数一致时,HPA中的最大和最小副本数,还有应用当前的副本数无需变更。
1/10 4 5
  • HPA(min/max):1/10
  • Deployment:5
当CronHPA中的目标副本数低于当前副本数时,保留当前副本数。
1/10 6 5
  • HPA(min/max):6/10
  • Deployment:6
  • 当CronHPA中的目标副本数高于当前副本数时,保留CronHPA的目标副本数。
  • CronHPA目标副本数高于HPA副本数下限(minReplicas)时,修改HPA的副本数下限。
5/10 4 5
  • HPA(min/max):4/10
  • Deployment:5
  • 当CronHPA中的目标副本数低于当前副本数时,保留当前应用副本数。
  • CronHPA目标副本数低于HPA副本数下限(minReplicas)时,修改HPA的副本数下限。
5/10 11 5
  • HPA(min/max):11/11
  • Deployment:11
  • 当CronHPA中的目标副本数高于当前副本数时,保留CronHPA的目标副本数。
  • CronHPA目标副本数高于HPA副本数上限(maxReplicas)时,修改HPA的副本数上限。
表格中参数说明如下:
  • HPA(min/max):表示HPA定义中最小和最大的副本数值。
  • CronHPA:表示预期扩缩容的副本数。
  • Deployment:表示当前应用的副本数。

从上述看出,CronHPA不会直接调整Deployment的副本数目,而是通过HPA来操作Deployment,这样可以避免HPA和CronHPA的冲突问题。