亚马逊AWS官方博客

立足 AWS 对 Kubernetes 进行成本优化

Original URL: https://aws.amazon.com/cn/blogs/containers/cost-optimization-for-kubernetes-on-aws/

 

感谢AWS容器技术先锋、Liatrio工程技术总监Casey Lee为本文编写做出的贡献。

将Amazon EKS提供的全托管Kubernetes控制平面,与运行在Amazon EC2上弹性的Kubernetes工作节点组合起来,就构成了一套理想的容器化工作负载运行环境。这不仅使构建者能够快速创建出Kubernetes集群,同时也能够按需扩展集群,支持灵活多变的业务需求。但正确的选择只是成功的第一步,我们还需要充分考量AWS Well-Architected Framework中提出的成本优化支柱原则。

Kubernetes集群的总体运行成本涉及了许多服务。EKS控制平面是其中最易于理解的部分,固定成本为每小时0.20美元。接下来,我们还需要有EC2实例用作Kubernetes集群的工作节点。而EC2实例的成本涉及多个方面,除了计算成本还包括块存储与数据传输两部分。而这两项成本与实际的工作负载高度相关,所以本文暂时不做深入讨论。换个角度,本文将深入研究EC2成本中最大的两个方面:实例运行小时数和实例价格。

EC2成本=实例运行小时数 x 实例价格

在Kubernetes集群当中,实例运行小时数与集群内的Pod数量、以及分配给这些Pod的对应资源成正比。

实例运行小时数=Pod运行小时数 x Pod对应资源

在本文中,我们将通过一下四种技术了解如何将EC2的资源使用成本降低80%甚至更高:

  • Auto Scaling(规模自动伸缩)——通过使集群内的节点和pod数量与需求保持一致,以优化实例运行时间。
  • Right Sizing (正确调整大小)——通过为各Pod分配适当的CPU与内存资源,以优化Pod资源。
  • Down Scaling(规模缩减)——在夜间及周末等非必要时段关闭Pod以优化Pod运行小时数。
  • Purchase Options(购买选项)——利用竞价实例替代按需实例,以优化实例价格。

Auto Scaling(规模自动伸缩)

AWS良好架构框架中的成本优化支柱,通过专门的章节讨论了“供需匹配”这部分内容,相关建议如下:

“……(供需匹配)可通过Auto Scaling实现,它可以帮助您根据定义的条件自动扩展或缩减EC2实例和Spot Fleet的容量。”

因此,在Kubernetes集群上进行成本优化的先决条件是确保您已经在集群之上使用了Cluster Autoscaler。这款工具能够在Kubernetes集群中执行两项关键功能:第一,它会监控集群中那些由于资源分配不足而无法正常运行的Pod。一旦出现这样的情况,Cluster Autoscaler都会自动更新Amazon EC2 弹性伸缩组,从而在集群当中增加一定数量的节点。第二,Cluster Autoscaler会检测资源利用率较低的节点,并将其中的Pod调度到其他节点之上。接下来,Cluster Autoscaler会自动缩减Auto Scaling组所需的节点数量,实现集群规模缩减。

Amazon EKS用户指南对Cluster Autoscaler的使用方式做出了详尽介绍。在配置Cluster Autoscaler时,大家需要注意以下几点:

服务账户的IAM角色——Cluster Autoscaler需要具备对应的访问权限,才能更新Auto Scaling组中的必要容量参数。推荐的方法是根据所需的策略及信任策略创建一个新的IAM角色,借此限制Cluster Autoscaler对于服务账户的访问权限。另外,请务必在服务账户上标注该角色的名称:

apiVersion: v1
kind: ServiceAccount
metadata:
  name: cluster-autoscaler
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::000000000000:role/my_role_name

当Cluster Autoscaler进行横向扩展时,它会直接增加Auto Scaling组内的节点数量,而启动新EC2实例的实际任务将由AWS弹性伸缩服务负责执行。如果在多个可用区内都配置了弹性伸缩组,则可以在这些可用区内启动新的实例。

对于使用持久存储卷的部署方案,我们需要在各个可用区内建立一个独立的Auto Scaling组。这样,当Cluster Autoscaler检测到需要对特定Pod进行横向扩展的情况时,即可根据当前可用区内已经存在的持久存储卷声明为接下来的扩展节点操作指定正确的可用区。

在使用多个Auto Scaling组时,请确保在Cluster Autoscaler的Pod规范中启用以下参数:

--balance-similar-node-groups=true

到目前位置,Cluster Autoscaler已经可以在集群当中正常运行,实例运行时间(Instance Hours)也将始终与集群内的Pod资源需求量紧密匹配。下一步是根据特定的Pod指标使用Horizontal Pod Autoscaler (HPA)对Pod数量进行横向扩展或缩减,借此优化Pod运行小时数(Pod Hours)以进一步优化我们的实例运行小时数。

Kubernetes已经提供了HPA控制器,因此配置HPA时只需要考虑一项前提,即确保已经将Kubernetes指标服务器部署在您的集群中,然后在您的部署中定义HPA资源。例如,以下定义的HPA资源配置将持续监控名为nginx-ingress-controller的部署的CPU使用率。接下来,HPA将在1到5之间扩缩Pod数量,以确保所有Pod的平均CPU使用率都能达到80%:

apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
  name: nginx-ingress-controller
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: nginx-ingress-controller
  minReplicas: 1
  maxReplicas: 5
  targetCPUUtilizationPercentage: 80

把Cluster Autoscaler与Horizontal Pod Autoscaler相结合,能够帮助我们将EC2实例小时数与集群内所运行工作负载的资源利用率尽可能统一起来。

Right sizing(正确调整大小)

回到AWS良好架构框架中的成本优化支柱部分,在其中的“成本效益资源”章节处,对Right Sizing的定义为:

“……使用成本最低的资源,同时仍然满足特定工作负载的技术规格要求。

使用Kubernetes,我们可以随时对Pod内容器的计算、CPU与内存资源进行大小调整,借此找到最合理的配额水平。各个Pod中的容器对于所能够使用的CPU与内存资源都有着一定的要求及限制。

请谨慎尝试,并保证这些资源的实际使用率与业务需求尽量匹配。如果设定的值太低,则容器可能存在资源不足并影响实际业务性能。而如果设定的值过高,则会浪费大量资源,导致各容器中都存在一部分未得到使用的资源。在实际利用率低于资源必要值时,我们将二者之间的差额称为闲置成本(slack cost)。以kube-resource-report为代表的多种工具能够对闲置成本进行可视化,同时正确判断Pod内的容器资源需求。在安装说明部分,我们可以通过以下helm图表了解如何安装这款工具:

$ helm upgrade --install kube-resource-report chart/kube-resource-report.

如以上图所示,像Jenkins这类应用能够显著降低CPU与内存需求,每月可以节约高达66.53美元的闲置成本。而在对Kubernetes集群内所有应用程序正确调整Pod资源大小之后,我们实现了20%的成本节约,具体如下图所示。

Down scaling(规模缩减)

除了根据需求的自动扩展之外,AWS良好架构框架成本优化支柱中的供需匹配章节还提出以下建议:

可以安排系统在特定时间(例如工作日营业时间开始时)按预定义进行规模伸缩,借此保证资源始终与用户需求相匹配。”

在示例集群中,有相当一部分部署方案只需要在营业时段之内运行。我们可以将kube-downscaler工具部署在集群上,借此根据一天中的时间对集群资源进行规模伸缩。下面,我们通过环境变量为kube-downscaler配置默认运行时间:

DEFAULT_UPTIME = Mon-Fri 05:00-19:00 America/Los_Angeles

在这种情况下,周一至周五上午5:00至下午7:00以外的所有时间段,集群所有部署节点资源大小都将设置为0。通过annotation标注,名称空间与部署可以根据业务需求来自定义他们的启停时间。主要通过设置downscaler/uptime标注来自定义启停时间,甚至可以通过设置downscaler/exclude标注来禁用该功能。

如下图所示:

Amazon CloudWatch – EC2实例数量Grafana – 集群CPU资源使用率

各EC2实例在启用规模缩减之后,我们可以减少Pod运行小时数,并借此达成15%的额外资源节约比例,具体如下图所示。

购买选项

AWS良好架构框架成本优化支柱中的最后一部分为“购买选项”,相关建议如下:

竞价实例使您以远低于按需EC2实例的成本(最高节约比例达90%)使用AWS中的备用计算资源。

在EC2控制台中查看竞价实例的价格历史记录时,我们发现m5.large类型的竞价实例,在实际使用成本上始终比按需实例低55%至60%。

要将您的节点设定为在竞价实例(而非按需实例)上运行,请参阅题为《配合Amazon EKS,在Amazon EC2竞价实例上运行您的Kubernetes工作负载(Run your Kubernetes Workloads on Amazon EC2 Spot Instances with Amazon EKS)》的AWS Compute博文。需要注意的是,此文在示例中安装了kube-spot-termination-notice-handler工具以运行自定义终止处理程序。这是一项故障转移功能,用于在竞价实例发生服务中断时,将各Pod安全转移至其他节点。

除了由竞价实例组成的Auto Scaling组之外,对于无法容忍实例意外中断的各类Pod,大多数集群还会为其保留一套由按需实例构成的Auto Scaling组。在配置这些节点时,请注意向各Auto Scaling组内的kubelet传递额外参数,借此将各节点标记为essential或者preemptible

  • Essential: --node-labels=kubernetes.io/lifecycle=essential
  • Preemptible: --node-labels=kubernetes.io/lifecycle=preemptible

接下来,我们可以在容器规范中使用node affinity,以确保在适当的节点上调度容器:

affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: "kubernetes.io/lifecycle"
operator: "In"
values:
- essential

在将大多数节点转移至竞价实例之后,我们能够降低实例的运行成本,实现了40%的额外费用节约,如下图所示。请注意,面向竞价实例的转移不会对使用方式造成影响,只是大幅降低了资源使用费率。

总结

通过自动扩缩集群中节点及Pod,正确调整分配给Pod中容器的资源的大小,缩减业务时段以外的部署规模,并将大部分Pod转移至竞价实例,能够为Kubernetes集群节省超过80%的EC2实例成本。这四种重要的方式,均来自AWS良好架构构架中成本优化支柱原则所提到的最佳实践。事实也再次证明,这些建议确实能够帮助客户以更节省和更高效地方式在EKS中运行Kubernetes工作负载。

 

本篇作者

Isabel Macaulay