11주차 - ML Infra(GPU) on EKS(2)

728x90

 멀티 GPU 활용을 위한 AI/ML 인프라 with EKS

  • NCCL: GPU 간 통신을 위한 NVIDIA의 해결책
    • 분산 학습에서 GPU 간 통신 성능이 중요해짐에 따라, NVIDIA는 NCCL(NVIDIA Collective Communications Library)을 개발
    • NCCL은 여러 GPU 간의 집합 통신 연산을 최적화하기 위해 설계된 라이브러리임.
    • NCCL 주요 특징
      • 고성능 집합 통신 연산: AllReduce, Broadcast, Reduce, AllGather, ReduceScatter 등 딥러닝에 필수적인 통신 패턴을 최적화
      • 다양한 토폴로지 지원: PCIe, NVLink, NVSwitch 등 GPU 간 연결 토폴로지를 자동으로 감지하고 최적화
      • 멀티 노드 확장성: InfiniBand, RoCE, IP 소켓 등을 통한 노드 간 통신 지원
      • CUDA 통합: CUDA 스트림과 통합되어 계산과 통신의 오버랩 가능
    • NCCL은 딥러닝 프레임워크(PyTorch, TensorFlow 등)에 통합되어 사용자가 명시적으로 통신 코드를 작성하지 않아도 효율적인 분산 학습이 가능하게 함
    • 그러나 NCCL만으로는 노드 간 네트워크 병목 현상을 완전히 해결할 수 없음.
  • AWS EFA (Elastic Fabric Adapter) 기술
    • GPU 네트워크 병목 문제를 해결하기 위해 설계된 혁신적인 네트워크 인터페이스
    • 기반 핵심 기술:
      • OS 바이패스 기술: EFA는 운영 체제 커널을 우회하여 사용자 공간 애플리케이션이 네트워크 어댑터와 직접 통신 가능
        • 커널 컨텍스트 스위칭 제거
        • 시스템 콜 오버헤드 제거
        • 인터럽트 처리 최소화
      • RDMA (Remote Direct Memory Access): 원격 시스템의 메모리에 CPU 개입 없이 직접 접근할 수 있는 기술
        • 원격 시스템의 CPU를 사용하지 않고 메모리 읽기/쓰기 가능
        • 제로 카피(Zero-copy) 데이터 전송
        • DMA(Direct Memory Access)를 통한 효율적인 데이터 이동
      • NCCL과 EFA와의 통합: NVIDIA Collective Communications Library(NCCL)는 EFA와 최적화된 통합을 제공
        • GPU 직접 통신 최적화
        • 토폴로지 인식 통신 알고리즘
        • 자동 튜닝 메커니즘

  • Amazon EKS에 EFA를 통합함으로써 얻을 수 있는 주요 이점:
    1. 인프라 관리 간소화
      • Kubernetes를 통한 선언적 인프라 관리
      • GPU 및 EFA 리소스의 자동 검출 및 할당
      • 자동 확장 및 축소 기능
    2. 비용 최적화
      • 리소스 활용도 향상 (GPU 활용률 90% 이상)
      • 학습 시간 단축으로 인한 인스턴스 비용 절감
      • Spot 인스턴스와의 통합 가능성
    3. 성능 최적화
      • 노드 간 초저지연 통신
      • 분산 학습 확장성 향상
      • 대규모 모델 학습 가속화
    4. 개발자 경험 개선
      • 일관된 개발 및 배포 환경
      • 재현 가능한 실험 설정
      • CI/CD 파이프라인과의 통합 용이성

컨테이너 환경에서의 GPU 리소스 사용 진화 (멀티 GPU)

  • 분산 학습에서 발생하는 네트워크 병목 현상
    • 대규모 모델이 등장하면서, 이제 단일 GPU로는 학습이 불가능해짐.
      • GPT-3: 1,750억 파라미터
      • Megatron-Turing NLG: 5,300억 파라미터
      • PaLM: 5,400억 파라미터
    • AWS에서도 이러한 추세에 맞춰 대규모 모델 개발과 학습을 위한 인프라를 지속적으로 발전시키고 있음.
      • Amazon Bedrock: 100개 이상의 LLM을 지원하며
      • Trainium/Inferentia 칩을 통한 모델 성능 향상과 같은 AI 인프라 혁신에 투자
    • 2025년 현재 AWS는 이러한 대규모 모델의 학습과 추론을 위해 분산 컴퓨팅 기술을 적극적으로 활용하고 있으며, 단일 GPU로는 처리할 수 없는 규모의 모델 개발을 지원하고 있음.
    • 이러한 대규모 모델은 필연적으로 여러 GPU와 여러 노드에 걸친 분산 학습이 필요
    • 분산 학습에서 이루어지는 주요 통신 패턴 - AllReduce, AllGather, ReduceScatter 등

 

