k8s多维度自动弹性伸缩

47,745 阅读7分钟

一、背景

1.1 什么是弹性伸缩

根据用户的业务需求和策略,自动调整其弹性计算资源的管理服务,其优势有:

  • 从应用开发者的角度:能够让应用程序开发者专注实现业务功能,无需过多考虑系统层资源
  • 从系统运维者的角度:极大的降低运维负担, 如果系统设计合理可以实现“零运维”
  • 从管理者角度:极大降低成本
  • 是实现 Serverless 架构的基石,也是 Serverless 的主要特性之一

1.2 k8s 自动弹性伸缩功能包括

  • Pod 水平自动伸缩,HPA,Horizontal Pod Autoscaler
  • Pod 垂直自动伸缩,VPA,Vertical Pod Autoscaler
  • 集群自动伸缩,CA,Cluster Autoscaler。后续会针对CA做源码分析。

1.3 HPA

  • 负责调整 pod 的副本数量来实现。是最常用的弹性伸缩组件
  • 解决的是业务负载波动较大的问题
  • 依赖 metrics-server 组件收集 pod 上的 metrics,然后根据预先设定的伸缩策略决定扩缩容 pod
  • metrics-server 默认只支持基于 cpu、memory 监控指标伸缩策略
  • 如果要使用自定义指标(比如 QPS)作为伸缩策略,需要额外安装 prometheus-adapter,将自定义指标转换为 k8s apiserver可以识别的指标
  • HPA-Controller 在k8s默认的 controller-manager 中已经安装

1.4 VPA

  • 负责调整单个 pod 的资源限额 request、limit 实现
  • 解决的是资源配额评估不准的问题
  • 依赖历史负载指标,自动计算或调整资源配额
  • VPA-Controller 需要额外安装,参考

1.5 CA

  • 负责调整 k8s node 节点数量实现集群级别的扩缩容
  • 依赖底层 IaaS 层的弹性伸缩能力
  • CA-Controller 需要额外安装,参考

1.6 三者使用场景

  • VPA 用的比较少
  • HPA 用的比较多,流量变化触发 HPA,新增或减少 pod
  • Pod变化如果触发 pending或资源不足,会触发 CA的自动扩缩容

二、HPA

2.1 架构

参考

  • k8s 提供了一种标准 metrics 接口
  • HPA Controller 通过这个统一 metrics 接口可以查下到任意一个 HPA对象关联的 metrics 数据
  • 查询 metrics 的接口是通过 apiserver 的聚合层转发到后端真实的 metric-server 和 prometheus-adapter

参考

2.2 原生指标

  • 最早 metrics 数据由 metric-server 提供,只支持 cpu 和 memory 作为指标
  • 通过采集 Node、kubelet 数据汇总到本地
  • 没有持久化,保存在内存

2.4 自定义指标

  • 为了适应更灵活的需求,metrics APi 开始支持扩展用户自定义指标 custom metrics
  • 需要自行开发 custom metrics server,社区提供开发框架 custom-metrics-apiserver
  • 社区还提供了更通用的 promethus adapter 适配自定义指标已经存在 prometheus 中的情况
  • prometheus 几乎是监控标准,因此 prometheus-adapter几乎可以满足所有自定义指标需求

2.5 原理

  • 用户在 HPA 里设置 metrics 类型和期望的目标 metrics 数值
  • HPA Controller 定期(默认15s)reconcile 每个 HPA 对象
  • reconcile 里通过 metrics 的 API 获取该 HPA 的 metrics 实时最新数值,并与目标值比较,确定扩缩容方向
  • 计算出 Deployment 的目标副本数,最后调用 Deployment 的 scale 接口调整副本数
  • 存在多个指标时,最终会选择扩缩容幅度最大的那个为最终副本数
  • 扩容有一定阈值
  • 缩容要超过一定冷却器(默认5min)

2.6 metrics 的分类

最新版 HPA:autoscaling/v2beta1,有四种类型的 metrics

  • Resource:支持k8s所有系统资源,包括cpu、memory。一般只用cpu,memory不准确。
  • Pods:由 pod 自身提供的自定义 metrics 数据
  • Object:监控指标部署由 pod 本身的服务提供,比如 Ingress
  • External:来自外部系统的自定义指标

2.7 使用示例

  • scaleTargetRef:针对哪个负载进行HPA,几乎只会用于 Deployment 对象

  • minReplicas:缩容的最小值

  • maxReplicas:扩容的最大值

  • type:前面介绍的4中之一,这里使用 Resource

  • resource.target.type:

    • Utilization:百分比
    • AveragetValue:平均值
    • Value:精确值
apiVersion: autoscaling/v2beta2
kind: HorizontalPodAutoscaler
metadata:
  name: hpa-test
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

2.8 缺点

使用 HPA 能满足一些场景,但是也存在一些缺点:

  • 弹性不够及时:pod启动、预热需要一定时间
  • 如何配置 HPA不好把控
  • 不支持 Dryrun,一点修改就会实际修改实例数量

