将 AWS Graviton 与 x86 CPU 混合以优化成本和弹性,使用 Amazon EKS
  • 17

结合 AWS Graviton 与 x86 CPU 优化成本与弹性

关键要点

本文介绍如何将基于 AWS Graviton 的 Amazon EC2 实例与现有的 x86 基础 Amazon EKS 环境集成,以实现更好的应用程序弹性和成本优化。推荐在生产环境之前先在测试环境中验证应用程序性能。采用 KEDA 控制不同 CPU 类型的应用程序容量,并使用 Karpenter 实现节点自动供应。

本文由 Yahav Biran首席解决方案架构师和 Yuval Dovrat以色列计算服务主管撰写。

本文展示了如何将基于 AWS Graviton 的 Amazon EC2 实例集成到一个运行于 x86 基础的Amazon 弹性 Kubernetes 服务 (Amazon EKS)环境中。客户通过混合 CPU 架构来使他们的应用程序能够利用广泛的 Amazon EC2 实例类型,并提高整体应用程序的弹性。为了成功运行混合 CPU 应用程序,强烈建议在将生产应用程序部署到 Graviton 实例上之前,在测试环境中验证应用程序性能。您可以参考 AWS 的迁移指南了解更多关于将您的应用程序迁移到 AWS Graviton 的信息。

以下是一个例子,展示如何使用KEDA来控制 EKS 不同 CPU 类型的应用容量。KEDA 会根据应用程序的响应延迟通过应用加载均衡器进行测量触发部署。为了简化资源配置,还展示了开源的 Kubernetes 节点供应工具Karpenter和AWS 负载均衡器控制器的使用。

解决方案概述

本文涵盖了两种测试混合 CPU 应用程序的解决方案。第一个配置见下面的图 1是“A/B 配置”。该配置使用基于应用负载均衡器 (ALB) 的 Ingress 控制流向 x86 和 Graviton 节点池的流量。您可以使用此配置逐步将现有应用程序从 x86 实例迁移到 Graviton 实例,同时通过Amazon CloudWatch验证响应时间。

图 1 A/B 配置

风驰加速器app官网

第二个配置是“Karpenter 控制配置”在下面的图 2 中显示为配置 2,Karpenter 会自动控制实例混合。Karpenter 配置为使用加权配置器,该加权配置器优先选择基于 AWS Graviton 的 Amazon EC2 实例,而非基于 x86 的 Amazon EC2 实例。

图 2 Karpenter 控制配置

建议您首先使用“A/B”配置来测量实时请求的响应时间。一旦验证了 Graviton 实例上的工作负载,您便可以构建第二个配置以简化部署配置并提高弹性。这使得您的应用程序在需要时能够自动利用 x86 实例,例如在未计划的大规模事件期间。

您可以在 GitHub 上找到完整的逐步指南,以帮助您检查和尝试本文中描述的示例应用程序部署。以下是逐步指南的概述。

代码迁移到 AWS Graviton

第一步是将代码从基于 x86 的实例迁移到 Graviton 基础的实例。AWS 提供了多个资源来帮助您迁移代码,包括AWS Graviton 快速启动计划、AWS Graviton 技术指南 GitHub 存储库、AWS Graviton 迁移指南,以及Graviton 移植顾问。

在进行任何必要更改之后,您可能需要针对 Arm64 架构重新编译您的应用程序。如果您的应用程序是用编译为机器代码的语言如 Golang 和 C/C编写的,或者需要为解释型/JIT 编译语言如Python/C API或Java 本地接口 (JNI)重新构建原生代码库,则需要执行此操作。

为了使您的容器化应用程序能够在 x86 和 Graviton 节点上运行,您必须为 x86 和 Arm64 架构构建 OCI 镜像,将它们推送到您的镜像存储库如 Amazon ECR,并通过创建和推送 OCI 多架构清单列表将它们组合在一起。您可以在这篇AWS 博客文章中找到这些步骤的概述。您还可以在 GitHub 上找到适用于 AWS Cloud Development Kit (CDK) 的构造来帮助您入门。

将 AWS Graviton 与 x86 CPU 混合以优化成本和弹性,使用 Amazon EKS

为简化流程,您可以使用支持跨平台软件包的 Linux 发行版包管理器,并尽量避免在 Linux 发行版中使用特定于平台的软件包名称。例如,使用:

bashRUN pip install httpd

而不是:

bashARG ARCH=aarch64 or amd64 RUN yum install httpd{ARCH}

这篇博客文章更深入地介绍了如何自动化构建多架构 OCI 镜像的过程。

应用程序部署

配置 1 A/B 控制拓扑

这种拓扑允许您在验证应用程序在 x86 和 Graviton 实例上的响应时间约 300ms的同时迁移到 Graviton。图 1 显示了这种设计具有一个单一的监听器,将传入请求转发至两个目标组。其中一个目标组与 Graviton 实例相关联,而另一个目标组则与 x86 实例相关联。与每个目标组相关的流量比在 Ingress 配置中进行定义。

以下是创建配置 1 的步骤:

创建两个 KEDA ScaledObjects,根据延迟指标AWS/ApplicationELBTargetResponseTime扩缩 pods 数量,以符合目标组triggersmetadatadimensionValue。声明可接受的最大延迟为 targetMetricValue03。下面是Graviton 部署的 scaledObject (specscaleTargetRef),注意注释部分标注了x86 部署的 scaledObject。

