使用 Elastic Fabric Adapter 的 Machine Learning 培训 - Amazon EKS

帮助改进此页面

想为本用户指南做出贡献? 滚动到页面底部,然后选择在 GitHub 上编辑此页面。您的贡献有助于我们的用户指南为每个人提供更充分的参考。

使用 Elastic Fabric Adapter 的 Machine Learning 培训

本主题介绍如何将 Elastic Fabric Adapter(EFA)与部署在 Amazon EKS 集群中的 Pods 集成。Elastic Fabric Adapter (EFA) 是 Amazon EC2 实例的网络接口,使您能够在AWS上运行要求大规模高级别节点间通信的应用程序。其量身定制的操作系统旁路硬件接口增强了实例间通信的性能,这对扩缩这些应用程序至关重要。借助 EFA,采用消息传递接口 (MPI) 的高性能计算 (HPC) 应用程序和采用 NVIDIA Collective Communications Library (NCCL) 的 Machine Learning (ML) 应用程序可以扩展到数千个 CPU 或 GPU。因此,您同时获得了本地 HPC 集群的应用程序性能,以及AWS云的按需弹性和灵活度。将 EFA 与 Amazon EKS 集群上运行的应用程序集成,可以缩短完成大规模分布式培训工作负载的时间,而无需向集群添加更多实例。有关 EFA 的更多信息,请参阅 Elastic Fabric Adapter

本主题中描述的 EFA 插件完全支持 Amazon EC2 P4d 实例,它代表了云中分布式 Machine Learning 的顶尖技术。每个 p4d.24xlarge 实例通过 EFA 拥有八个 NVIDIA A100 GPU 和 400Gbps 的 GPUDirectRDMA。GPUDirectRDMA 使您能够通过 CPU 旁路在节点之间实现 GPU 到 GPU 的直接通信,从而增加集体通信带宽并降低延迟。Amazon EKS 和 EFA 与 P4d 实例的集成提供了一种无缝衔接的方法,可为分布式 Machine Learning 培训利用最高性能的 Amazon EC2 计算实例。

先决条件
  • 现有 Amazon EKS 集群。如果您没有现有集群,请参考我们的某个 开始使用 Amazon EKS 指南创建一个集群。您的集群必须部署在至少具有一个私有子网的 VPC 中,该子网应当具有足够多的可用 IP 地址以便在其中部署节点。私有子网必须具有由外部设备(如 NAT 网关)提供的出站 Internet 访问。

    如果您计划使用 eksctl 创建您的节点组,eksctl 还可以为您创建集群。

  • 在您的设备或 AWS CloudShell 上安装和配置了 AWS Command Line Interface(AWS CLI)的版本 2.12.3 或更高版本,或版本 1.27.160 或更高版本。要查看当前版本,请使用 aws --version | cut -d / -f2 | cut -d ' ' -f1。软件包管理器(如 yumapt-get 或适用于 macOS 的 Homebrew)通常比 AWS CLI 的最新版本落后几个版本。要安装最新版本,请参阅《AWS Command Line Interface 用户指南》中的安装、更新和卸载 AWS CLI,以及使用 aws configure 快速配置。AWS CloudShell 中安装的 AWS CLI 版本也可能比最新版本落后几个版本。如需更新,请参阅《AWS CloudShell 用户指南》中的将 AWS CLI 安装到主目录

  • 您的设备或 AWS CloudShell 上安装了 kubectl 命令行工具。该版本可以与集群的 Kubernetes 版本相同,或者最多早于或晚于该版本一个次要版本。例如,如果您的集群版本为 1.29,则可以将 kubectl1.281.291.30 版本与之配合使用。要安装或升级 kubectl,请参阅 安装或更新 kubectl

  • 在启动支持多个 Elastic Fabric Adapter 的 Worker 节点(例如 p4d.24xlarge)之前,您必须先安装 Amazon VPC CNI plugin for Kubernetes 版本 1.7.10 或更高版本。有关更新您的 Amazon VPC CNI plugin for Kubernetes 版本的更多信息,请参阅 使用 Amazon VPC CNI plugin for Kubernetes Amazon EKS 附加组件

创建节点组

