brew tap aws/tap
brew install eksdemoeksdemo create cluster gpusharing -i t3.large -N 2 --region us-west-2 --dry-run eksdemo create cluster gpusharing -i t3.large -N 2 --region us-west-2 
머신러닝과 딥러닝은 이제 기업 경쟁력의 핵심입니다. 이를 실현하기 위한 필수 조건은 고성능 GPU 인프라입니다. 하지만 전통적인 베어메탈 환경에서 GPU를 사용하는 데에는 여러 한계가 존재했고, 이를 해결하기 위해 컨테이너 기반 GPU 가상화 기술이 빠르게 진화해왔습니다.
컨테이너는 Linux Cgroups·Namespaces로 CPU, 메모리, 네트워크를 격리하지만, GPU는 물리적 장치 파일·드라이버 의존성 등 고유 제약이 있습니다.
/dev/nvidia* 파일 직접 다루기 복잡docker run --device=/dev/nvidia0:/dev/nvidia0 \
--device=/dev/nvidiactl:/dev/nvidiactl \
-v /usr/local/cuda:/usr/local/cuda \
tensorflow/tensorflow:latest-gpu
# Docker 19.03 이후
docker run --gpus '"device=0,1"' nvidia/cuda:11.0-base nvidia-smi
-gpus 옵션으로 장치 자동 감지resources:
limits:
nvidia.com/gpu: 2
컨테이너 기반 GPU 가상화는 이미 표준 인프라가 되었으며, 주요 효과는 다음과 같습니다:
eksdemo create nodegroup gpu -i g5.4xlarge -N 1 -c gpusharing --dry-run eksdemo create nodegroup gpu -i g5.4xlarge -N 1 -c gpusharingkubectl get node --label-columns=node.kubernetes.io/instance-type,eks.amazonaws.com/capacityType,topology.kubernetes.io/zonekubectl label node i-0af783eca345807e8.us-west-2.compute.internal eks-node=gpucurl -O https://raw.githubusercontent.com/sanjeevrg89/eks-gpu-sharing-demo/refs/heads/main/nvdp-values.yamlhelm repo add nvdp https://nvidia.github.io/k8s-device-plugin
helm repo update
helm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace kube-system \
-f nvdp-values.yaml \
--version 0.14.0kubectl get daemonset -n kube-system | grep nvidiakubectl get nodes -o json | jq -r '.items[] | select(.status.capacity."nvidia.com/gpu" != null) | {name: .metadata.name, capacity: .status.capacity}'kubectl create namespace gpu-demo
cat << EOF > cifar10-train-deploy.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: tensorflow-cifar10-deployment
namespace: gpu-demo
labels:
app: tensorflow-cifar10
spec:
replicas: 5
selector:
matchLabels:
app: tensorflow-cifar10
template:
metadata:
labels:
app: tensorflow-cifar10
spec:
containers:
- name: tensorflow-cifar10
image: public.ecr.aws/r5m2h0c9/cifar10_cnn:v2
resources:
limits:
nvidia.com/gpu: 1
EOF
$ kubectl apply -f cifar10-train-deploy.yamlwatch -d 'kubectl get pods -n gpu-demo' kubectl get pods -n gpu-demokubectl describe pod tensorflow-cifar10-deployment-7c6f89c8d6-k7z77 -n gpu-democat << EOF > nvidia-device-plugin.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: nvidia-device-plugin
namespace: kube-system
data:
any: |-
version: v1
flags:
migStrategy: none
*sharing:
timeSlicing:
resources:
- name: nvidia.com/gpu
replicas: 10*
EOF
$ kubectl apply -f nvidia-device-plugin.yamlhelm upgrade -i nvdp nvdp/nvidia-device-plugin \
--namespace kube-system \
-f nvdp-values.yaml \
--version 0.14.0 \
--set config.name=nvidia-device-plugin \
--forcekubectl get nodes -o json | jq -r '.items[] | select(.status.capacity."nvidia.com/gpu" != null) | {name: .metadata.name, capacity: .status.capacity}'kubectl get pods -n gpu-demokubectl logs tensorflow-cifar10-deployment-7c6f89c8d6-k7z77 -n gpu-demo | grep memory최근 GPT‑3(1,750억 파라미터), Megatron‑Turing NLG(5,300억 파라미터), PaLM(5,400억 파라미터) 등 초거대 모델이 등장하면서, 더 이상 단일 GPU만으로는 학습이 불가능해졌습니다.
이제는 멀티 GPU + 멀티 노드 기반의 분산 학습이 필수이며, 이로 인해 네트워크 병목 문제가 본격적으로 대두되고 있습니다.
분산 딥러닝 학습 중 대표적인 통신 연산은 다음과 같습니다.
AllReduce
모든 GPU가 각자의 그래디언트를 주고받으며 평균을 계산