EKS Blueprint with Terraform w/ RDMA 미지원 g5.8xlarge

$ git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git

$ cd terraform-aws-eks-blueprints/patterns/nvidia-gpu-efa

$ sed -i "s/p5.48xlarge/g5.8xlarge/g" eks.tf
$ sed -i "s/us-west-2/us-east-1/g" main.tf

$ terraform init
$ terraform apply -target="module.vpc" -auto-approve
$ terraform apply -target="module.eks" -auto-approve
$ terraform apply -auto-approve

 

 

MPI Operator를 사용한 테스트 w/ RDMA 미지원 g5.8xlarge

$ aws eks --region us-east-1 update-kubeconfig --name nvidia-gpu-efa

# 인스턴스 유형별 노드 나열
$ kubectl get nodes -L node.kubernetes.io/instance-type
NAME                          STATUS   ROLES    AGE   VERSION               INSTANCE-TYPE
ip-10-0-1-129.ec2.internal    Ready    <none>   22m   v1.32.1-eks-5d632ec   g5.8xlarge
ip-10-0-11-12.ec2.internal    Ready    <none>   15m   v1.32.1-eks-5d632ec   g5.8xlarge
ip-10-0-12-158.ec2.internal   Ready    <none>   23m   v1.32.1-eks-5d632ec   m5.large
ip-10-0-26-134.ec2.internal   Ready    <none>   23m   v1.32.1-eks-5d632ec   m5.large

# Kubeflow MPI Operator 배포
$ kubectl apply -f https://raw.githubusercontent.com/kubeflow/mpi-operator/v0.4.0/deploy/v2beta1/mpi-operator.yaml
namespace/mpi-operator created
customresourcedefinition.apiextensions.k8s.io/mpijobs.kubeflow.org created
serviceaccount/mpi-operator created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-admin created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-edit created
clusterrole.rbac.authorization.k8s.io/kubeflow-mpijobs-view created
clusterrole.rbac.authorization.k8s.io/mpi-operator created
clusterrolebinding.rbac.authorization.k8s.io/mpi-operator created
deployment.apps/mpi-operator created

# 또한 mpi-operator 클러스터 역할에 패치를 적용하여 mpi-operator 서비스 계정이 apiGroup leases 리소스에 액세스할 수 있도록 설정
$ kubectl apply -f https://raw.githubusercontent.com/aws-samples/aws-do-eks/main/Container-Root/eks/deployment/kubeflow/mpi-operator/clusterrole-mpi-operator.yaml
clusterrole.rbac.authorization.k8s.io/mpi-operator configured

# 실습에 사용하는 g5.8xlarge 인스턴스에는 인스턴스 당 GPU 1개 및 EFA 1개를 포함하고 있으므로 생성 스크립트를 수정하여 실행
$ sed -i "s/GPU_PER_WORKER=8/GPU_PER_WORKER=1/g" generate-efa-info-test.sh
$ sed -i "s/EFA_PER_WORKER=32/EFA_PER_WORKER=1/g" generate-efa-info-test.sh

# efa 테스트 수행
$ ./generate-efa-info-test.sh
$ kubectl apply -f ./efa-info-test.yaml
mpijob.kubeflow.org/efa-info-test created

# 모니터링 (워커 포드가 완전히 실행될 때까지 런처 포드가 몇 번 다시 시작되는 것은 정상임)
$ watch 'kubectl get pods'
매 2.0초:   kubectl get pods                                                                                                                               LOCK-PC: Sun Apr 13 01:27:45 2025
NAME                           READY   STATUS              RESTARTS   AGE
efa-info-test-launcher-mbql8   0/1     ContainerCreating   0          57s
efa-info-test-worker-0         0/1     ContainerCreating   0          57s
efa-info-test-worker-1         0/1     ContainerCreating   0          57s

# (...시간이 지나고...)
매 2.0초:   kubectl get pods                                                                                                                               LOCK-PC: Sun Apr 13 01:29:43 2025
NAME                           READY   STATUS      RESTARTS   AGE
efa-info-test-launcher-mbql8   0/1     Completed   0          2m56s

