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 직접 통신 최적화
- 토폴로지 인식 통신 알고리즘
- 자동 튜닝 메커니즘
- OS 바이패스 기술: EFA는 운영 체제 커널을 우회하여 사용자 공간 애플리케이션이 네트워크 어댑터와 직접 통신 가능
- Amazon EKS에 EFA를 통합함으로써 얻을 수 있는 주요 이점:
- 인프라 관리 간소화
- Kubernetes를 통한 선언적 인프라 관리
- GPU 및 EFA 리소스의 자동 검출 및 할당
- 자동 확장 및 축소 기능
- 비용 최적화
- 리소스 활용도 향상 (GPU 활용률 90% 이상)
- 학습 시간 단축으로 인한 인스턴스 비용 절감
- Spot 인스턴스와의 통합 가능성
- 성능 최적화
- 노드 간 초저지연 통신
- 분산 학습 확장성 향상
- 대규모 모델 학습 가속화
- 개발자 경험 개선
- 일관된 개발 및 배포 환경
- 재현 가능한 실험 설정
- 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 등
- 대규모 모델이 등장하면서, 이제 단일 GPU로는 학습이 불가능해짐.
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
'2025_AEWS Study' 카테고리의 다른 글
11주차 - ML Infra(GPU) on EKS(1) (0) | 2025.04.28 |
---|---|
12주차 - Amazon VPC Lattice for Amazon EKS(2) (0) | 2025.04.28 |
12주차 - Amazon VPC Lattice for Amazon EKS(1) (0) | 2025.04.27 |
10주차 - K8s 시크릿 관리 Update(5) (0) | 2025.04.14 |
10주차 - K8s 시크릿 관리 Update(4) (0) | 2025.04.14 |