下面的程序通过一个包含 EFA 接口和 GPUDirect RDMA 且受 p4d.24xlarge 支持的节点组,帮助您创建节点组,并使用 EFA 针对多节点 NCCL 性能运行一个 NVIDIA Collective Communications Library (NCCL) 示例测试。该示例可用作使用 EFA 在 Amazon EKS 上进行分布式深度学习培训的模板。

  1. 确定您想在其中部署节点的 AWS 区域 中有哪些支持 EFA 的 Amazon EC2 实例类型可用。region-code 替换为您想要在其中部署节点组的 AWS 区域。

    aws ec2 describe-instance-types --region region-code --filters Name=network-info.efa-supported,Values=true \ --query "InstanceTypes[*].[InstanceType]" --output text

    部署节点时,您想要部署的实例类型必须在集群所在的 AWS 区域 中可用。

  2. 确定您想要部署的实例类型在哪些可用区中可用。本教程使用了 p4d.24xlarge 实例类型,必须在上一步所指定的 AWS 区域 的输出中返回该实例类型。在生产集群中部署节点时,请将 p4d.24xlarge 替换为上一步中返回的任何实例类型。

    aws ec2 describe-instance-type-offerings --region region-code --location-type availability-zone --filters Name=instance-type,Values=p4d.24xlarge \ --query 'InstanceTypeOfferings[*].Location' --output text

    示例输出如下。

    us-west-2a    us-west-2c    us-west-2b

    记下返回的可用区,以供后续步骤使用。将节点部署到集群时,VPC 的子网必须在输出返回的其中一个可用区中具有可用的 IP 地址。

  3. 使用 eksctl,或者使用 AWS CLI 和 AWS CloudFormation 创建节点组。

    eksctl
    先决条件

    您的设备或 AWS CloudShell 上安装了 0.183.0 版或更高版本的 eksctl 命令行工具。要安装或更新 eksctl,请参阅 eksctl 文档中的 Installation

    1. 将以下内容复制到名为 efa-cluster.yaml 的文件中。将 example values 替换为您自己的值。您可以将 p4d.24xlarge 替换为不同的实例,但是如果您进行替换,请确保 availabilityZones 的值为第 1 步中针对实例类型返回的可用区。

      apiVersion: eksctl.io/v1alpha5 kind: ClusterConfig metadata: name: my-efa-cluster region: region-code version: "1.XX" iam: withOIDC: true availabilityZones: ["us-west-2a", "us-west-2c"] managedNodeGroups: - name: my-efa-ng instanceType: p4d.24xlarge minSize: 1 desiredCapacity: 2 maxSize: 3 availabilityZones: ["us-west-2a"] volumeSize: 300 privateNetworking: true efaEnabled: true
    2. 在现有集群中创建托管节点组。

      eksctl create nodegroup -f efa-cluster.yaml

      如果您没有现有集群,可以运行以下命令来创建集群和节点组。

      eksctl create cluster -f efa-cluster.yaml
      注意

      由于此示例中使用的实例类型具有 GPU,eksctl 会在每个实例上为您自动安装 NVIDIA Kubernetes 设备插件。

    AWS CLI and AWS CloudFormation

    EFA 联网有几个要求,包括创建 EFA 特定的安全组,创建 Amazon EC2 置放群组,创建指定一个或多个 EFA 接口的启动模板,并将 EFA 驱动程序安装作为 Amazon EC2 用户数据的一部分。要了解有关 EFA 要求的更多信息,请参阅《Amazon EC2 用户指南》中的 EFA 和 MPI 入门。以下步骤为您创建所有这些内容。将所有示例值替换为您自己的值。

    1. 设置将在后面的步骤中使用的几个变量。将所有 example values 替换为您自己的值。将 my-cluster 替换为您的现有集群的名称。后面将使用 node_group_resources_name 的值来创建 AWS CloudFormation 堆栈。后面将使用 node_group_name 的值在集群中创建节点组。

      cluster_name="my-cluster" cluster_region="region-code" node_group_resources_name="my-efa-nodegroup-resources" node_group_name="my-efa-nodegroup"
    2. 在您的 VPC 中确定一个私有子网,该子网与您想要部署的实例类型位于相同的可用区中。

      1. 检索集群的版本并将其存储在变量中,以便在后续步骤中使用。

        cluster_version=$(aws eks describe-cluster \ --name $cluster_name \ --query "cluster.version" \ --output text)
      2. 检索您的集群所在的 VPC ID,并将其存储在变量中,以便在后续步骤中使用。

        vpc_id=$(aws eks describe-cluster \ --name $cluster_name \ --query "cluster.resourcesVpcConfig.vpcId" \ --output text)
      3. 检索集群的控制层面安全组的 ID,并将其存储在变量中,以便在后续步骤中使用。

        control_plane_security_group=$(aws eks describe-cluster \ --name $cluster_name \ --query "cluster.resourcesVpcConfig.clusterSecurityGroupId" \ --output text)
      4. 获取 VPC 中位于第 1 步返回的可用区中的子网 ID 列表。

        aws ec2 describe-subnets \ --filters "Name=vpc-id,Values=$vpc_id" "Name=availability-zone,Values=us-west-2a" \ --query 'Subnets[*].SubnetId' \ --output text

        如果没有返回输出,请尝试第 1 步中返回的其他可用区。如果您的子网都不在第 1 步返回的可用区中,则您需要在第 1 步返回的可用区中创建一个子网。如果您的 VPC 中没有空间再创建其他子网,则可以向该 VPC 中添加 CIDR 块并在新 CIDR 块中创建子网,或者在新 VPC 中创建一个新集群。

      5. 通过检查子网的路由表来确定子网是否为私有子网。

        aws ec2 describe-route-tables \ --filter Name=association.subnet-id,Values=subnet-0d403852a65210a29 \ --query "RouteTables[].Routes[].GatewayId" \ --output text

        示例输出如下。

        local

        如果输出为 local igw-02adc64c1b72722e2,则说明该子网是公有子网。您必须在第 1 步返回的可用区中选择一个私有子网。确定私有子网后,请记下其 ID 以便后面的步骤中使用。

      6. 使用上一步中的私有子网 ID 设置一个变量,以便在后续步骤中使用。

        subnet_id=your-subnet-id
    3. 下载 AWS CloudFormation 模板。

      curl -O https://raw.githubusercontent.com/aws-samples/aws-efa-eks/main/cloudformation/efa-p4d-managed-nodegroup.yaml
    4. 将下面的文本复制到计算机上。将 p4d.24xlarge 替换为第 1 步中的实例类型。将 subnet-0d403852a65210a29 替换为您在第 2.b.v 步中标识的私有子网的 ID。将 path-to-downloaded-cfn-template 替换为您在上一步中下载的 efa-p4d-managed-nodegroup.yaml 的路径。将 your-public-key-name 替换为您的公有密钥的名称。完成替换后,运行修改后的命令。

      aws cloudformation create-stack \ --stack-name ${node_group_resources_name} \ --capabilities CAPABILITY_IAM \ --template-body file://path-to-downloaded-cfn-template \ --parameters \ ParameterKey=ClusterName,ParameterValue=${cluster_name} \ ParameterKey=ClusterControlPlaneSecurityGroup,ParameterValue=${control_plane_security_group} \ ParameterKey=VpcId,ParameterValue=${vpc_id} \ ParameterKey=SubnetId,ParameterValue=${subnet_id} \ ParameterKey=NodeGroupName,ParameterValue=${node_group_name} \ ParameterKey=NodeImageIdSSMParam,ParameterValue=/aws/service/eks/optimized-ami/${cluster_version}/amazon-linux-2-gpu/recommended/image_id \ ParameterKey=KeyName,ParameterValue=your-public-key-name \ ParameterKey=NodeInstanceType,ParameterValue=p4d.24xlarge
    5. 确定何时部署您在上一步中部署的堆栈。

      aws cloudformation wait stack-create-complete --stack-name $node_group_resources_name

      上一个命令没有产生输出,但是您的 shell 提示符要直到创建堆栈后才会返回。

    6. 使用上一步中 AWS CloudFormation 堆栈所创建的资源创建您的节点组。

      1. 从已部署的 AWS CloudFormation 堆栈检索信息并将其存储在变量中。

        node_instance_role=$(aws cloudformation describe-stacks \ --stack-name $node_group_resources_name \ --query='Stacks[].Outputs[?OutputKey==`NodeInstanceRole`].OutputValue' \ --output text) launch_template=$(aws cloudformation describe-stacks \ --stack-name $node_group_resources_name \ --query='Stacks[].Outputs[?OutputKey==`LaunchTemplateID`].OutputValue' \ --output text)
      2. 使用在上一步中创建的启动模板和节点 IAM 角色创建一个托管节点组。

        aws eks create-nodegroup \ --cluster-name $cluster_name \ --nodegroup-name $node_group_name \ --node-role $node_instance_role \ --subnets $subnet_id \ --launch-template id=$launch_template,version=1
      3. 确认已创建节点。

        aws eks describe-nodegroup \ --cluster-name ${cluster_name} \ --nodegroup-name ${node_group_name} | jq -r .nodegroup.status

        在上一个命令返回的状态变为 ACTIVE 之前,请勿继续操作。节点可能需要几分钟才能准备就绪。

    7. 如果您选择了 GPU 实例类型,则必须部署 适用于 Kubernetes 的 NVIDIA 设备插件。将 vX.X.X 替换为您需要的 NVIDIA/k8s-device-plugin 版本,然后运行以下命令。

      kubectl apply -f https://raw.githubusercontent.com/NVIDIA/k8s-device-plugin/vX.X.X/nvidia-device-plugin.yml
  4. 部署 EFA Kubernetes 设备插件。

    EFA Kubernetes 设备插件检测 EFA 接口并将其通告为可分配给 Kubernetes 的资源。应用程序可以使用 Pod 请求规范中的扩展资源类型 vpc.amazonaws.com/efa,就像 CPU 和内存一样。有关更多信息,请参阅 Kubernetes 文档中的使用扩展资源。请求后,该插件会自动为 Pod 分配并挂载 EFA 接口。使用该设备插件可以简化 EFA 设置,而且不需要在特权模式下运行 Pod。

    helm repo add eks https://aws.github.io/eks-chart helm install aws-efa-k8s-device-plugin --namespace kube-system eks/aws-efa-k8s-device-plugin