# 테스트 결과 확인
$ kubectl logs -f $(kubectl get pods | grep launcher | cut -d ' ' -f 1)
Warning: Permanently added 'efa-info-test-worker-1.efa-info-test.default.svc' (ED25519) to the list of known hosts.
Warning: Permanently added 'efa-info-test-worker-0.efa-info-test.default.svc' (ED25519) to the list of known hosts.
[1,1]<stdout>:provider: efa
[1,1]<stdout>:    fabric: efa
[1,1]<stdout>:    domain: rdmap0s29-rdm
[1,1]<stdout>:    version: 122.0
[1,1]<stdout>:    type: FI_EP_RDM
[1,1]<stdout>:    protocol: FI_PROTO_EFA
[1,0]<stdout>:provider: efa
[1,0]<stdout>:    fabric: efa
[1,0]<stdout>:    domain: rdmap0s29-rdm
[1,0]<stdout>:    version: 122.0
[1,0]<stdout>:    type: FI_EP_RDM
[1,0]<stdout>:    protocol: FI_PROTO_EFA

# 작업 제거
$ kubectl delete -f ./efa-info-test.yaml

 

 

EFA NCCL 테스트 w/ RDMA 미지원 g5.8xlarge

# 실습에 사용하는 g5.8xlarge 인스턴스에는 인스턴스 당 GPU 1개 및 EFA 1개를 포함하고 있으므로 생성 스크립트를 수정하여 실행
$ sed -i "s/INSTANCE_TYPE=p5e\.48xlarge/INSTANCE_TYPE=g5\.8xlarge/g" generate-efa-nccl-test.sh
$ sed -i "s/GPU_PER_WORKER=8/GPU_PER_WORKER=1/g" generate-efa-nccl-test.sh
$ sed -i "s/EFA_PER_WORKER=32/EFA_PER_WORKER=1/g" generate-efa-nccl-test.sh
$ sed -i "s/FI_EFA_USE_DEVICE_RDMA=1/FI_EFA_USE_DEVICE_RDMA=0/g" generate-efa-nccl-test.sh
$ ./generate-efa-nccl-test.sh

$ kubectl apply -f ./efa-nccl-test.yaml
mpijob.kubeflow.org/efa-nccl-test created

$ watch kubectl get pods
매 2.0초:   kubectl get pods                                                                                                                               LOCK-PC: Sun Apr 13 01:39:18 2025
NAME                           READY   STATUS    RESTARTS      AGE
efa-nccl-test-launcher-mmfxv   1/1     Running   2 (75s ago)   77s
efa-nccl-test-worker-0         1/1     Running   0             77s
efa-nccl-test-worker-1         1/1     Running   0             77s

# (...시간이 지나고...)
매 2.0초:   kubectl get pods                                                                                                                               LOCK-PC: Sun Apr 13 01:48:52 2025
NAME                           READY   STATUS      RESTARTS   AGE
efa-nccl-test-launcher-mmfxv   0/1     Completed   2          10m

