

 **このページの改善にご協力ください** 

このユーザーガイドに貢献するには、すべてのページの右側のペインにある「**GitHub でこのページを編集する**」リンクを選択してください。

# Elastic Fabric Adapter を使用して Amazon EKS で機械学習トレーニングを実行する
<a name="node-efa"></a>

このトピックでは、Amazon EKS クラスターにデプロイした Pod と Elastic Fabric Adapter (EFA) を統合する方法について説明します。Elastic Fabric Adapter (EFA) は、Amazon EC2 インスタンス向けのネットワークインターフェイスです。これにより、AWS で高レベルのノード間通信を必要とするアプリケーションを実行できます。カスタムビルドされたオペレーティングシステムのバイパスハードウェアインターフェイスにより、インスタンス間通信のパフォーマンスが向上します。これは、これらのアプリケーションのスケーリングに不可欠です。EFA を使用すると、Message Passing Interface (MPI) を使用するハイパフォーマンスコンピューティング (HPC) アプリケーションと NVIDIA Collective Communications Library (NCCL) を使用する Machine Learning (ML) アプリケーションを、数千の CPU または GPU にスケールできます。その結果、AWS クラウドのオンデマンドの伸縮自在性と柔軟性を備えたオンプレミスの HPC クラスターのアプリケーションパフォーマンスを実現できます。EFA と Amazon EKS クラスターで実行中のアプリケーションを統合すると、大規模な分散型トレーニングワークロードを完了する時間を短縮できます。クラスターにインスタンスを追加する必要はありません。EFA の詳細については、「[Elastic Fabric Adapter](https://aws.amazon.com/hpc/efa/)」を参照してください。

## EFA を使用するインスタンスタイプ
<a name="efa-instances"></a>

AWS EFA Kubernetes Device Plugin は、EFA を持つすべての Amazon EC2 インスタンスタイプをサポートします。EFA を持つすべてのインスタンスタイプのリストを見るには、「Amazon EC2 ユーザーガイド」の「[サポートされるインスタンスタイプ](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/efa.html#efa-instance-types)」を参照してください。ただし、機械学習アプリケーションを迅速に実行するために、EFA に加えて、nVidia GPU、[AWS Inferentia](https://aws.amazon.com/machine-learning/inferentia/) チップ、[AWS Trainium](https://aws.amazon.com/machine-learning/trainium/) チップなどのハードウェアアクセラレーションチップもインスタンスに搭載しておくことをお勧めします。ハードウェアアクセラレーションチップと EFA を持つインスタンスタイプのリストを見るには、「*Amazon EC2 ユーザーガイド*」の「[高速コンピューティング](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/efa.html#efa-instance-types)」を参照してください。

インスタンスタイプを比較して選択する場合、そのインスタンスタイプで使用できる EFA ネットワークカードの数と、アクセラレータカードの数、CPU の量、メモリの量を考慮してください。ネットワークカードごとに EFA を 1 つまで割り当てることができます。EFA はネットワークインターフェイスとしてカウントされます。EFA を持つ各インスタンスタイプで使用できる EFA の数を確認するには、「*Amazon EC2 ユーザーガイド*」の「[ネットワークカード](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#network-cards)」のリストを参照してください。

## EFA および EFA 専用インターフェイス
<a name="efa-only-interfaces"></a>

Elastic Fabric Adapter (EFA) は、Elastic Network Adapter (ENA) と OS バイパスインターフェイスの機能を組み合わせたネットワークインターフェイスで、AWS Scalable Reliable Datagram (SRD) プロトコルを搭載しています。EFA 機能を使用すると、アプリケーションはハードウェアと直接通信して低レイテンシーの転送を実現できます。EFA 専用インターフェイスを使用して EFA 機能にのみアクセスすることを選択し、通信を同じアベイラビリティーゾーン内のインターフェイスに制限できます。

EFA 専用インターフェイスを持つノードを作成するには、カスタム EC2 起動テンプレートを使用して `InterfaceType` を `efa-only` に設定する必要があります。カスタム起動テンプレートでは、ネットワークカード `0` を EFA 専用インターフェイスに設定することはできません。このネットワークカードが EC2 インスタンスのプライマリネットワークカードおよびネットワークインターフェイスであるためです。EFA 専用インターフェイスには、VPC CNI バージョン `1.18.5` 以降が必要です。Amazon Linux 2 を使用している場合、EFA 専用インターフェイスの AMI バージョンは `v20240928` 以降である必要があります。

次の手順では、nVidia GPU と EFA インターフェイスを持つノードで `eksctl` を使用して、EKS クラスターを作成する手順を説明します。`eksctl` を使用して、EFA 専用インターフェイスを使用するノードとノードグループを作成することはできません。

## 前提条件
<a name="efa-prereqs"></a>
+ 既存の Amazon EKS クラスター。既存のクラスターがない場合は、[Amazon EKS の使用を開始する](getting-started.md) を使用して作成します。クラスターは、ノードをデプロイするのに十分な IP アドレスを持つ、少なくとも 1 つのプライベートサブネットがある VPC にデプロイする必要があります。プライベートサブネットには、NAT ゲートウェイなどの外部のデバイスから提供されるアウトバウンドのインターネットアクセスが必要です。

  `eksctl` を使用してノードグループを作成する予定がある場合、`eksctl` でクラスターを作成することもできます。
+ ご使用のデバイスまたは AWS CloudShell で、バージョン `2.12.3` 以降、または AWS コマンドラインインターフェイス (AWS CLI) のバージョン `1.27.160` 以降がインストールおよび設定されていること。現在のバージョンを確認するには「`aws --version | cut -d / -f2 | cut -d ' ' -f1`」を参照してください。`yum`、`apt-get`、macOS 用の Homebrew などのパッケージマネージャーは、多くの場合 AWS CLI の最新バージョンより数バージョン古くなっています。最新バージョンをインストールするには「*AWS コマンドラインインターフェイスユーザーガイド*」の「[インストール](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)」および「[aws configure を使用したクイック設定](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config)」を参照してください。AWS クラウドシェル にインストールされている AWS CLI バージョンも最新バージョンより数バージョン遅れることがあります。更新するには、「*AWS CloudShell ユーザーガイド*」の「[ホームディレクトリへの AWS CLI のインストール](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software)」を参照してください。
+ デバイスまたは AWS クラウドシェル に、`kubectl` コマンドラインツールがインストールされていること。バージョンはご使用のクラスターの Kubernetes バージョンと同じか、1 つ前のマイナーバージョン以前、あるいはそれより新しいバージョンが使用できます。例えば、クラスターのバージョンが `1.29` である場合、`kubectl` のバージョン `1.28`、`1.29`、または `1.30` が使用できます。`kubectl` をインストールまたはアップグレードする方法については「[`kubectl` および `eksctl` のセットアップ](install-kubectl.md)」を参照してください。
+ `p4d` や `p5` といった複数の Elastic Fabric Adapters をサポートするワーカーノードを起動する前に、Amazon VPC CNI plugin for Kubernetes バージョン `1.7.10` 以降をインストールしておく必要があります。Amazon VPC CNI plugin for Kubernetes バージョンの更新の詳細については、「[Amazon VPC CNI を使用して Pod に IP を割り当てる](managing-vpc-cni.md)」を参照してください。
+ p6-b200 インスタンスの場合、EFA Device プラグインバージョン v0.5.6 以降を使用する必要があります。

**重要**  
Kubernetes で EFA を導入するために必要となる重要な考慮事項は、クラスター内のリソースとして Huge Page を設定および管理することです。詳細については、Kubernetes ドキュメントの「[huge pageを管理する](https://kubernetes.io/docs/tasks/manage-hugepages/scheduling-hugepages/)」を参照してください。EFA ドライバーがインストールされた Amazon EC2 インスタンスでは、5128 2MiB Huge Page が事前に割り当てられます。このページは、ジョブの仕様で使用するリソースとしてリクエストできます。

## ノードグループの作成
<a name="efa-create-nodegroup"></a>

次の手順は、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 リージョンで利用可能である必要がります。

1.  デプロイするインスタンスタイプが利用可能なアベイラビリティーゾーンを特定します。このチュートリアルでは、`p5.48xlarge` インスタンスタイプが使用されているため、前のステップで指定した AWS リージョンの出力が返されているはずです。本番クラスターにノードをデプロイするときは、*p5.48xlarge* を前のステップで返されたいずれかのインスタンスタイプに置き換えます。

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

   出力例は次のとおりです。

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

   後のステップで使用するために、返されたアベイラビリティーゾーンをメモします。ノードをクラスターにデプロイする場合、VPC には、出力で返されるアベイラビリティーゾーンの 1 つに使用可能な IP アドレスを持つサブネットが必要です。

1. `eksctl` を使用してノードグループを作成します。デバイスまたは AWS CloudShell にインストールされている `eksctl` コマンドラインツールのバージョン `0.215.0` 以降が必要です。`eksctl` をインストールまたはアップグレードするには`eksctl` ドキュメントの「[インストール](https://eksctl.io/installation)」を参照してください。

   1. 次の内容を *efa-cluster.yaml* という名前のファイルにコピーします。値の例 は実際に使用する値に置き換えます。`p5.48xlarge` を異なるインスタンスに置き換えることができますが、その場合、`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: p5.48xlarge
          minSize: 1
          desiredCapacity: 2
          maxSize: 3
          availabilityZones: ["us-west-2a"]
          volumeSize: 300
          privateNetworking: true
          efaEnabled: true
      ```

   1. 既存のクラスターにマネージド型ノードグループを作成します。

      ```
      eksctl create nodegroup -f efa-cluster.yaml
      ```

      既存のクラスターがない場合は、次のコマンドを実行してクラスターとノードグループを作成できます。

      ```
      eksctl create cluster -f efa-cluster.yaml
      ```
**注記**  
この例で使用されているインスタンスタイプには GPU が含まれているため、Amazon Linux 2 を使用するときは `eksctl` で NVIDIA Kubernetes デバイスプラグインが各インスタンスに自動的にインストールされます。NVIDIA デバイスプラグインが Bottlerocket の EKS NVIDIA バリアントに組み込まれているため、このプラグインは Bottlerocket には必要ありません。ノードグループ設定で `efaEnabled` が `true` に設定されている場合、`eksctl` では EFA デバイスプラグインもノードに自動的にデプロイされます。

### EFA で Bottlerocket を使用する
<a name="efa-bottlerocket"></a>

Bottlerocket AMI バージョン 1.28.0 以降には、EFA の公式サポートが含まれています。EFA 対応ノードに Bottlerocket を使用するには、設定で `amiFamily: Bottlerocket` を指定します。カスタム AMI ID を使用する必要がある場合は、`managedNodeGroups` の代わりに標準の `nodeGroups` を使用する必要があります。

設定の例を次に示します。

```
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig

metadata:
  name: my-efa-bottlerocket-cluster
  region: region-code
  version: "1.XX"

iam:
  withOIDC: true

availabilityZones: ["us-west-2a", "us-west-2c"]

managedNodeGroups:
  - name: my-efa-bottlerocket-ng
    instanceType: p5.48xlarge
    minSize: 1
    desiredCapacity: 2
    maxSize: 3
    availabilityZones: ["us-west-2a"]
    volumeSize: 300
    privateNetworking: true
    efaEnabled: true
    amiFamily: Bottlerocket
    bottlerocket:
      enableAdminContainer: true
      settings:
        kernel:
          sysctl:
            "vm.nr_hugepages": "3000"  # Configures 3000 * 2Mi = 6000Mi hugepages
```

上記の `vm.nr_hugepages` sysctl 設定で、2Mi hugepages の数を指定します。この例で、3000 は 3000 x 2Mi = 6000Mi の hugepages を意味します。

### EFA デバイスプラグインのインストールを確認する
<a name="verify-efa-device-plugin"></a>

`efaEnabled: true` を使用してノードグループを作成すると、`eksctl` によって EFA Kubernetes デバイスプラグインが自動的にデプロイされます。デバイスプラグインが正しくインストールされ、機能していることを確認できます。

1. DaemonSet のステータスを確認します。

   ```
   kubectl get daemonsets -n kube-system
   ```

   サンプル出力:

   ```
   NAME                                  DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
   aws-efa-k8s-device-plugin-daemonset   2         2         2       2            2           <none>          6m16s
   ...
   ```

   ここでは、EFA デバイスプラグインの DaemonSet が 2 つのノードで実行されています。どちらも READY と AVAILABLE です。

1. 次に、DaemonSet によって作成されたポッドを確認します。

   ```
   kubectl get pods -n kube-system -l name=aws-efa-k8s-device-plugin
   ```

   サンプル出力:

   ```
   NAME                                        READY   STATUS    RESTARTS   AGE
   aws-efa-k8s-device-plugin-daemonset-d68bs   1/1     Running   0          6m16s
   aws-efa-k8s-device-plugin-daemonset-w4l8t   1/1     Running   0          6m16s
   ```

   EFA デバイスプラグインポッドが実行中状態であり、プラグインが正常にデプロイされ、動作していることを確認します。

1. リソース登録を確認します。

   `vpc.amazonaws.com/efa` リソースが kubelet に登録されていることを確認するには、ノードを記述します。

   ```
   kubectl describe nodes
   ```

   EFA リソースが正しく登録されている場合、ノードのキャパシティと割り当て可能なリソースの下に一覧表示されます。例えば、次のようになります。

   ```
   Capacity:
     ...
     vpc.amazonaws.com/efa:  4
   Allocatable:
     ...
     vpc.amazonaws.com/efa:  4
   ```

   この出力では、ノードが EFA リソースを認識し、それをリクエストするポッドで使用できるようになっていることが確認されます。

## (オプション) EFA のパフォーマンスをテストする
<a name="efa-application"></a>

EFA セットアップをテストすることをお勧めします。GitHub の `aws-samples/awsome-distributed-training` リポジトリで [NCCL テスト](https://github.com/aws-samples/awsome-distributed-training/tree/main/micro-benchmarks/nccl-tests)を使用できます。[NCCL テスト](https://github.com/NVIDIA/nccl-tests)は、Nvidia Collective Communication Library を使用してネットワークのパフォーマンスを評価します。次のステップでは、Amazon EKS で NCCL テストを送信します。

1. Kubeflow MPI Operator のデプロイ:

   NCCL テストでは、Kubeflow MPI Operator を適用できます。MPI Operator を使用すると、Kubernetes で AllReduce スタイルの分散型トレーニングを簡単に実行できます。詳細については、GitHub の「[MPI Operator](https://github.com/kubeflow/mpi-operator)」を参照してください。

1. マルチノードの NCCL パフォーマンステストを実行して、GPUDirectRDMA/EFA を検証する:

   GPUDirectRDMA over EFA を使用した NCCL パフォーマンスを検証するには、標準の NCCL パフォーマンステストを実施します。詳細については、GitHub で公式の「[NCCL-Tests](https://github.com/NVIDIA/nccl-tests.git)」(NCCL テスト) を参照してください。

   2 ノード NCCLL パフォーマンステストを実行するには、次の手順を実行します。サンプルの NCCL テストジョブでは、各ワーカーが 8 つの GPU、5210Mi の `hugepages-2Mi`、4 つの EFA、8000Mi のメモリをリクエストします。これは事実上、各ワーカーが `p5.48xlarge` インスタンスのすべてのリソースを使用することを意味します。

   1. MPIJob マニフェストを作成する:

      次の JSON を `nccl-tests.yaml` という名前のファイルにコピーします:

      ```
      apiVersion: kubeflow.org/v2beta1
      kind: MPIJob
      metadata:
        name: nccl-tests
      spec:
        runPolicy:
          cleanPodPolicy: Running
          backoffLimit: 20
        slotsPerWorker: 8
        mpiReplicaSpecs:
          Launcher:
            replicas: 1
            template:
               spec:
                restartPolicy: OnFailure
                containers:
                - image: public.ecr.aws/hpc-cloud/nccl-tests:latest
                  imagePullPolicy: IfNotPresent
                  name: test-nccl-launcher
                  env:
                   - name: PATH
                     value: $PATH:/opt/amazon/efa/bin:/usr/bin
                  command:
                  - /opt/amazon/openmpi/bin/mpirun
                  - --allow-run-as-root
                  - --tag-output
                  - -np
                  - "16"
                  - -N
                  - "8"
                  - --bind-to
                  - none
                  - -x
                  - PATH
                  - -x
                  - LD_LIBRARY_PATH
                  - -x
                  - NCCL_DEBUG=INFO
                  - -x
                  - NCCL_BUFFSIZE=8388608
                  - -x
                  - NCCL_P2P_NET_CHUNKSIZE=524288
                  - -x
                  - NCCL_TUNER_PLUGIN=/opt/amazon/ofi-nccl/lib/x86_64-linux-gnu/libnccl-ofi-tuner.so
                  - --mca
                  - pml
                  - ^cm,ucx
                  - --mca
                  - btl
                  - tcp,self
                  - --mca
                  - btl_tcp_if_exclude
                  - lo,docker0,veth_def_agent
                  - /opt/nccl-tests/build/all_reduce_perf
                  - -b
                  - "8"
                  - -e
                  - "16G"
                  - -f
                  - "2"
                  - -g
                  - "1"
                  - -c
                  - "1"
                  - -n
                  - "100"
          Worker:
            replicas: 2
            template:
              spec:
                nodeSelector:
                  node.kubernetes.io/instance-type: "p5.48xlarge"
                containers:
                - image: public.ecr.aws/hpc-cloud/nccl-tests:latest
                  imagePullPolicy: IfNotPresent
                  name: nccl-tests-worker
                  volumeMounts:
                  - name: shmem
                    mountPath: /dev/shm
                  resources:
                    limits:
                      nvidia.com/gpu: 8
                      hugepages-2Mi: 5120Mi
                      vpc.amazonaws.com/efa: 32
                      memory: 32000Mi
                    requests:
                      nvidia.com/gpu: 8
                      hugepages-2Mi: 5120Mi
                      vpc.amazonaws.com/efa: 32
                      memory: 32000Mi
                volumes:
                - name: shmem
                  hostPath:
                    path: /dev/shm
      ```

   1. NCCL テスト MPIJob を適用する:

      マニフェストを適用して `MPIJob` を送信します。これにより、2 つの `p5.48xlarge` Amazon EC2 インスタンスが作成されます。

      ```
      kubectl apply -f nccl-tests.yaml
      ```

      出力例は次のとおりです。

      ```
      mpijob.kubeflow.org/nccl-tests created
      ```

   1. ジョブがポッドを開始したことを検証する:

      実行中の Pod を表示します。

      ```
      kubectl get pods
      ```

      出力例は次のとおりです。

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

      MPI Operator は、ランチャー Pod と 2 つのワーカー Pod (ノードごとに 1 つ) を作成します。

   1. ログを使用してジョブが正常に実行されていることを検証する:

      `nccl-tests-launcher` Pod のログを表示します。*nbql9* を出力の値で置き換えます。

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

テストが正常に完了すると、Nvidia Collective Communication Library を使用するアプリケーションをデプロイできます。