(可选)部署示例 EFA 兼容应用程序

部署 Kubeflow MPI Operator

对于 NCCL 测试,您可以应用 Kubeflow MPI Operator。MPI Operator 可以轻松地在 Kubernetes 上运行 Allreduce 模式的分布式训练。有关更多信息,请参阅 GitHub 上的 MPI Operator

kubectl apply -f https://raw.githubusercontent.com/kubeflow/mpi-operator/master/deploy/v2beta1/mpi-operator.yaml
运行多节点 NCCL 性能测试以验证 GPUDirectrDMA/EFA

要通过 EFA 使用 GPUDirectRDMA 验证 NCCL 性能,请运行标准 NCCL 性能测试。有关更多信息,请参阅 GitHub 上的官方 NCCL 测试存储库。您可以使用随此测试提供的示例 Dockerfile,它已经针对 NVIDIA CUDA 11.2 和最新版本 EFA 进行构建。

或者,您也可以下载 Amazon ECR 存储库中提供的 AWS Docker 镜像。

重要

在 Kubernetes 中采用 EFA 时需要考虑的一个重要因素,是将 Huge Pages 作为集群中的资源进行配置和管理。有关更多信息,请参阅 Kubernetes 文档中的管理 Huge Pages。安装了 EFA 驱动程序的 Amazon EC2 实例预先分配 5128 个 2M 的 Huge Pages,您可以请求将它们作为资源在您的作业规范中使用。