$ kubectl logs -f $(kubectl get pods | grep launcher | cut -d ' ' -f 1)
Warning: Permanently added 'efa-nccl-test-worker-0.efa-nccl-test.default.svc' (ED25519) to the list of known hosts.
Warning: Permanently added 'efa-nccl-test-worker-1.efa-nccl-test.default.svc' (ED25519) to the list of known hosts.
[1,0]<stdout>:# nThread 1 nGpus 1 minBytes 8 maxBytes 17179869184 step: 2(factor) warmup iters: 5 iters: 100 agg iters: 1 validation: 1 graph: 0
[1,0]<stdout>:#
[1,0]<stdout>:# Using devices
[1,0]<stdout>:#  Rank  0 Group  0 Pid     33 on efa-nccl-test-worker-0 device  0 [0000:00:1e] NVIDIA A10G
[1,0]<stdout>:#  Rank  1 Group  0 Pid     33 on efa-nccl-test-worker-1 device  0 [0000:00:1e] NVIDIA A10G
[1,0]<stdout>:#
[1,0]<stdout>:# Reducing maxBytes to 7624021333 due to memory limitation
[1,0]<stdout>:NCCL version 2.26.2+cuda12.2
[1,0]<stdout>:#
[1,0]<stdout>:#                                                              out-of-place                       in-place
[1,0]<stdout>:#       size         count      type   redop    root     time   algbw   busbw #wrong     time   algbw   busbw #wrong
[1,0]<stdout>:#        (B)    (elements)                               (us)  (GB/s)  (GB/s)            (us)  (GB/s)  (GB/s)
[1,0]<stdout>:           8             2     float     sum      -1    67.14    0.00    0.00      0    67.69    0.00    0.00      0
[1,0]<stdout>:          16             4     float     sum      -1    69.12    0.00    0.00      0    68.49    0.00    0.00      0
[1,0]<stdout>:          32             8     float     sum      -1    70.05    0.00    0.00      0    69.90    0.00    0.00      0
[1,0]<stdout>:          64            16     float     sum      -1    70.44    0.00    0.00      0    69.89    0.00    0.00      0
[1,0]<stdout>:         128            32     float     sum      -1    70.64    0.00    0.00      0    70.60    0.00    0.00      0
[1,0]<stdout>:         256            64     float     sum      -1    71.02    0.00    0.00      0    70.79    0.00    0.00      0
[1,0]<stdout>:         512           128     float     sum      -1    72.00    0.01    0.01      0    71.11    0.01    0.01      0
[1,0]<stdout>:        1024           256     float     sum      -1    72.34    0.01    0.01      0    72.39    0.01    0.01      0
[1,0]<stdout>:        2048           512     float     sum      -1    74.97    0.03    0.03      0    74.22    0.03    0.03      0
[1,0]<stdout>:        4096          1024     float     sum      -1    80.03    0.05    0.05      0    79.39    0.05    0.05      0
[1,0]<stdout>:        8192          2048     float     sum      -1    89.68    0.09    0.09      0    88.78    0.09    0.09      0
[1,0]<stdout>:       16384          4096     float     sum      -1    95.54    0.17    0.17      0    94.89    0.17    0.17      0
[1,0]<stdout>:       32768          8192     float     sum      -1    109.7    0.30    0.30      0    108.3    0.30    0.30      0
[1,0]<stdout>:       65536         16384     float     sum      -1    112.6    0.58    0.58      0    111.5    0.59    0.59      0
[1,0]<stdout>:      131072         32768     float     sum      -1    142.0    0.92    0.92      0    141.3    0.93    0.93      0
[1,0]<stdout>:      262144         65536     float     sum      -1    281.7    0.93    0.93      0    281.3    0.93    0.93      0
[1,0]<stdout>:      524288        131072     float     sum      -1    382.5    1.37    1.37      0    381.4    1.37    1.37      0
[1,0]<stdout>:     1048576        262144     float     sum      -1    475.7    2.20    2.20      0    477.6    2.20    2.20      0
[1,0]<stdout>:     2097152        524288     float     sum      -1    779.3    2.69    2.69      0    779.7    2.69    2.69      0
[1,0]<stdout>:     4194304       1048576     float     sum      -1   1369.3    3.06    3.06      0   1356.9    3.09    3.09      0
[1,0]<stdout>:     8388608       2097152     float     sum      -1   3039.0    2.76    2.76      0   3016.8    2.78    2.78      0
[1,0]<stdout>:    16777216       4194304     float     sum      -1   6375.0    2.63    2.63      0   6341.5    2.65    2.65      0
[1,0]<stdout>:    33554432       8388608     float     sum      -1    12124    2.77    2.77      0    12060    2.78    2.78      0
[1,0]<stdout>:    67108864      16777216     float     sum      -1    23665    2.84    2.84      0    23565    2.85    2.85      0
[1,0]<stdout>:   134217728      33554432     float     sum      -1    47018    2.85    2.85      0    46881    2.86    2.86      0
[1,0]<stdout>:   268435456      67108864     float     sum      -1    94155    2.85    2.85      0    93550    2.87    2.87      0
[1,0]<stdout>:   536870912     134217728     float     sum      -1   185925    2.89    2.89      0   187473    2.86    2.86      0
[1,0]<stdout>:  1073741824     268435456     float     sum      -1   372377    2.88    2.88      0   371851    2.89    2.89      0
[1,0]<stdout>:  2147483648     536870912     float     sum      -1   745248    2.88    2.88      0   745261    2.88    2.88      0
[1,0]<stdout>:  4294967296    1073741824     float     sum      -1  1491861    2.88    2.88      0  1490178    2.88    2.88      0
[1,0]<stdout>:# Out of bounds values : 0 OK
[1,0]<stdout>:# Avg bus bandwidth    : 1.35737
[1,0]<stdout>:#
[1,0]<stdout>:

 

  • 리소스 제거
$ terraform destroy -target="module.eks_blueprints_addons" -auto-approve
$ terraform destroy -target="module.eks" -auto-approve
$ terraform destroy -auto-approve
728x90