亚马逊AWS官方博客

Amazon EKS 基于 Spot 运行大规模计算任务架构调优实践

概述

Amazon EKS 是一项托管的 Kubernetes 服务,且经过认证与 Kubernetes 一致,因此上游 Kubernetes 上运行的现有应用程序可与 Amazon EKS 兼容。出于其安全性、可靠性和可扩展性,在各个行业和领域,EKS 是运行 Kubernetes 的最佳平台。

我们看到在医药行业和自动驾驶领域利用 EKS + Spot 的组合方案去做海量的数据处理计算任务,他们的特点就是利用 EKS 集群 Spot 计算节点做任务处理,并且 EKS 的工作节点不需要常驻,每次调度的计算任务量级巨大。本文就是针对类似场景,给出 EKS + Spot 集群做频繁节点调度时的一些最佳实践。

架构示意图

这里给出 EKS + Spot 常用架构示意图,我们可以看到,为了实现节点组的自动扩缩容,需要安装 Cluster Autoscaler 支持根据Pod 数量去动态调整 Node 数量,在一些业务场景中,我们还需要安装 EKS Node Termination Handler 去捕获 Spot Termination Notification 做自定义的业务处理。

调优实践

本文结合实际应用场景的测试调优过程,给出一些可以更好使用 EKS Spot 的实践参考。

使用多种 Spot 机型

EKS NodeGroup 支持多种 Spot 机型调度,每个 EC2 Spot 机型在每个 Region 的每个 Availability Zone 都有独立的 Capacity Pool ,同时配置多种 Spot 机型可以增加获取成功率。

节点组 Spot 获取策略

EKS NodeGroup 设置 Spot 机型获取策略建议选择 capacity-optimized,这个策略是会按照指定的多种机型在不同AZ的 Capacity Pool 的大小,优先提供最多容量的 Spot 机型去获取。以下给出参考的 yaml 配置。

# cluster-nodegroup.yaml 文件
$ vim cluster-nodegroup.yaml
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
    name: eks-test
    region: cn-northwest-1
nodeGroups:
    - name: test-ng-1
      ami: ami-063b63a893ab19ebb 
      minSize: 1
      maxSize: 5
      desiredCapacity: 1
      instancesDistribution:
        instanceTypes: ["m5.large", "m5d.large", "m4.large"] # 多种机型
        onDemandBaseCapacity: 0
        onDemandPercentageAboveBaseCapacity: 0
        spotAllocationStrategy: capacity-optimized # 容量优化获取Spot策略
      ssh:
        allow: true
        publicKeyName: ec2_key_pair
      labels:
        lifecycle: Ec2Spot
        intent: apps
        aws.amazon.com/spot: "true"
      taints:
        spotInstance: "true:PreferNoSchedule"
      tags:
        k8s.io/cluster-autoscaler/node-template/label/lifecycle: Ec2Spot
        k8s.io/cluster-autoscaler/node-template/label/intent: apps
        k8s.io/cluster-autoscaler/node-template/label/aws.amazon.com/spot: "true"
        k8s.io/cluster-autoscaler/node-template/taint/spotInstance: "true:PreferNoSchedule"
      iam:
        withAddonPolicies:
          autoScaler: true
          cloudWatch: true
          albIngress: true

EKS 集群预留足够的 IP

EKS VPC CNI 支持 Kubernetes Pod 具有与其在 Amazon VPC 网络上相同的 IP 地址,也就是说 EKS 集群中的 Pod 可以与 EC2 一样去获取 VPC CIRD 的私有 IP,可以很方便的进行相互的网络访问。如果我们在 EKS 中运行大规模的 Pod,需要为 EKS 使用的子网预留足够的 CIRD 段。Amazon VPC 最高支持 /16 的网段,意味着在一个 EKS 集群最多可以创建超过 6万个Pod。

优化 CNI 插件参数

Amazon VPC CNI 支持 EKS 对 VPC IP 地址的获取,EKS Node 节点的 EC2(Spot)的不同实例类型,支持的 ENI 个数和 Secondary IP 个数是不相同的,我们可以参考 EC2 可用 ENI/Secondary IP 去计算每个Node 上可以运行的 Pod 数量。如下图一个 m5.4xlarge 机型的 ENI 和 Secondary IP 数量计算示例。