yamlapiVersion kedash/v1alpha1kind ScaledObjectspec scaleTargetRef apiVersion apps/v1 kind Deployment name armsimplemultiarchapp #amdsimplemultiarchapp triggers type awscloudwatch metadata namespace AWS/ApplicationELB dimensionName LoadBalancer dimensionValue app/simplemultiarchapp/xxxxxx metricName TargetResponseTime targetMetricValue 03

一旦拓扑创建完成,添加Amazon CloudWatch 容器洞察以测量 CPU、网络吞吐量和实例性能。为简化测试并控制潜在的实例代间性能差异,创建两个专用的 Karpenter 配置器和 Kubernetes 部署副本集,并为每个配置指定实例代间、CPU 数量和 CPU 架构。本示例使用c7g (Graviton3)和c6i (Intel)。您将在下一个拓扑中删除这些限制,以允许更多的分配灵活性。

x86 基础实例的 Karpenter 配置器

yamlapiVersion karpentersh/v1alpha5kind Provisionermetadata name x86provisionerspec requirements key karpenterk8saws/instancegeneration operator In values 6 key karpenterk8saws/instancecpu operator In values 2 key kubernetesio/arch operator In values amd64

Graviton 基础实例的 Karpenter 配置器

yamlapiVersion karpentersh/v1alpha5kind Provisionermetadata name arm64provisionerspec requirements key karpenterk8saws/instancegeneration operator In values 7 key karpenterk8saws/instancecpu operator In values 2 key kubernetesio/arch operator In values arm64

创建两个 Kubernetes Deployment 资源每个 CPU 架构一个使用 nodeSelector 将一个 Deployment 调度到 Graviton 基础实例上,另一个则针对 x86 基础实例](https//githubcom/awssamples/apphealthwithawsloadbalancercontroller/blob/main/simplemultiarchapp/appamddeployyaml)。类似地,创建两个 NodePort 服务资源,其中每个服务指向其架构特定的副本集。创建一个应用程序负载均衡器使用AWS 负载均衡器控制器来分发传入请求到不同的 pods。在 ingress 中添加一个ingresskubernetesio/actionsweightedrouting 注释来控制流量路由。您可以根据需要调整下例中的权重。这个迁移例子从1000的 x86 到 Graviton 率开始,并逐渐调整至10的增量,直到达到0100的比例。

yamlalbingresskubernetesio/actionsweightedrouting { targetGroups[ { serviceNamearmsimplemultiarchappsvc servicePort80weight50 } { serviceNameamdsimplemultiarchappsvc servicePort80weight50 }] }}

spec ingressClassName alb rules http paths path / pathType Prefix backend service name weightedrouting

您可以模拟实时用户请求到示例应用程序的 ALB 端点。Amazon CloudWatch 将填充 ALB 目标组请求/秒度量,按HTTP 响应代码维度,以帮助评估应用程序的吞吐量和 CPU 使用情况。

在仿真过程中,您需要确认以下几点:

Graviton 和 x86 基础实例的 pods 处理不同量的流量。应用程序响应时间 (p99) 满足性能要求300ms。

HTTP 2xx 响应的橙色Graviton和蓝色x86曲线图 4显示了每种 CPU 架构在迁移过程中的应用程序吞吐量HTTP 请求/秒。

图 3 每种 CPU 架构的 HTTP 2XX

图 4 显示了 x86 基础实例向 Graviton 基础实例迁移过程中的应用程序响应时间示例。与每个实例族相关的延迟随着实时请求仿真变化而增减。在这个示例中,x86 实例的延迟直到 0700增长到 300ms,因为大多数请求负载被导向 x86 基础的 pods。大约在 0800 时开始趋于一致,因为更多的 pods 被转换为 Graviton 基础实例。最后,在 1500 之后,请求负载完全由 Graviton 基础实例处理。

图 4 p99 目标响应时间

配置 2 Karpenter 控制配置

在完全测试应用程序在 Graviton 基础的 EC2 实例上的表现后,您可以通过使用加权配置器简化部署拓扑,同时保留按需启动 x86 基础实例的能力。

以下是创建配置 2 的步骤:

重用上一拓扑中的基于 CPU 的配置器,但为 Graviton 基础实例配置器分配更高的 specweight。仍然部署 x86 配置器以防需要 x86 基础实例。karpenterk8saws/instancefamily 可扩大到配置 1 中设置的范围之外,或通过将操作符切换为 NotIn 来排除。

x86 基础 Amazon EC2 实例的 Karpenter 配置器:

yamlapiVersion karpentersh/v1alpha5kind Provisionermetadata name x86provisionerspec requirements key kubernetesio/arch operator In values [amd64]

Graviton 基础 Amazon EC2 实例的 Karpenter 配置器:

yamlapiVersion karpentersh/v1alpha5kind Provisionermetadata name priorityarm64provisionerspec weight 10 requirements key kubernetesio/arch operator In values [arm64]

接下来,将两个 Kubernetes 部署合并为一个部署,类似于迁移前的原始配置即,没有指向特定 CPU 配置器的nodeSelector。

这两个服务还合并为一个单一的 Kubernetes 服务,并从 ingress 资源中移除了 actionsweightedrouting 注释:

yamlspec rules http paths path /app pathType Prefix backend service name simplemultiarchappsvc

将来自第一个配置的两个 KEDA ScaledObject 资源合并,并指向一个单一部署,例如 simplemultiarchapp。新的KEDA ScaledObject 将是:

yaml