참조 : 기시다 AEWS 3기
AllGather, ReduceScatter, Broadcast 등
예시:
8개의 GPU 노드가 AllReduce를 수행할 때, 통신에 소요되는 시간이 학습 전체의 약 70%를 차지하고, 이로 인해 GPU 사용률이 60~70% 수준으로 떨어지는 사례가 보고되었습니다.
분산 학습의 병목을 완화하기 위해 NVIDIA가 제공하는 통신 라이브러리입니다.
단점: 노드 간 네트워크 컨트롤러나 스위치 수준의 병목까지 완전히 해결하기에는 한계가 있습니다.
AWS는 GPU 간 고성능 네트워크를 위해 EFA(Elastic Fabric Adapter) 를 제공합니다.

AWS EKS와 결합했을 때 얻을 수 있는 장점을 정리하면 다음과 같습니다.
| 분류 | 주요 내용 |
|---|---|
| 인프라 관리 | Kubernetes를 통한 GPU 및 EFA 리소스 선언적 관리, 오토스케일링 |
| 비용 최적화 | GPU 활용률 90% 이상 달성, 학습 시간 단축, Spot 인스턴스와의 연동으로 비용 절감 |
| 성능 향상 | 초저지연 네트워크 통신 제공, 대규모 분산 학습 워크로드 가속 |
| 개발자 경험 | 일관된 실행 환경 제공, 실험 재현성 확보, CI/CD 파이프라인과의 통합 용이 |
EFA는 다음과 같은 고성능 인스턴스에서 사용할 수 있습니다.
자세한 내용은 AWS 공식 문서의 EFA 지원 인스턴스 항목을 참고하세요.
git clone https://github.com/aws-ia/terraform-aws-eks-blueprints.git
cd terraform-aws-eks-blueprints/patterns/nvidia-gpu-efased -i "s/p5.48xlarge/g5.8xlarge/g" eks.tf # spec 변경
sed -i "s/us-west-2/us-east-1/g" main.tf # region 변경terraform init
terraform apply -target="module.vpc" -auto-approve
terraform apply -target="module.eks" -auto-approve
terraform apply -auto-approveaws eks --region us-east-1 update-kubeconfig --name nvidia-gpu-efakubectl get nodes -L node.kubernetes.io/instance-typekubectl apply -f https://raw.githubusercontent.com/kubeflow/mpi-operator/v0.4.0/deploy/v2beta1/mpi-operator.yamlkubectl apply -f https://raw.githubusercontent.com/aws-samples/aws-do-eks/main/Container-Root/eks/deployment/kubeflow/mpi-operator/clusterrole-mpi-operator.yamlsed -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./generate-efa-info-test.sh
kubectl apply -f ./efa-info-test.yamlwatch 'kubectl get pods'kubectl logs -f $(kubectl get pods | grep launcher | cut -d ' ' -f 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.yamlwatch 'kubectl get pods'kubectl logs -f $(kubectl get pods | grep launcher | cut -d ' ' -f 1)terraform destroy -target="module.eks_blueprints_addons" -auto-approve
terraform destroy -target="module.eks" -auto-approve
terraform destroy -auto-approve
<figure>
<img src='https://velog.velcdn.com/images/gjrjr4545/post/0047d1c3-4bf5-4858-9104-ee19630136cd/image.png' alt='missing' />
<em>출처 : https://catalog.workshops.aws/genaifsxeks/en-US/010-introduction</em>
aws cloud9 update-environment --environment-id ${C9_PID} --managed-credentials-action DISABLE
rm -vf ${HOME}/.aws/credentialsaws sts get-caller-identity 
TOKEN=`curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600"`
export AWS_REGION=$(curl -s -H "X-aws-ec2-metadata-token: $TOKEN" http://169.254.169.254/latest/meta-data/placement/region)export CLUSTER_NAME=eksworkshopecho $AWS_REGION
echo $CLUSTER_NAME 
aws eks update-kubeconfig --name $CLUSTER_NAME --region $AWS_REGIONkubectl get nodes 
kubectl get pods --namespace karpenter 

| 구성 요소 | 설명 |
|---|---|
| CSI 드라이버 | Kubernetes와 외부 스토리지 시스템(FSx 등)을 연결하는 인터페이스 |
| StorageClass | 스토리지의 속성(성능, 백업 정책 등)을 정의한 스토리지 "템플릿" |
| PV (Persistent Volume) | EKS 관리자가 프로비저닝한 실제 스토리지 리소스 |
| PVC (Persistent Volume Claim) | Pod가 요청하는 스토리지 요구사항 (크기, 접근 모드 등) |
| 방식 | 설명 | 사용 시점 |
|---|---|---|
| 정적 프로비저닝 | 관리자가 미리 FSx 인스턴스 + PV를 생성해두고, 사용자는 PVC로 연결 | 사전 준비된 스토리지가 필요한 경우 |
| 동적 프로비저닝 | 사용자가 PVC를 생성하면, Kubernetes가 자동으로 FSx 인스턴스 + PV를 생성 | 필요 시점에 스토리지 자동 생성 |
ACCOUNT_ID=$(aws sts get-caller-identity --query "Account" --output text)cat << EOF > fsx-csi-driver.json
{
"Version":"2012-10-17",
"Statement":[
{
"Effect":"Allow",
"Action":[
"iam:CreateServiceLinkedRole",
"iam:AttachRolePolicy",
"iam:PutRolePolicy"
],
"Resource":"arn:aws:iam::*:role/aws-service-role/s3.data-source.lustre.fsx.amazonaws.com/*"
},
{
"Action":"iam:CreateServiceLinkedRole",
"Effect":"Allow",
"Resource":"*",
"Condition":{
"StringLike":{
"iam:AWSServiceName":[
"fsx.amazonaws.com"
]
}
}
},
{
"Effect":"Allow",
"Action":[
"s3:ListBucket",
"fsx:CreateFileSystem",
"fsx:DeleteFileSystem",
"fsx:DescribeFileSystems",
"fsx:TagResource"
],
"Resource":[
"*"
]
}
]
}
EOFaws iam create-policy \
--policy-name Amazon_FSx_Lustre_CSI_Driver \
--policy-document file://fsx-csi-driver.json 
eksctl create iamserviceaccount \
--region $AWS_REGION \
--name fsx-csi-controller-sa \
--namespace kube-system \
--cluster $CLUSTER_NAME \
--attach-policy-arn arn:aws:iam::$ACCOUNT_ID:policy/Amazon_FSx_Lustre_CSI_Driver \
--approve 
export ROLE_ARN=$(aws cloudformation describe-stacks --stack-name "eksctl-${CLUSTER_NAME}-addon-iamserviceaccount-kube-system-fsx-csi-controller-sa" --query "Stacks[0].Outputs[0].OutputValue" --region $AWS_REGION --output text)echo $ROLE_ARNkubectl apply -k "github.com/kubernetes-sigs/aws-fsx-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.2"kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-fsx-csi-driver 
kubectl annotate serviceaccount -n kube-system fsx-csi-controller-sa \
eks.amazonaws.com/role-arn=$ROLE_ARN --overwrite=truekubectl get sa/fsx-csi-controller-sa -n kube-system -o yaml 
PV 볼륨 생성 두가지 방법
실습
cd /home/ec2-user/environment/eks/FSxLFSXL_VOLUME_ID=$(aws fsx describe-file-systems --query 'FileSystems[].FileSystemId' --output text)
DNS_NAME=$(aws fsx describe-file-systems --query 'FileSystems[].DNSName' --output text)
MOUNT_NAME=$(aws fsx describe-file-systems --query 'FileSystems[].LustreConfiguration.MountName' --output text) cat fsxL-persistent-volume.yaml 
VOLUME_ID, DNS_NAME, 를 MOUNT_NAMEFSx Lustre 인스턴스의 실제 값으로 변경sed -i'' -e "s/FSXL_VOLUME_ID/$FSXL_VOLUME_ID/g" fsxL-persistent-volume.yaml
sed -i'' -e "s/DNS_NAME/$DNS_NAME/g" fsxL-persistent-volume.yaml
sed -i'' -e "s/MOUNT_NAME/$MOUNT_NAME/g" fsxL-persistent-volume.yamlcat fsxL-persistent-volume.yaml 
kubectl apply -f fsxL-persistent-volume.yamlkubectl get pv 
kubectl apply -f fsxL-claim.yamlkubectl get pv,pvc 
console에 접근하면 다음과 같이 FSx가 생성된것을 확인할수 있습니다.

또한 모니터링 및 성능 텝에 접근하시면 다음과 같은 성능지표를 확인할수 있습니다.


| 구성요소 | 설명 |
|---|---|
| Mistral-7B-Instruct | 70억 파라미터의 오픈소스 LLM. 지시문 기반 챗봇에 최적화 |
| vLLM | LLM 추론용 고성능 오픈소스 서버 라이브러리. OpenAI API 호환, HuggingFace 통합 |
| Amazon EKS | vLLM + WebUI Pod 실행 플랫폼. Karpenter로 Inferentia2 기반 노드 자동 확장 |
| Amazon FSx for Lustre | S3와 연동되는 고성능 파일 시스템. 모델 데이터를 빠르게 제공 |
| Amazon S3 | Mistral-7B 모델 저장소. Lustre와 연동 |
| AWS Inferentia2 (Inf2 인스턴스) | 저비용 고성능 딥러닝 추론 가속기. 최대 12개 가속기, HBM 32GB, 190TFLOPS 성능 |
| AWS Neuron SDK | PyTorch/TensorFlow와 통합되는 Inferentia용 컴파일러/런타임/프로파일러 툴킷 |
| 항목 | 설명 |
|---|---|
| 용도 | 대규모 추론 전용 가속기 (LLM, 이미지/비디오 생성 등) |
| 성능 | 가속기당 32GB HBM / 190TFLOPS FP16 |
| 확장성 | EC2 인스턴스당 최대 12개 Inferentia2 탑재 |
| Neuron SDK | PyTorch/TensorFlow 통합, 코드 변경 최소화, 성능 최적화 제공 |
cd /home/ec2-user/environment/eks/genaicat inferentia_nodepool.yaml# inferentia_nodepool.yaml
apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
name: inferentia
labels:
intent: genai-apps
NodeGroupType: inf2-neuron-karpenter
spec:
template:
spec:
taints:
- key: aws.amazon.com/neuron
value: "true"
effect: "NoSchedule"
requirements:
- key: "karpenter.k8s.aws/instance-family"
operator: In
values: ["inf2"]
- key: "karpenter.k8s.aws/instance-size"
operator: In
values: [ "xlarge", "2xlarge", "8xlarge", "24xlarge", "48xlarge"]
- key: "kubernetes.io/arch"
operator: In
values: ["amd64"]
- key: "karpenter.sh/capacity-type"
operator: In
values: ["spot", "on-demand"]
nodeClassRef:
group: karpenter.k8s.aws
kind: EC2NodeClass
name: inferentia
limits:
cpu: 1000
memory: 1000Gi
disruption:
consolidationPolicy: WhenEmpty
# expireAfter: 720h # 30 * 24h = 720h
consolidateAfter: 180s
weight: 100
---
apiVersion: karpenter.k8s.aws/v1
kind: EC2NodeClass
metadata:
name: inferentia
spec:
amiFamily: AL2
amiSelectorTerms:
- alias: al2@v20240917
blockDeviceMappings:
- deviceName: /dev/xvda
ebs:
deleteOnTermination: true
volumeSize: 100Gi
volumeType: gp3
role: "Karpenter-eksworkshop"
subnetSelectorTerms:
- tags:
karpenter.sh/discovery: "eksworkshop"
securityGroupSelectorTerms:
- tags:
karpenter.sh/discovery: "eksworkshop"
tags:
intent: apps
managed-by: karpenterkubectl apply -f inferentia_nodepool.yamlkubectl get nodepool,ec2nodeclass inferentia 
kubectl apply -f https://raw.githubusercontent.com/aws-neuron/aws-neuron-sdk/master/src/k8/k8s-neuron-device-plugin-rbac.yml
kubectl apply -f https://raw.githubusercontent.com/aws-neuron/aws-neuron-sdk/master/src/k8/k8s-neuron-device-plugin.ymlkubectl apply -f https://raw.githubusercontent.com/aws-neuron/aws-neuron-sdk/master/src/k8/k8s-neuron-scheduler-eks.yml
kubectl apply -f https://raw.githubusercontent.com/aws-neuron/aws-neuron-sdk/master/src/k8/my-scheduler.ymlcat mistral-fsxl.yamlapiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-mistral-inf2-deployment
spec:
replicas: 1
selector:
matchLabels:
app: vllm-mistral-inf2-server
template:
metadata:
labels:
app: vllm-mistral-inf2-server
spec:
tolerations:
- key: "aws.amazon.com/neuron"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: inference-server
image: public.ecr.aws/u3r1l1j7/eks-genai:neuronrayvllm-100G-root
resources:
requests:
aws.amazon.com/neuron: 1
limits:
aws.amazon.com/neuron: 1
args:
- --model=$(MODEL_ID)
- --enforce-eager
- --gpu-memory-utilization=0.96
- --device=neuron
- --max-num-seqs=4
- --tensor-parallel-size=2
- --max-model-len=10240
- --served-model-name=mistralai/Mistral-7B-Instruct-v0.2-neuron
env:
- name: MODEL_ID
value: /work-dir/Mistral-7B-Instruct-v0.2/
- name: NEURON_COMPILE_CACHE_URL
value: /work-dir/Mistral-7B-Instruct-v0.2/neuron-cache/
- name: PORT
value: "8000"
volumeMounts:
- name: persistent-storage
mountPath: "/work-dir"
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: fsx-lustre-claim
---
apiVersion: v1
kind: Service
metadata:
name: vllm-mistral7b-service
spec:
selector:
app: vllm-mistral-inf2-server
ports:
- protocol: TCP
port: 80
targetPort: 8000kubectl apply -f mistral-fsxl.yaml
배포 확인
watch 'kubectl get pods'



배포된 vLLM 사용을 위한 webUI 채팅 애플리케이션 배포
kubectl apply -f open-webui.yamlkubectl get ing 






test/ 추가 !



저장을 눌러 구성 진행
기존 객체를 복사하지 않도록 진행


cd /home/ec2-user/environment/eks/FSxLkubectl get pods 
kubectl exec -it vllm-mistral-inf2-deployment-7d886c8cc8-4cdcg -- bashdf -h 
cd /work-dir/
ls -ll 
cd Mistral-7B-Instruct-v0.2/
ls -ll 
cd /work-dir
mkdir test
cd test
cp /work-dir/Mistral-7B-Instruct-v0.2/README.md /work-dir/test/testfile
ls -ll /work-dir/test
VPC_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region $AWS_REGION --query "cluster.resourcesVpcConfig.vpcId" --output text)
SUBNET_ID=$(aws eks describe-cluster --name $CLUSTER_NAME --region $AWS_REGION --query "cluster.resourcesVpcConfig.subnetIds[0]" --output text)
SECURITY_GROUP_ID=$(aws ec2 describe-security-groups --filters Name=vpc-id,Values=${VPC_ID} Name=group-name,Values="FSxLSecurityGroup01" --query "SecurityGroups[*].GroupId" --output text)
echo $SUBNET_ID
echo $SECURITY_GROUP_ID 
cd /home/ec2-user/environment/eks/FSxLkind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: fsx-lustre-sc
provisioner: fsx.csi.aws.com
parameters:
subnetId: SUBNET_ID
securityGroupIds: SECURITY_GROUP_ID
deploymentType: SCRATCH_2
fileSystemTypeVersion: "2.15"
mountOptions:
- flocksed -i'' -e "s/SUBNET_ID/$SUBNET_ID/g" fsxL-storage-class.yaml
sed -i'' -e "s/SECURITY_GROUP_ID/$SECURITY_GROUP_ID/g" fsxL-storage-class.yamlkubectl apply -f fsxL-storage-class.yamlkubectl get sc 
kubectl apply -f fsxL-dynamic-claim.yamlkubectl describe pvc/fsx-lustre-dynamic-claim 
kubectl get pvc 
cd /home/ec2-user/environment/eks/FSxLaws ec2 describe-subnets --subnet-id $SUBNET_ID --region $AWS_REGION | jq .Subnets[0].AvailabilityZonevi pod_performance.yaml# 1번 : 맨 아래 두줄 주석 해제
# 2번 : topology.kubernetes.io/zone 변경
kind: Pod
apiVersion: v1
metadata:
name: fsxl-performance
spec:
containers:
- name: fsxl-performance
image: nginx
ports:
- containerPort: 80
name: "http-server"
volumeMounts:
- name: persistent-storage
mountPath: /data
volumes:
- name: persistent-storage
persistentVolumeClaim:
claimName: fsx-lustre-dynamic-claim
# nodeSelector:
# topology.kubernetes.io/zone: us-east-2c
kubectl apply -f pod_performance.yamlkubectl get pods 
kubectl exec -it fsxl-performance -- bashapt-get update
apt-get install fio ioping -yioping -c 20 . 
mkdir -p /data/performance
cd /data/performance
fio --randrepeat=1 --ioengine=libaio --direct=1 --gtod_reduce=1 --name=fiotest --filename=testfio8gb --bs=1MB --iodepth=64 --size=8G --readwrite=randrw --rwmixread=50 --numjobs=8 --group_reporting --runtime=10 