可以参考腾讯开源的 EHPA,实现智能 HPA。

三、VPA

3.1 架构

参考

VPA 包含以下组件:

  • History Storage:通过 metrics api采集和存储监控数据
  • Recommender:根据监控指标(History Storage)结合内置机制给出资源建议值
  • Updater:实时更新 pod resource requests,监听 VPA API,根据建议值动态修改 pod 资源
  • VPA Admission Controller:用于 pod 创建时修改 request、limit

vpa

3.2 流程说明

  • vpa 连接检查 pod 在运行过程中占用的资源,默认间隔为10s一次
  • 当发现 pod 资源占用到达阈值时,vpa会尝试更改分配的内存或cpu
  • vpa尝试更新部署组件中的pod资源定义
  • pod重启,新资源将应用于创建出来的实例

3.3 运行模式

vpa 支持4中更新策略:

  • Initial:仅在 pod 创建时修改,以后都不再修改
  • Auto:默认策略,pod创建时、pod更改时都会修改
  • Recreate:类似 Auto,在 Pod 的创建和更新时都会修改资源请求,不同的是,只要Pod 中的请求值与新的推荐值不同,VPA 都会驱逐该 Pod,然后使用新的推荐值重新启一个。因此,一般不使用该策略,而是使用 Auto,除非你真的需要保证请求值是最新的推荐值。
  • Off:不改变 Pod 的资源请求,不过仍然会在 VPA 中设置资源的推荐值

3.4 使用注意

  • 同一个 deployment,不能同时使用 hpa 和 vpa
  • vpa 更新资源会导致 pod 重建、重启、甚至重新调度
  • vpa 使用 admission webhook ,需要确保与其他 webhook 不冲突
  • vpa的性能没有在大型集群中测试过
  • vap建议值可能超过实际资源上限,从而导致pod处于pending无法被调度
  • 多个 vpa 同时配置同一个pod会造成未定义的行为
  • vpa不支持扩展控制器

3.5 总结

  • 使用的场景太少,重启 pod业务不可接受
  • 没有大规模场景验证,一般不太会用这个功能

四、CA

4.1 架构

参考

CA由一下几个模块组成:

  • autoscaler:核心模块,负责整体扩缩容功能
  • Estimator:负责评估计算扩容节点
  • Simulator:负责模拟调度,计算缩容节点
  • Cloud Provider:与云上 IaaS 层交互,负责增删改查节点。云厂商需要实现相关接口。

CA

4.2 扩缩容的时机

参考ca官方说明

  • pod 因资源不足 pending,触发扩容。不可调度后最多 10s 可以触发扩容
  • node 资源利用率低,且 node 上所有 pod 都能调度到其他 node 上。节点不可用后 10min 开始缩容
  • 可以在启动时关闭缩容功能

4.3 哪些pod会阻止CA缩容Node

  • 节点上有pod被PodDisruptionBudget控制器限制。
  • 节点上有命名空间是kube-system的pods。
  • 节点上的pod不是被控制器创建,例如不是被deployment, replica set, job, stateful set创建。
  • 节点上有pod使用了本地存储
  • 节点上pod驱逐后无处可去,即没有其他node能调度这个pod
  • 节点有注解:"cluster-autoscaler.kubernetes.io/safe-to-evict": "false"

4.4 配置某些Node禁止缩容

为节点添加特殊标签: "cluster-autoscaler.kubernetes.io/scale-down-disabled": "true"

kubectl annotate node <nodename> cluster-autoscaler.kubernetes.io/scale-down-disabled=true

五、HPA + CA结合有多快

5.1 影响因素

当 CA 和 HPA 结合使用时,从负载增加到新 pod 运行的总时间主要由三个因素决定:

  • HPA 反应时间
  • CA 反应时间
  • 节点创建时间

5.2 时间分析

具体每一环节的默认时间:

  • kubelet 每隔 10s 对 pod 的 cpu 使用率指标进行抓取
  • Metric server 每隔 1min 从 kubelet 获取数据
  • HPA 每隔 30s 检查一次 Metric server 中的 CPU 负载指标
  • CA 检查到 pod pending 最多 10s 触发扩容

5.3 具体数值

扩容最终时间:

  • 做出扩容决定:预计大多数情况不到 30s
  • 开出机器并且 pod 调度成功:取决于云厂商,GCE一般是3~4min

缩容最终时间:

  • 仅缩容pod:取决于 HPA 的缩容冷却时间,默认好像是5min
  • 缩容Node:CA的冷却时间是10min

六、总结

本文针对 k8s 集群扩容的背景、价值、实现做了大概的介绍,HPA 默认就可以使用,CA需要额外安装组件使用,而VPA使用较少。我司正是使用了 HPA + CA的组合来实现联动扩缩容,后续会做源码级分析,敬请期待。

\