完成以下步骤以运行双节点 NCCL 性能测试。在示例 NCCL 测试作业中,每个工作线程请求八个 GPU、5210Mi 的 Hugepages-2mi、四个 EFA 和 8000Mi 的内存,这意味着每个工作线程都会使用 p4d.24xlarge 实例的所有资源。

  1. 创建 NCCL 测试作业。

    kubectl apply -f https://raw.githubusercontent.com/aws-samples/aws-efa-eks/main/examples/simple/nccl-efa-tests.yaml

    示例输出如下。

    已创建 mpijob.kubeflow.org/nccl-tests-efa

  2. 查看您运行的 Pods。

    kubectl get pods

    示例输出如下。

    NAME READY STATUS RESTARTS AGE nccl-tests-efa-launcher-nbql9 0/1 Init:0/1 0 2m49s nccl-tests-efa-worker-0 1/1 Running 0 2m49s nccl-tests-efa-worker-1 1/1 Running 0 2m49s

    MPI Operator 创建一个启动器 Pod 和 2 个工作线程 Pods(每个节点上一个)。

  3. 查看 efa-launcher Pod 的日志。将 wzr8j 替换为输出中的值。

    kubectl logs -f nccl-tests-efa-launcher-nbql9

有关更多示例,请参阅 GitHub 上的 Amazon EKS EFA 示例存储库。