一、背景
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
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 层交互,负责增删改查节点。云厂商需要实现相关接口。
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"
代码语言:javascript复制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的组合来实现联动扩缩容,后续会做源码级分析,敬请期待。