前言
应用容器化改造后,不可避免地会面临这样一个问题:Kubernetes 集群的 Node 资源配置不足会导致 Pod 无法及时运行,购买过多的 Node 又会导致资源的闲置浪费。
那么如何利用 Kubernetes 的容器编排能力和云上资源的灵活性及规模化优势,来保证业务的高弹性、低成本?
本文主要探讨比心云平台如何利用阿里云容器服务 ACK,来构建应用弹性架构,进一步优化计算成本。
注意:文中的「Node」等同于节点。集群中的Node和集群中的节点,是一个意思。
弹性伸缩概述
弹性伸缩是根据业务需求和策略,经济地自动调整弹性计算资源的管理服务。
弹性伸缩可以分为两个维度:
- 调度层弹性,主要负责修改 Workload( 例如 Deployment ) 的调度容量变化。例如,HPA 是典型的调度层弹性组件,通过 HPA 可以调整应用的副本数,调整的副本数会改变当前 Workload 占用的调度容量,从而实现调度层的伸缩。
- 资源层弹性,主要是集群的容量规划不能满足集群调度容量时,会通过水平弹出 Node 的方式进行调度容量的补充。
两层的弹性组件与能力可以分开使用,也可以结合在一起使用,并且两者之间是通过调度层面的容量状态进行解耦。
Kubernetes 中共有三种不同的弹性伸缩策略:HPA(HorizontalPodAutoscaling)、 VPA(VerticalPodAutoscaling)与 CA(ClusterAutoscaler)。其中,HPA 和 VPA 的扩缩容对象是 Pod ,而 CA 的扩缩容对象是 Node 。
- HPA:调度层弹性组件,Kubernetes 内置,Pod 水平伸缩组件,主要面向在线业务。
- VPA:调度层弹性组件,Kubernetes 社区开源,Pod 垂直伸缩组件,主要面向大型单体应用。适用于无法水平扩展的应用,通常是在 Pod 出现异常恢复时生效。
- CA:资源层弹性组件,Kubernetes 社区开源,Node 水平伸缩组件。全场景适用。
另外各大云厂商(例如阿里云等)还提供了 Virtual Node 组件,提供无服务器运行时环境。用户无需关心 Node 资源,只需针对 Pod 按量付费即可。适用于在线流量突增、CI/CD、大数据作业等场景。本文在介绍 Virtual Node 时会以阿里云为例。
Pod 水平伸缩 HPA
HPA(Horizontal Pod Autoscaler)是 Kubernetes 的内置组件,也是最常用的 Pod 弹性方案。通过 HPA 可以自动调整 Workload 的副本数。HPA 自动伸缩特性使 Kubernetes 具有非常灵活的自适应能力,能够在用户设定内快速扩容多个 Pod 副本来应对业务负载的急剧飙升,也可以在业务负载变小的情况下根据实际情况适当缩容来节省计算资源给其他的服务,整个过程自动化无需人为干预,适合服务波动较大、服务数量多且需要频繁扩缩容的业务场景。
HPA 适用于 Deployment、StatefulSet 等实现 scale 接口的对象,不适用于无法扩缩的对象,例如 DaemonSet 资源。Kubernetes 内置有 HorizontalPodAutoscaler 资源,通常是对需要配置水平自动伸缩的 Workload 创建一个 HorizontalPodAutoscaler 资源,Workload 与 HorizontalPodAutoscaler 相对应 。
HPA 扩缩容流程
Pod 水平自动扩缩特性由 Kubernetes API 资源和控制器实现。资源利用指标决定控制器的行为,控制器会周期性的根据 Pod 资源利用情况调整服务 Pod 的副本数量,以使得工作负载的度量水平与用户所设定的目标值匹配。以 Deployment 和 CPU 使用率为例,其扩缩容流程如下图所示:
默认 HPA 只支持基于 CPU 和内存的自动伸缩,例如当 CPU 使用率超过阈值时就自动增加应用实例数,当 CPU 使用率又低于阈值时就自动减少实例数。
但是默认 HPA 驱动弹性的维度比较单一,并不能满足日常的运维需求。可以将 HPA 和开源的 Keda 结合使用,Keda 可以从事件、定时、自定义指标等维度来驱动弹性。
HPA 注意事项
- 如果设置了多个弹性伸缩指标,HPA 会依据各个指标,分别计算出目标副本数,取最大值进行扩缩容操作。
- 当指标类型选择为 CPU 利用率(占 Request)时,必须为容器设置 CPU Request。
- HPA 在计算目标副本数时会有一个 10% 的波动因子。如果在波动范围内,HPA 并不会调整副本数目。
- 如果服务对应的 Deployment.spec.replicas 值为 0,HPA 将不起作用。
- 如果对单个 Deployment 同时绑定多个 HPA ,则创建的 HPA 会同时生效,会造成工作负载的副本重复扩缩。
Pod 垂直伸缩 VPA
VPA(VerticalPodAutoscaling) 是社区开源组件,需要在 Kubernetes 集群上手动部署安装,VPA 提供垂直的 Pod 伸缩的功能。
VPA 会基于 Pod 的资源使用情况自动为 Pod 设置资源占用的限制,从而让集群将 Pod 调度到有足够资源的最佳节点上。VPA 也会保持最初容器定义中资源 request 和 limit 的占比。此外,VPA 可用于向用户推荐更合理的 Request,在保证容器有足够使用的资源的情况下,提升容器的资源利用率。
VPA 优势
相较于 HPA,VPA 具有以下优势:
- VPA 可为有状态应用实现扩容,HPA 则不适合有状态应用的水平扩容。
- 有些应用 Request 设置过大,缩容至一个 Pod 时资源利用率仍然很低,此时可以通过 VPA 进行垂直缩容以提高资源利用率。
VPA 限制
使用 VPA 有以下限制和注意事项:
- 更新正在运行的 Pod 资源配置是 VPA 的一项试验性功能,会导致 Pod 的重建和重启,而且有可能被调度到其他的 Node 上。
- VPA 不会驱逐没有在副本控制器管理下的 Pod。目前对于这类 Pod,Auto 模式等同于 Initial 模式。
- 目前 VPA 不能和监控 CPU 和内存度量的 HPA 同时运行,除非 HPA 只监控除 CPU 和内存以外的指标。
- VPA 使用 admission webhook 作为其准入控制器。如果集群中有其他的 admission webhook,需要确保它们不会与 VPA 发生冲突。准入控制器的执行顺序定义在 API Server 的配置参数中。
- VPA 会处理出现的绝大多数 OOM 的事件,但不保证所有的场景下都有效。
- VPA 的性能还没有在大型集群中测试过。
- VPA 对 Pod 资源 requests 的修改值可能超过实际的资源上限,例如 Node 资源上限、空闲资源或资源配额,从而造成 Pod 处于 Pending 状态无法被调度。同时使用集群自动伸缩( ClusterAutoscaler )可以一定程度上解决这个问题。
- 多个 VPA 同时匹配同一个 Pod 会造成未定义的行为。
Node 水平伸缩 CA
HPA 和 VPA 都是调度层的弹性,解决了 Pod 的弹性伸缩。如果集群整体的资源容量不能满足集群调度容量时,HPA 和 VPA 弹出的 Pod 还是会处于 Pending 状态。这时就需要资源层的弹性伸缩。
在 Kubernetes 中,Node 自动水平伸缩是通过社区开源的 CA(ClusterAutoscaler) 组件实现的。社区 CA 支持设置多个伸缩组,支持设置扩容和缩容策略。各大云厂商在社区 CA 的基础上会加入一些特有的功能,例如支持多可用区、多实例规格、多种伸缩模式等ÿ