为了提升 Pod 启动速度,Amazon VPC CNI 插件会在 Node 启动后,为每个 Node 准备 IP 热池,默认会准备一个 ENI + 10个Secondary IP,我们可以根据 Node 上预估的 Pod 数量,优化 WARMENITARGET、WARMIPTARGET和MINIMUMIPTARGET 这三个参数的设置。预置 ENI 和 Secondary IP 的数量太多或者太少都会影响性能,我们需要结合业务需求进行具体的设置。以下介绍如何修改 CNI 配置,CNI 插件作为 DaemonSet 部署为 aws-node,我们可以直接编辑相关配置。

 # 默认每个 Node 会有两个DaemonSet,aws-node 和 kube-proxy
$ kubectl get ds -n kube-system
NAME           DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR            AGE
aws-node       4         4         4       4            4           <none>                   65d
kube-proxy     4         4         4       4            4           <none>                   65d

# 编辑 aws-node 
$ kubectl edit ds/aws-node -n kube-system

# 搜索 WARM_ENI_TARGET 关键字,配置三个参数设置
# 以下配置代表默认使用一个 ENI,每个 ENI 最少初始化 3个 IP,始终保持 1个 IP的预热个数
- "name": "WARM_ENI_TARGET"
  "value": "1"
- "name": "MINIMUM_IP_TARGET"
  "value": "3"
- "name": "WARM_IP_TARGET"
  "value": "1"

CA 策略调整

The Kubernetes Cluster Autoscaler 是主流的集群自动伸缩解决方案,Amazon EKS 也提供了对应适配的开源实现,支持对 EKS 节点组后端的 AutoScaling Group 进行动态管理,以下为架构实现示意图。

使用 CA 去管理 Spot 机型的节点组,一定要遵循的一条关键原则就是要保证每个 Node Group 的 Spot 机型都是相同的 CPU、内存,这样 CA 才可以准确的进行调度, 如果机型不相同,CA 默认会参照机型列表的第一个机型做调度计算,但是这样就会引起资源调度无法适配问题。

多节点组调度

我们可以在一个节点组设置多个相同 CPU 和内存的机型,增加 Spot 获取的概率,我们也可以利用多个节点组增加获取 Spot 的概率,多节点组建议两种方式。

方式一: 多个相同实例类型的节点组

方式二:多个不相同实例类型的节点组,通过权重做调度

EKS API Server API limits

在大规模调度 EKS Spot 节点和部署 Pod 任务的过程中,我们需要关注 EKS 控制平面的 API Server 性能,目前 EKS 的托管的 API Server 支持安装用户请求量的变化进行 AutoScaling,以达到满足对 API 请求性能的需要。

在实际测试中,我们也会遇到一些 API Limits 问题,这里也提供几个可能遇到限制的API,因为在做 CA 过程中,Node 初始化 CNI 和 Pod Assign IP 的过程中都会频繁的做 API 调用。

  • ModifyNetworkInterfaceAttribute
  • CreateNetworkInterface
  • AssignPrivateIpAddresses
  • AttachNetworkInterface
  • DetachNetworkInterface
  • DeleteNetworkInterface

ECR 性能调优

Amazon Elastic Container Registry (Amazon ECR) 是托管容器映像注册表服务,它安全、可扩展且可靠。Amazon ECR 使用 Amazon IAM 支持拥有基于资源的权限的私有容器映像存储库。这样,指定用户或 Amazon EC2 实例可以访问您的容器存储库和映像。您可以使用首选 CLI 推送、拉取和管理 Docker 映像、Open Container Ititistry (OCI) 映像和 OCI 兼容构件。ECR 提供了高性能的镜像拉取能力,并且由于是内网环境,流量吞吐也是可以达到很高的性能。ECR 也有相关的 API 配额 可以调优,可以参考具体业务场景进行申请修改。

总结

对于很多使用 Amazon Web Service 用户来说,Spot Instances 是非常受欢迎的一个配置方式,因为它帮助用户节约了很多的费用。在 Amazon EKS 里搭配 Spot Instances,可以帮你在兼顾高效率的同时还能节约费用,以上实战调优的总结希望可以提供快速上手的参考。

参考资料

本篇作者

唐健

AWS解决方案架构师,负责基于AWS的云计算方案的架构设计,同时致力于AWS云服务在移动应用与互联网行业的应用和推广。拥有多年移动互联网研发及技术团队管理经验,丰富的互联网应用架构项目经历。