일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 텔레메트리란
- Mac Terraform
- Terrafrom
- /etc/fstab 설정
- 테라폼 자동완성
- docker -i -t
- EC2
- 리눅스
- MFA 분실
- 리눅스 시간대
- 테라폼 캐시
- 디스크 성능테스트
- 테라폼 맥
- 테라폼 설치
- xfs_quota
- epxress-generator
- EBS 최적화
- AWS EBS
- Authenticator
- 볼륨추가
- MFA 인증
- docker 상태
- EBS
- 컨테이너 터미널
- 컨테이너 터미널 로그아웃
- /etc/fstab 뜻
- AWS
- ebs 재부팅
- ebs 마운트
- 볼륨 연결
- Today
- Total
I got IT
GenAI on EKS with inferentia & FSx Workshop 본문
※ 해당 글은 가시다님의 AEWS 스터디 내용을 참고하고 스터디 협력자 이신 AWS 최영락 님의 도움으로 워크샵 실습을 내용을 토대로 작성하였습니다.
실습 개요
이 워크숍에서는 오픈소스 LLM을 기반으로 한 vLLM을 사용하여 생성형 AI 기반의 대화형 챗봇 애플리케이션을 구축합니다.
이를 위해 다음과 같은 AWS 서비스를 다룹니다.
- Amazon EKS – 오케스트레이션 계층
- Amazon FSx for Lustre – LLM을 호스팅
- AWS Inferentia – 가속화된 컴퓨팅 리소스
해당 워크숍에서는 Amazon FSx, EKS, AWS Inferentia에 각각 구성 요소를 배포하여 생성형 AI 챗봇 애플리케이션을 만들어 봅니다.
또한 이러한 패턴을 쉽게 활용하여 나만의 생성형 AI 및 머신러닝 워크로드를 구축하는 방법도 배울 수 있습니다.
실습 아키텍처
- 사용자(User)가 Open WebUI를 통해 요청 → ALB를 통해 전달
- Open WebUI Pod가 사용자 입력을 처리하고 → vLLM Pod로 전달
- vLLM Pod는 Amazon FSx for Lustre에 마운트된 모델 파라미터를 참조하여 추론 수행
- FSx for Lustre는 모델 파일을 Amazon S3에서 가져와 캐싱 (import)
- vLLM은 AWS Inferentia를 통해 빠르게 추론을 수행하고 → 결과를 Open WebUI에 반환
- 사용자에게 응답 전송
실습 목표
- Overall: Amazon EKS 클러스터에 vLLM과 WebUI 파드를 배포하여 생성형 AI 챗봇 애플리케이션을 Kubernetes 환경에서 구축합니다.
- LLM에 적합한 스토리지 사용:
- Amazon FSx for Lustre 및 Amazon S3를 통해 Mistral-7B 모델을 저장하고 접근합니다.
- Amazon FSx for Lustre 및 Amazon S3를 통해 고성능의 확장 가능한 데이터 계층으로 구성하여,모델과 데이터를 저장하는 기반으로 사용합니다.
- 데이터 계층에서의 운영 효율성도 확보할 수 있습니다: 컨테이너 파드 간에 하나의 모델 데이터를 중복 없이 공유하고, 여러 리전 간에도 데이터를 원활하게 공유하거나 DR(재해복구) 시나리오에 대응할 수 있습니다.
- 고속 컴퓨팅 타입 사용: AWS Inferentia Accelerator를 활용해 생성형 AI 워크로드에 고속 컴퓨팅 성능을 제공합니다.
- EKS기반의 유연한 확장: Karpenter를 사용하여, 추가적인 파드 요청이 있을 때 필요한 노드를 자동으로 확장하여, 유연한 확장성과 운영 효율성을 확보할 수 있습니다.
- EKS for AI Service: AWS Inferentia 가속 컴퓨팅 노드풀을 Amazon EKS 클러스터 내에 구성하여,생성형 AI 애플리케이션의 실행을 위한 전용 노드로 활용합니다.
실습 구성 요소 특징
Mistral-7B-Instruct model
이번 실습에 사용된 LLM 모델은 오픈소스 AI 모델과 공유 플랫폼인 Hugging Face의 Mistral-7B-Instruct model 모델 입니다. 🔗
해당 모델은 70억 파라미터의 오픈소스 LLM이며, 대화형 프롬프트에 최적화된 지시문 튜닝 버전
으로 실제 서비스, 실험, vLLM 추론 환경에서 널리 활용된다고 합니다.
항목 | 내용 |
---|---|
모델명 | Mistral-7B-Instruct v0.1 |
파라미터 수 | 약 70억 (7B) |
구조 | Decoder-only Transformer (GPT류) |
컨텍스트 길이 | 최대 32,768 tokens |
릴리스일 | 2023년 9월 (Mistral-7B), 10월 (Instruct 버전) |
오픈소스 여부 | ✅ Apache 2.0 라이선스로 공개 |
학습 방식 | Supervised fine-tuning + Chat/Instruct dataset |
vLLM 🔗
vLLM 은 Mistral-7B-Instruct 같은 LLM을 쉽게 배포하고 추론할 수 있도록 돕는 오픈소스 LLM 추론/서빙 프레임워크 입니다. OpenAI API와 호환되는 인터페이스를 제공하므로 기존 LLM 기반 앱에 쉽게 연결할 수 있습니다.
vLLM 프레임워크 특징
빠른 속도:
- 최신 수준의 서빙 처리량 (throughput) 제공
- PagedAttention을 활용한 attention key/value 메모리의 효율적인 관리
- 들어오는 요청을 지속적으로 배치 처리 (continuous batching)
- CUDA/HIP 그래프 기반의 빠른 모델 실행
유연하고 쉬운 사용성:
- HuggingFace의 인기 모델들과 자연스럽게 통합 가능
- OpenAI 호환 API 서버 제공
- Prefix caching 기능 지원
- AWS Neuron, NVIDIA GPU 등 다양한 칩셋을 지원
vLLM on Amazon EKS
유연한 워크로드 확장 및 신속한 배포환경을 위하여 Amazon Elastic Kubernetes Service(EKS) 상에 vLLM 프레임워크를 사용하여 Mistral-7B-Instruct 모델을 배포할 예정입니다.
Karpenter를 활용해 AWS Inferentia2 기반 EC2 노드(생성형 AI를 위한 가속 컴퓨팅)를 자동으로 프로비저닝하며,해당 노드에서는 컨테이너 이미지로부터 vLLM 파드를 실행하게 됩니다.
Open WebUI 🔗
이번 실습에서는 Mistral-7B-Instruct 모델을 사용하기 위해 유저 인터페이스로 Open WebUI를 채택하였습니다.
Open WebUI는 오픈소스 기반의 LLM(대형 언어 모델) 인터페이스 웹앱입니다. 주로 vLLM, Ollama, LM Studio, text-generation-webui 같은 추론 서버와 연동해 사용자가 채팅형태로 모델과 상호작용할 수 있도록 도와줍니다.
Amazon FSx for Lustre + S3 스토리지 구성
FSx for Lustre 파일 시스템을 생성할 때 또는 생성 후에 S3 버킷(또는 접두사)과 데이터 리포지토리 연결(Data Repository Association, DRA)을 설정할 수 있습니다. 이 연결을 통해 S3 버킷의 객체가 Lustre 파일 시스템 내에서 파일로 자동으로 표시됩니다. 🔗
- 이로 인해 S3 객체를 로컬 파일시스템에서 파일로 인식 및 조회가 가능하고,
- S3로 양방향 동기화 및 내보내기 (r/w)가 가능합니다.
사용 사례
FSx for Lustre는 S3 버킷을 "직접 mount"하는 것이 아니라, S3와의 데이터 리포지토리 연결을 통해 Lustre 파일 시스템에서 S3 데이터를 파일로 노출하는 방식입니다. 고성능 컴퓨팅(HPC), 머신러닝, 대규모 데이터 분석 등에서 S3 데이터를 빠르게 처리해야 할 때 적합합니다
캐싱 매커니즘
동작 방식: DRA를 설정하면 S3 버킷(또는 프리픽스)과 FSx for Lustre 파일 시스템의 특정 디렉터리가 연결됩니다. 이때 S3의 파일·디렉터리 메타데이터가 FSx for Lustre 파일 시스템에 로드되어, 사용자는 S3 객체를 파일처럼 볼 수 있습니다. 실제 파일 내용(데이터)은 사용자가 해당 파일을 처음 읽을 때 S3에서 FSx for Lustre로 온디맨드로 가져와 캐싱됩니다 🔗
AWS Inferentia Accelerator
AWS Inferentia Accelerator는 딥러닝(DL) 및 생성형 AI 추론 애플리케이션을 위한 고성능·저비용의 인스턴스 환경을 제공하기 위해 AWS가 직접 설계한 하드웨어입니다. 즉 EC2 인스턴스 유형으로 선택할 수 있습니다.
특히 Inferentia2 기반의 Amazon EC2 Inf2 인스턴스는 대형 언어 모델(LLM)과 같이 점점 더 복잡해지는 모델을 배포하는 데 최적화되어 있습니다.
Neuron SDK 🔗
AWS Neuron SDK는 컴파일러, 런타임, 프로파일링 도구가 포함된 SDK로, 딥러닝 워크로드에 대해 고성능·비용 효율적인 가속을 가능하게 해줍니다.
Neuron SDK는 PyTorch, TensorFlow와 같은 주요 프레임워크와 네이티브로 통합되어, 개발자는 기존의 코드와 워크플로우를 그대로 유지하면서도 Inferentia Accelerator 위에서 모델을 실행할 수 있습니다.
실습 환경 확인
워크샵에 미리 구성된 AWS Cloud9 IDE 환경에 접속합니다. EKS 클러스터에 접근하기 위해 해당 권한을 가진 역할을 부여하여 줍니다. Cloud9 으로 생성된 임시 권한은 사용하지 않기 때문에 이를 비활성화 하여 줍니다.
권한 설정
AWS managed temporary credentials 비활성화
aws cloud9 update-environment --environment-id ${C9_PID} --managed-credentials-action DISABLE
rm -vf ${HOME}/.aws/credentials
현재 역할 확인
aws 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)
EKS 클러스터 접근 구성
실습에서 사용할 eks 클러스터 이름을 변수로 등록합니다.
export CLUSTER_NAME=eksworkshop
클러스터 확인
echo $AWS_REGION
echo $CLUSTER_NAME
EKS 접근을 위해 Kubeconfig를 업데이트합니다.
aws eks update-kubeconfig --name $CLUSTER_NAME --region $AWS_REGION
노드 접근 확인
kubectl get nodes
실습 인프라 확인
해당 워크샵의 인프라는 테라폼으로 설치가 되었습니다. 해당 테라폼 코드는 EKS 실습에 많이 사용되는 AWS terraform 블루프린트 코드를 참고합니다. 🔗
카펜터 구성은 어떻게 되었는지 살펴봅니다.
kubectl -n karpenter get deploy/karpenter -o yaml
- helm 으로 설치됨 Chart 버전: 1.0.1
- replicas: 2 → 고가용성 구성
- RollingUpdate. maxSurge: 25%, maxUnavailable: 1.
- 한 번에 25%까지 신규 파드를 먼저 띄울 수 있고,
- 최대 1개의 파드가 동시에 unavailable 가능 → 무중단 롤링 배포 지원
- CLUSTER_ENDPOINT
- 새 노드가 연결할 외부 쿠버네티스 클러스터 엔드포인트입니다. 엔드포인트가 지정되지 않으면 노드는 DescribeCluster API를 사용하여 클러스터 엔드포인트를 검색합니다.
- INTERRUPTION_QUEUE
- EKS Terraform 블루프린트로 생성된 SQS 대기열의 엔드포인트입니다. 이 SQS 대기열은 Spot 중단 알림 및 AWS 상태 이벤트를 저장하는 데 사용됩니다.
카펜터 파드 조회
kubectl get pods --namespace karpenter
카펜터 로그 표시
# 카펜터 로그 조회 명령어 alias 등록
alias kl='kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter --all-containers=true -f --tail=20'
# alias 로 조회
kl
스토리지 구성
FSx for lustre를 EKS CSI 드라이버로 연결하는 방법에 대해서는 다음 공식문서를 참고할 수 있습니다. 🔗
스토리지 아키텍처
이 워크숍에서는 Mistral-7B-Instruct 모델을 Amazon S3 버킷에 저장합니다. 이 버킷은 Amazon FSx for Lustre 파일 시스템과 연결되며, vLLM 컨테이너는 Generative AI ChatBot 애플리케이션에 이를 사용합니다.
- FSx for Lustre 스토리지 인스턴스 프로비저닝
- CSI 드라이버를 사용하여 FSx for Lustre 스토리지 연동
- vLLM을 호스팅하는 애플리케이션에서 PV로 활용
CSI 드라이버에 권한 수임 설정
CSI 드라이버가 사용자를 대신하여 AWS API 호출을 수행할 수 있도록 하는 IAM 정책 및 서비스 계정을 만듭니다. (IRSA)
아래 명령을 복사하여 실행하여 fsx-csi-driver.json 파일을 만듭니다. AWS Policy에 사용될 정책을 선언합니다.
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":[
"*"
]
}
]
}
EOF
위 정책 구문으로 AWS IAM Policy를 생성합니다. (Amazon_FSx_Lustre_CSI_Driver)
aws iam create-policy \
--policy-name Amazon_FSx_Lustre_CSI_Driver \
--policy-document file://fsx-csi-driver.json
CSI 드라이버가 사용할 IRSA를 생성합니다 (fsx-csi-controller-sa). 위에서 생성한 정책을 넣어줍니다.
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
해당 명렁어를 통해 fsx-csi-controller-sa 이름의 Service Account와 그에 사용될 IAM Role이 생성됩니다.
CSI 드라이버에 설정할 IAM Role arn(위에서 생성)을 별도로 저장해 둡니다.
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_ARN
CSI 드라이버를 배포합니다. 🔗
kubectl apply -k "github.com/kubernetes-sigs/aws-fsx-csi-driver/deploy/kubernetes/overlays/stable/?ref=release-1.2"
CSI 드라이버 배포 확인
kubectl get pods -n kube-system -l app.kubernetes.io/name=aws-fsx-csi-driver
CSI 드라이버에 위에서 생성한 IRSA를 연동하여 줍니다.
- aws-fsx-csi-driver CSI 드라이버에 연결된 SA를 조회합니다.
kubectl -n kube-system get pod fsx-csi-controller-6f4c577bd4-lm9h6 -o jsonpath='{.spec.serviceAccountName}'
- 해당 SA가 참조하는 AWS IAM Role을 조회합니다.
kubectl get sa -n kube-system fsx-csi-controller-sa -oyaml | grep role
기존에 생성되어 있던 기본 addon 역할을 참조하는 것을 확인할 수 있습니다.
- 다음 명령을 복사하여 실행하여 서비스 계정에 IAM 역할을 추가합니다.
kubectl annotate serviceaccount -n kube-system fsx-csi-controller-sa \
eks.amazonaws.com/role-arn=$ROLE_ARN --overwrite=true
서비스 어카운트 내용을 확인하여 이것이 성공했는지 확인할 수 있습니다.
kubectl get sa/fsx-csi-controller-sa -n kube-system -o yaml
워크로드에 PV 생성 및 연결
이번 실습에서는 영구 볼륨(PV)에 정적 프로비저닝 방식을 사용합니다 .
- 이미 Lustre 인스턴스용 FSx를 프로비저닝했으며, 이 인스턴스는 Mistral-7B 모델을 저장하는 Amazon S3 버킷에 연결되어 있습니다.
- 영구 볼륨 정의를 생성하고 영구 볼륨 클레임을 생성하여 vLLM Pod에서 이 스토리지 볼륨을 사용하여 Mistral-7B 모델 데이터에 액세스할 수 있도록 합니다.
0️⃣ PV 생성 준비작업
아래 명령을 실행하여 올바른 작업으로 직접 변경하면 이 연습에 대한 명령을 실행할 수 있습니다.
FSxL 볼륨을 구성하기 위한 작업 디렉토리로 이동합니다.
cd /home/ec2-user/environment/eks/FSxL
pvc, sc(storage class), pv, pod 등의 리소스 메니페스트 파일이 있습니다.
실습에 사용할 변수를 설정합니다. PV가 참조하는 FSx 정보를 등록합니다.
FSXL_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)
1️⃣ FSx for Lustre 인스턴스 확인
FSx for Lustre 인스턴스는 이미 생성되어 있습니다.
따라서 이 영구 볼륨 정의에서는 해당 1200GiB FSx for Lustre 인스턴스가 'fsx-pv'라는 이름을 사용하여 EKS 클러스터 리소스로 등록되도록 구성하기만 하면 됩니다.
데이터 리포지토리 탭에서 S3가 연결된 것도 확인할 수 있습니다. (DRA)
2️⃣ PV 생성
변수가 포함된 영구 볼륨(PV) YAML 파일 정의(fsxL-persistent-volume.yaml)를 살펴보겠습니다.
위에서 저장한 변수로 대입하여 실제 값을 fsxL-persistent-volume.yaml에 대입하여 줍니다.
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.yaml
해당 매니페스트로 pv 를 생성합니다.
kubectl apply -f fsxL-persistent-volume.yaml
kubectl get pv
3️⃣ PVC 생성
이제 이전 단계에서 정의한 PersistentVolume과 바인딩할 PersistentVolumeClaim(PVC)을 생성합니다. fsx-pv 의 volumeName 값을 사용하여 미리 프로비저닝된 PersistentVolume을 직접 참조하고 있습니다.
# fsxL-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fsx-lustre-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 1200Gi
volumeName: fsx-pv
pvc 생성하여 스토리지 배포
kubectl apply -f fsxL-claim.yaml
kubectl get pv,pvc
이제 FSx for Lustre 스토리지를 사용할 준비가 완료되었습니다.
생성형 AI 채팅 애플리케이션 배포
이번 실습에서는 Amazon EKS 클러스터에 vLLM Pod와 WebUI Pod를 배포하여 Kubernetes에서 생성 AI 챗봇 애플리케이션을 구성하고 배포하고, Amazon FSx for Lustre와 Amazon S3를 사용하여 Mistral-7B 모델을 저장하고 액세스하고, 생성 AI 워크로드에 대한 가속 컴퓨팅으로 AWS Inferentia Accelerators를 활용합니다.
추론 모델을 사용하기 위한 환경을 먼저 구성 후 WebUI 서비스를 배포하여 애플리케이션을 사용할 준비를 완료하도록 합니다.
모델 추론을 위해 AWS Inferentia 노드에 vLLM 배포
Mistral-7B-Insturctor vLLM 모델을 사용하기 위한 노드 환경을 먼저 배포합니다.
1️⃣ AWS Inferentia Accelerators를 위한 Karpenter NodePool 및 EC2 NodeClass 생성
NodePool과 NodeClass가 정의된 매니페스트파일을 확인합니다.
cat inferentia_nodepool.yaml
해당 NodePool 및 EC2NodeClass 구성은 AWS Inferentia2 (Inf2) 인스턴스를 기반으로 한 생성형 AI 워크로드용 노드풀 설정입니다.
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: karpenter
- instance-family: inf2 → AWS Inferentia2 계열 인스턴스만 사용
- AWS Neuron SDK 탑재, GPU 대비 높은 추론 성능/비용 효율
- instance-size: xlarge ~ 48xlarge
- kubernetes.io/arch: amd64 → 아키텍처는 amd64로 제한
- role: Karpenter-eksworkshop → 노드를 실행할 때 사용할 IAM Role
- aws.amazon.com/neuron taint가 걸려 있어 Neuron 기반 파드만 스케줄 가능
노드풀과 노드클래스를 배포합니다.
kubectl apply -f inferentia_nodepool.yaml
생성된 리소스를 확인합니다.
kubectl get nodepool,ec2nodeclass inferentia
2️⃣ Neuron device 플러그인 및 Neuron Scheduler 설치
AWS Inferentia 기반 추론을 Kubernetes(EKS)에서 사용할 때 핵심 구성요소인 Neuron Device Plugin과 Neuron Scheduler는 NeuronCore 자원 할당의 자동화, 최적화된 스케줄링을 담당합니다.
Neuron device 플러그인은 Kubernetes에서 NeuronCore를 리소스로 인식하고, Pod에 할당 가능하게 만들어주는 DaemonSet입니다.
Neuron device 플러그인을 설치하려면 다음 명령을 실행합니다. (kubectl 경고 무시).
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.yml
Neuron Scheduler는 NeuronCore 자원의 효율적 분배를 위한 Kubernetes 스케줄러 확장 컴포넌트입니다.k8s scheduler와 비슷한 역할을 한다고 생각하면 됩니다.
kubectl 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.yml
생성된 리소스를 확인합니다.
kubectl get all -A | grep neuron
3️⃣ vLLM 애플리케이션 배포
이제 모델 제공 기능과 추론 엔드포인트를 제공하는 vLLM 포드를 배포합니다. vLLM 포드가 온라인 상태가 되면 FSx for Lustre 기반 영구 볼륨에서 Mistral-7B 모델(29GB)을 메모리에 로드하여 사용할 수 있습니다.
아래 명령어를 실행하여 vLLM Pod를 배포합니다.
vLLM Pod 의 매니페스트를 확인합니다.
apiVersion: 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: 8000
- 추론 모델: Mistral-7B-Instruct-v0.2 (Neuron용으로 컴파일된 버전)
- 추론 런타임: vLLM + AWS Neuron (Inferentia2)
- 스토리지: FSx for Lustre에서 모델 및 캐시 로드 (PVC로 마운트됨)
- /work-dir에 fsx-lustre-claim PVC 마운트 → 모델 파일 읽기 용도
- 컨테이너 옵션 (args): --device=neuron, --tensor-parallel-size=2, --max-model-len=10240 등 추론 파라미터 지정
- 스케줄링 설정: tolerations 추가로 aws.amazon.com/neuron taint가 있는 노드에 배포 가능
이제 서비스와 디플로이먼트를 배포합니다.
kubectl apply -f mistral-fsxl.yaml
💡 1. vLLM 배포에는 약 7~8분이 소요됩니다. ( 다음 단계로 넘어가셔도 되며, 이 단계가 완료될 때까지 기다릴 필요는 없습니다.) 카펜터에의해 새로운 Inferentia 타입의 노드가 생성되므로 다소 시간이 소요될 수 있습니다.
배포 진행상황을 모니터링 합니다.
watch -n 1 -c "kubectl get svc,deployment -o wide; kubectl get node -o wide"
EKS 웹 콘솔에서 클러스터에 노드가 추가 됐는지 확인합니다.
새로운 AWS Inferentia inf2.xlarge 컴퓨팅 노드가 있는 것을 볼 수 있습니다.
인스턴스 이름 클릭하여 해당 노드의 할당 리소스 및 파드 정보를 확인합니다.
카펜터에의해 생성되었기에 파이널라이저에 karpenter.sh/termination이 사용되는 것을 확인할 수 있습니다.
이제 모델추론을 처리할 수 있는 애플리케이션 생성이 완료되었습니다. 프론트엔드만 설정하면 일반적인 형태의 생성형 AI 챗봇을 사용할 수 있습니다.
모델과 상호 작용하기 위한 WebUI 채팅 애플리케이션 배포
"Open WebUI" 애플리케이션을 사용하여 추론 서비스에 연결할 수 있습니다 .
이 애플리케이션은 워크숍에서 배포할 vLLM 호스팅 Mistral-7B-Instruct 모델에서 제공하는 OpenAI 호환 엔드포인트를 사용하도록 설계되었습니다.
Open WebUI 애플리케이션을 사용하면 사용자가 채팅 기반 인터페이스를 통해 LLM 모델과 상호 작용할 수 있습니다.
1️⃣ Open WebUI Pod를 배포
Open WebUI 배포를 위한 manifest를 살펴봅니다.
cat open-webui.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: open-webui-deployment
spec:
replicas: 1
selector:
matchLabels:
app: open-webui-server
template:
metadata:
labels:
app: open-webui-server
spec:
containers:
- name: open-webui
image: kopi/openwebui
env:
- name: WEBUI_AUTH
value: "False"
- name: OPENAI_API_KEY
value: "xxx"
- name: OPENAI_API_BASE_URL
value: "http://vllm-mistral7b-service/v1"
---
apiVersion: v1
kind: Service
metadata:
name: open-webui-service
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: external
service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: instance
spec:
selector:
app: open-webui-server
# type: LoadBalancer
ports:
- protocol: TCP
port: 80
targetPort: 8080
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: open-webui-ingress
annotations:
alb.ingress.kubernetes.io/scheme: internet-facing
alb.ingress.kubernetes.io/target-type: ip
alb.ingress.kubernetes.io/healthcheck-path: /
alb.ingress.kubernetes.io/healthcheck-interval-seconds: '10'
alb.ingress.kubernetes.io/healthcheck-timeout-seconds: '9'
alb.ingress.kubernetes.io/healthy-threshold-count: '2'
alb.ingress.kubernetes.io/unhealthy-threshold-count: '10'
alb.ingress.kubernetes.io/success-codes: '200-302'
alb.ingress.kubernetes.io/load-balancer-name: open-webui-ingress
labels:
app: open-webui-ingress
spec:
ingressClassName: alb
rules:
- http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: open-webui-service
port:
number: 80
위 manifest를 통해 세 리소스를 생성합니다.
- Deployment: Open WebUI 컨테이너 실행. 인증 없이 접속 가능하며, vLLM 엔드포인트와 연결됨
- Service: 80포트로 내부 Pod 연결, NLB 형태도 가능
- Ingress: 퍼블릭 ALB로 외부 HTTP 요청을 open-webui-service로 전달
해당 리소스 배포를 통해 ALB Ingress를 통해 Chatbot (Open WebUI)사이트에 접속할 수 있게 됩니다.
다음 명령어를 통해 리소스를 생성합니다.
kubectl apply -f open-webui.yaml
생성된 리소스와 Ingress 주소를 확인합니다.
kubectl get svc,deployment,ingress | grep open
2️⃣ OpenWeb UI 접속
이제 OpenWeb UI가 배포될 때까지 1~2분 정도 기다린 후, 위의 URL 주소를 복사하여 웹 브라우저에 붙여넣으세요. Open WebUI 채팅 클라이언트 인터페이스가 열립니다.
애플리케이션이 배포되면 다음과 같이 초기화면을 확인할 수 있습니다.
WebUI 인터페이스 상단 메뉴 막대에 드롭다운 메뉴가 표시되며, 이를 통해 모델을 선택할 수 있습니다. 드롭다운 메뉴에서 Mistral-7B 모델을 선택하고 새로 배포된 Generative AI 채팅 애플리케이션에서 채팅을 시작할 수 있습니다.
이제 Amazon EKS에서 실행되는 컨테이너화된 애플리케이션으로 생성형 AI 챗봇을 성공적으로 배포했습니다. 캐시된 Mistral-7B 모델은 Amazon FSx Lustre에 호스팅되고 컴퓨팅은 AWS Inferentia Accelerators에서 구동됩니다.
ex) 저는 다음과 같이 AWS cloud 시장 점유율에 대해서 문의를 해보았습니다.
Mistral-7B 데이터 확인 및 생성된 데이터 자산 공유 & 복제하기
실습 아키텍처
이번 실습에서는 다음과 같은 내용을 수행합니다.
- Mistral-7B 모델 데이터가 어떻게 저장되어 있는지 확인합니다.
- FSx for Lustre로 백업된 Persistent Volume (PV) 를 통해 S3 버킷의 데이터를 어떻게 접근하는지도 살펴봅니다.
- EKS 파드 내에서 테스트 파일을 생성하여 해당 파일이 S3 버킷으로 자동 export 되는 것을 확인합니다.
- 다른 리전에 있는 S3 버킷으로의 자동 복제(S3 Replication) 해봅니다.
- 해당 구성을 통해서 장애 발생시 혹은 DR 구축 시 Secondary 리전에 Production 리전의 워크로드 리소스를 배포하기만 하면 데이터는 그대로 공유 되므로 빠른 서비스 복구가 가능해 집니다.
❓FSx for lustre 스토리지를 사용하는 이유
AI/ML 워크로드에서는 여러 개의 Pod가 대용량 모델 파일이나 학습 데이터 세트에 동시에 접근해야 하는 경우가 많습니다. 이때 FSx for Lustre는 단일 고성능 공유 스토리지로써, 다음과 같은 이점을 제공합니다.
- 공유 PVC 기반의 중앙 스토리지: 수많은 Pod가 동시에 접근할 수 있는 하나의 영구 볼륨(PV/PVC)을 사용하여, 모델이나 데이터를 중복 없이 저장하고 효율적으로 재사용할 수 있습니다.
- 로컬 볼륨 대비 운영 효율성 향상: 기존처럼 각 Pod마다 로컬 볼륨을 만들고 데이터를 복사할 필요 없이, 공통 데이터 소스를 마운트만 하면 되므로 Pod 생성 속도와 스토리지 관리 효율성이 크게 향상됩니다.
- 중복 데이터 제거: 여러 로컬 볼륨에 동일한 모델/데이터를 복제하지 않아도 되기 때문에, 스토리지 비용과 I/O 낭비를 줄일 수 있습니다.
- 고성능 I/O 처리: Lustre 파일 시스템은 대규모 병렬 읽기/쓰기 처리가 가능하므로, 대형 모델 추론 및 학습에 적합한 스토리지 성능을 제공합니다.
- 대용량 학습 데이터를 보관 및 처리 하는데 용이: FSx for Lustre는 Amazon S3 버킷을 백엔드 스토리지처럼 연동할 수 있어, S3에 저장된 모델과 학습 데이터를 파일시스템처럼 바로 마운트해서 사용할 수 있습니다.
S3 연결 FSx for Lustre 인스턴스에 대한 S3 크로스 리전 복제 구성
해당 지역에 생성된 S3 버킷을 클릭 → 관리 탭을 선택하고 복제 규칙 으로 스크롤한 다음 복제 규칙 만들기를 선택합니다.
화면 상단의 빨간색 팝업 상자에서 '버킷 버전 관리 사용' 을 클릭합니다. 그런 다음 '규칙 이름' 아래에 나중에 규칙을 식별하는 데 도움이 되는 규칙 이름을 입력합니다. (FSxL-Replication-01) '
상태 ' 아래에는 기본적으로 '사용 '이 선택되어 있습니다.
소스 버킷 에서 하나 이상의 필터를 사용하여 이 규칙의 범위 제한을 선택한 다음 필터링할 값으로 test/를 입력합니다. test/ 하위 객체만 복제하도록 합니다.
대상 에서 S3 찾아보기를 클릭하고 us-east-2에 생성한 대상 S3 버킷을 선택합니다. 이 버킷의 이름은 fsx-lustre-bucket-2ndregion-xxxx 와 같습니다 . 그런 다음 경로 선택을 클릭합니다 .
빨간색 팝업 상자에서 버킷 버전 관리 사용을 클릭합니다 .
대상 버킷의 리전은 us-east-2 인 것을 확인합니다. (소스 버킷: use-west-2)
이제 Amazon S3가 사용자를 대신하여 S3 버킷 간에 S3 객체를 복제할 수 있도록 AWS Identity and Access Management(IAM) 역할을 설정하세요. 미리 생성된 기존 역할(이름은 s3-cross-region-replication-role 로 시작 ) 을 선택하세요.
암호화의 경우 AWS KMS로 암호화된 객체 복제를 선택 하고 "사용 가능한 AWS KMS 키"를 클릭한 다음 표시되는 키 하나만 선택합니다. (AWS 기본 키 사용)
다른 모든 기본 옵션을 유지하고 저장을 클릭하여 구성을 저장합니다.
❗기존 객체를 복제하라는 팝업이 표시됩니다. 아니요, 기존 객체를 복제하지 않음을 선택 하고 제출을 클릭합니다. 실습에서는 단순 교차 복제를 검증하는 과정이므로 생성되는 객체에 대해서만 복제를 적용합니다.
S3 복제 규칙 페이지로 돌아가면 규칙이 성공적으로 생성되었음을 확인할 수 있습니다.
Mistral-7B 데이터 확인 및 S3 자동 Export 및 리전 간 복제 검증
파드에 연결된 Persistent Volume (FSx for Lustre)에 /mnt/work-dir/test
경로에 파일을 만들면 S3에 자동으로 export → us-east-2 리전으로 자동 복제 되도록 하는 실습을 해봅니다.
1️⃣ Pod에 로그인하고 모델 데이터를 검사하고 복제할 테스트 파일을 만듭니다.
실습을 위해 디렉토리를 이동합니다.
cd /home/ec2-user/environment/eks/FSxL
접속할 vLLM Pod를 찾습니다.
kubectl get pods
해당 파드에 접속합니다.
kubectl exec -it <YOUR-vLLM-POD-NAME> -- bash
해당 파드에서 마운트 상태를 확인합니다.
df -hT
lustre 타입의 파일시스템이 /work-dir 에 마운트 된 것을 확인할 수 있습니다. 해당 파일시스템 호스트는 다음과 같이 웹 콘솔에서도 확인할 수 있습니다.
FSx for lustre 가 마운트된 경로로 이동하여 파일을 확인합니다.
cd /work-dir/
ls -ll
이는 위에서 살펴본 fsx-lustre-mlfglouwx* S3 버킷의 파일 구조와 동일하다는 것을 콘솔에서도 확인할 수 있습니다.
Mistral-7B 모델이 여기에 저장되어 있는 것을 확인할 수 있습니다. 모델의 데이터 구조가 어떻게 생겼는지 살펴보겠습니다.
cd Mistral-7B-Instruct-v0.2/
ls -ll
다음으로, S3와 연동된 경로에서 테스트 파일을 생성합니다. 여기서 FSx for Lustre가 새 파일/변경된 파일을 Amazon S3로 자동 내보내는 기능과 S3 버킷 간 복제 기능을 확인할 수 있습니다.
test 라는 새 폴더 아래에 testfile 이라는 테스트 파일을 생성합니다. 그러면 다음과 같은 과정으로 S3 버킷 리전복제가 수행되는 것을 확인할 수 있습니다.
FSx 인스턴스에 연결된 S3 버킷으로 테스트 파일 export → 버킷 복제 기능을 통해 Second region에 복제 (us-east-2)
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
S3 콘솔에서 해당 오브젝트 경로가 생성된 것을 확인할 수 있습니다.
S3 복제 대상 버킷에 들어와 보면 해당 testfil이 동일한 경로에 복제된 것을 확인할 수 있습니다.
데이터 레이어 테스트를 위한 사용자 전용 환경 만들기
이전 실습에서는 미리 생성된 FSx for Lustre 스토리지 인스턴스를 사용하는 정적 프로비저닝 방식을 통해 EKS 클러스터에서 Persistent Volume(PV)과 Persistent Volume Claim(PVC) 를 생성하고 사용하였습니다.
이번 실습에서는 Storage Class를 이용해 동적으로 FSx for lustre 인스턴스를 생성하여 PV를 할당하는 동적 프로비저닝 방식으로 스토리지를 사용하는 시나리오를 실습해 보도록합니다.
FSx for Lustre 동적 프로비저닝을 사용한 PV 및 스토리지 생성 실습
1️⃣ 실습에 필요한 환경 변수 설정
다음 단계에서는 아래 환경 변수를 사용하게 되니, 설정해 보겠습니다.
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 $VPC_ID
echo $SUBNET_ID
echo $SECURITY_GROUP_ID
스토리지 관련 리소스를 생성하기 위해 관련 매니페스트파일이 있는 디렉토리로 이동합니다.
cd /home/ec2-user/environment/eks/FSxL
2️⃣ StorageClass 정의 및 생성
FSxL 스토리지를 생성하기 위한 storage class 매니페스트를 조회합니다.
cat fsxL-storage-class.yaml
해당 파일에 위에서 설정한 환경변수를 대입하여 줍니다.
sed -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.yaml
적용된 내용을 확인합니다. 각 필드에 대한 자세한 내용은 다음 도큐를 확인하시기 바랍니다. 🔗
cat fsxL-storage-class.yaml
- subnetId - Amazon FSx for Lustre 파일 시스템을 생성할 서브넷 ID입니다. Amazon FSx for Lustre는 모든 가용 영역에서 지원되지 않습니다. Amazon FSx for Lustre 콘솔을 열고
https://console.aws.amazon.com/fsx/
사용하려는 서브넷이 지원되는 가용 영역에 있는지 확인하십시오. 서브넷에는 노드가 포함될 수도 있고, 다른 서브넷 또는 VPC일 수도 있습니다. 지정한 서브넷이 노드가 있는 서브넷과 다른 경우, VPC를 연결해야 하며 보안 그룹에서 필요한 포트가 열려 있는지 확인해야 합니다. - securityGroupIds – 노드의 보안 그룹 ID입니다.
- s3ImportPath – 영구 볼륨으로 데이터를 복사할 Amazon Simple Storage Service 데이터 저장소입니다.
- s3ExportPath – 새 파일이나 수정된 파일을 내보내려는 Amazon S3 데이터 저장소입니다.
- 배포 유형 - 파일 시스템 배포 유형입니다. 유효한 값은 SCRATCH_1, SCRATCH_2 및 PERSISTENT_1입니다. 배포 유형에 대한 자세한 내용은 Amazon FSx for Lustre 파일 시스템 생성을 참조하세요.
- default값은 SCRATCH_1 입니다.
- SCRATCH_1: 단기 저장 및 일시적 데이터 처리용 FSx 유형. 비용이 저렴하고 성능은 보통. 데이터는 휘발성이며, 전송 중 암호화는 지원하지 않음.
- SCRATCH_2: SCRATCH_1 에서 전송 중 데이터 암호화와 더 높은 버스트 처리량을 지원합니다. 해당 실습에서는 SCRATCH_2 옵션을 사용하였습니다.
- autoImportPolicy - FSx가 따르는 정책으로, 연결된 데이터 저장소의 변경 사항을 파일 시스템에 자동으로 업데이트하는 방식을 결정합니다. 사용 가능한 정책 목록은 FSx for Lustre 공식 문서를 참조하세요.
- perUnitStorageThroughput - 배포 유형 PERSISTENT_1의 경우, 고객은 스토리지 처리량을 지정할 수 있습니다. 기본값: "200". 단, 여기서는 "200" 또는 "100"과 같은 문자열로 지정해야 합니다.
storage class를 생성합니다.
kubectl apply -f fsxL-storage-class.yaml
storage class를 확인합니다.
kubectl get sc
3️⃣ PVC 생성
이 단계에서는 앞서 정의한 스토리지 클래스에 대한 영구 볼륨 클레임을 생성합니다.
kubectl apply -f fsxL-dynamic-claim.yaml
생성된 PVC를 확인해봅니다. FSx for lustre 인스턴스를 생성하는 데에는 15분 정도 소요됩니다.
kubectl get pvc,sc
웹콘솔 에서 생성되고 있는 것을 확인할 수 있습니다.
시간이 지난 후 PVC가 바운딩 된 것을 확인합니다.
FSx for lustre 성능 테스트
이번 실습에서는 스토리지 벤치마크 도구인 FIO 와 IOping 를 사용하여 FSx for lustre 성능을 테스트 해봅니다.
1️⃣ FSx for Lustre의 yaml 파일과 10GB 스토리지를 사용하여 테스트 포드 프로비저닝
⚠️ FSx가 프로비저닝된 가용영역을 확인하여 Pod가 프로비저닝될 가용영역과 일치 시키도록 합니다.
FSx for lustre는 단일 가용 영역 사용의 제한이 적용되고 파드에서 FSx for lustre에 연동하기 위해서는 가용영역을 맞춰줘야 합니다. 🔗
aws ec2 describe-subnets --subnet-id $SUBNET_ID --region $AWS_REGION | jq .Subnets[0].AvailabilityZone
성능 테스트용 파드를 배포합니다.
kubectl apply -f pod_performance.yaml
해당 파드가 fsx-lustre-dynamic-claim PVC로 생성된 볼륨을 마운트 하는 것을 확인할 수 있습니다.
2️⃣ IOping 를 사용한 성능 테스트
아래 명령을 사용하여 컨테이너에 로그인합니다.
kubectl exec -it fsxl-performance -- bash
실습에 사용할 FIO 및 IOping 를 설치합니다.
apt-get update
apt-get install fio ioping -y
파드에 마운트된 파일시스템 확인
df -hT
📊 root 디렉토리 (ebs 볼륨) 스토리지 지연확인
/ 경로에서 다음 명령어를 수행합니다.
ioping -c 20 .
📊 /data 디렉토리 (FSx for lustre) 스토리지 지연확인
FSx for Lustre 파일 시스템의 지연 시간을 테스트하려면 아래 IOping 명령을 실행합니다.
cd /data
ioping -c 20 .
ioping 결과 일반적으로 < 0.5ms(500us)인 평균 지연 시간을 기록합니다. 이는 FSx for Lustre 파일 시스템의 낮은 지연 시간과 높은 성능을 보여줍니다.
💡 EBS 와 FSx for lustre의 스토리지 지연 성능 비교
항목 | FSx for Lustre (/data) | OverlayFS (/) |
---|---|---|
최소 지연 시간 | 12.7 µs ✅ | 422.9 µs |
평균 지연 시간 | 106.2 µs ✅ | 488.4 µs |
최대 지연 시간 | 1.12 ms | 663.9 µs ✅ |
mdev (분산) | 278.1 µs | 53.8 µs ✅ |
IOPS | 9.42k IOPS ✅ | 2.05k IOPS |
Throughput | 36.8 MiB/s ✅ | 8.00 MiB/s |
FSx for Lustre는 컨테이너 루트 파일시스템(OverlayFS)보다 월등한 성능을 보였습니다. 특히 평균 지연 시간은 약 5배 빠르고, IOPS와 처리량 역시 각각 4~5배 이상 높은것을 확인할 수 있었습니다. Lustre는 분산 파일시스템 특성상 순간적인 최대 지연은 다소 높은 경우도 있으나, 전반적으로 짧은 응답 시간과 높은 동시처리 성능을 통해 AI/ML 워크로드에 매우 적합한 스토리지임을 보여줍니다. 반면 OverlayFS는 지연 시간은 일정하지만, 속도 자체는 느리며, 병렬 처리 능력도 떨어져 고부하 워크로드에는 적합하지 않습니다.
따라서, 고속 I/O, 병렬 처리, 모델 캐싱 등의 고성능 파일 접근이 요구되는 환경에서는 FSx for Lustre가 훨씬 더 효과적인 선택이라고 볼 수 있습니다.
3️⃣ FIO 를 사용한 성능 테스트
다음 명령어를 사용하여 부하 테스트를 진행합니다.
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
해당 명령어는 1MB 블록 크기로 8GB짜리 파일에 대해 8개의 병렬 작업자(worker)
가 64 I/O 큐 깊이로 랜덤 읽기/쓰기를 10초간 수행하며, 직접 디스크 접근을 통해 OS 캐시 영향을 제거한 실제 디스크 성능 측정을 목표로 합니다. 즉 이는 high-throughput 워크로드 시뮬레이션에 적합한 명령어 테스트 입니다.
해당 명령어의 결과는 다음과 같습니다.
결과
처리량(Throughput): 파일 시스템 크기에 비례합니다. 현재는 1.2TiB로 구성되어 있으므로 일반적으로 평균 약 240MB/s 정도의 쓰루풋이 나옵니다. FSx for lustre 구성별로 성능에 대한 기준표는 다음 링크를 참고 바랍니다. 🔗
항목 | 값 |
---|---|
Read BW | 234MiB/s ≒ 246MB/s |
Write BW | 243MiB/s ≒ 254MB/s |
지연 시간(Latency)은 일반적으로 0.5ms 이하로 매우 낮은 결과를 보여줍니다.
IOPS: 작업 설정에 따라 달라집니다. 일반적으로 병렬작업의 고성능 컴퓨팅 워크로드를 수행할 때 기준으로 FSx for lustre는 해당 워크로드에 매우 적합한 성능을 보여줍니다.
항목 | 값 |
---|---|
Read IOPS | 234 IOPS |
Write IOPS | 242 IOPS |
블록당 1MB이므로 IOPS 자체는 낮아 보일 수 있으나, 이는 고속 대용량 처리 테스트 구성에 적합한 수치입니다
지연과 큐 상태
- 대부분의 요청이 큐 깊이 64 이상에서 완료됨 (I/O depths: >=64 비율이 91.8%)
- 이는 시스템이 고부하 병렬 처리 상황을 잘 감당하고 있다는 것을 보여줌
- ctx=11672 → context switching 수치도 안정적이며, CPU 사용률도 낮음
결론
fio 테스트 결과를 보면, 해당 스토리지는 1MB 블록 단위의 랜덤 읽기/쓰기 환경에서도 초당 약 500MB에 가까운 처리량과 230~240 IOPS의 성능을 안정적으로 보여주고 있습니다. 특히 병렬 작업자 8명, 큐 깊이 64의 고부하 조건에서도 지연이 거의 없이 대부분의 요청이 최상위 큐에서 완료되었으며, CPU 사용률도 낮게 유지되었습니다. 이러한 성능은 일반적인 파일시스템 대비 상당히 우수한 수준이며, FSx for Lustre 스토리지가 AI/ML 워크로드에 적합한 데이터 처리 성능을 충실히 보여준 결과로 평가할 수 있을 것 같습니다.
마치며
느낀점
이번 실습을 통해 Amazon EKS 환경에서 vLLM을 활용한 생성형 AI 추론 서버를 성공적으로 구축하고, FSx for Lustre 파일시스템을 기반으로 고성능 스토리지 연동까지 검증해보았습니다.
vLLM은 OpenAI 호환 API를 제공하면서도 다양한 오픈소스 LLM 모델을 유연하게 배포할 수 있다는 점에서 매우 편리하고 AI 혹은 LLM에 아예 배경지식이 없는 일반인도 쉽게 모델을 사용할 수 있다는 것이 너무 인상적이고 흥미로운 경험이었습니다.
또, Neuron 기반의 Inf2 인스턴스를 활용하면 추론 성능과 비용 효율성까지 극대화할 수 있다는 점도 확인할 수 있었습니다.
또한 FSx for Lustre는 AI/ML 워크로드에서 흔히 발생하는 대규모 모델/데이터를 다수의 파드에서 동시에 읽어야 하는 상황에 최적화된 공유 스토리지임을 확인할 수 있었습니다. S3와의 연동으로 데이터 이동 없이 직접 캐시처럼 마운트하여 사용 가능하다는 점, 그리고 높은 처리량과 낮은 지연 시간 등의 뛰어난 성능과 기능을 확인해 볼 수 있었습니다.
이번 실습은 단순히 모델을 띄우는 것을 넘어서, 클라우드 네이티브 환경에서 생성형 AI 워크로드를 안정적이고 고성능으로 운영하기 위한 인프라 구성과 선택 기준을 실제로 체감할 수 있는 좋은 기회였습니다.
※ Appendix: 실습 관련 배경 지식 정리
실습을 진행하면서 AI나 머신러닝에 대해서 배경지식이 부족하여 해당 내용에 대해 스스로 정리를 해봤습니다. 저같이 선행 지식이 부족할 경우 참고 하면 좋을 것 같습니다.
모델 파라미터
- 딥러닝 모델이 학습을 통해 최적화한 weight와 bias 값. 모델 내부의 수많은 뉴런/레이어에서 입력값에 따라 출력을 만들기 위해 수학적으로 곱해지는 숫자들 입니다.ex)
- Mistral-7B → 약 70억 개의 파라미터
- GPT-3 → 175억
- GPT-4 → 1조+
- 즉 모델의 ‘지식’ 이라고 보면 된다고 합니다. 따라서 파라미터가 많을 수록 모델이 가지고 있는 지식의 양이 많은 것이라고 볼 수 있습니다.
model.safetensors
,pytorch_model.bin
같은 파일에 저장. 해당 파일은 모델의 스토리지인 FSx 에 저장되어 있음
모델 추론의 흐름
1️⃣ 모델 파라미터 로딩
처음 컨테이너가 시작될 때,
vLLM은 다음과 같은 과정을 통해 모델 파라미터를 디스크에서 GPU or ML Accelerator 메모리(RAM)에 로딩합니다:
단계 | 설명 |
---|---|
1. 모델 weight 경로 설정 | HuggingFace Hub에서 가져오거나, --model /mnt/fsx/mistral-7b 와 같이 FSx for Lustre 등 로컬 경로로 지정 |
2. 파라미터 파일 열기 | .safetensors , .bin , .pt 등의 weight 파일을 open |
3. CPU 메모리 로딩 | weight를 먼저 CPU RAM에 로딩 후, 필요한 경우 GPU/HBM/Neuron으로 복사 |
4. 추론 엔진 초기화 | attention, transformer layer, position embedding 등 레이어 구성 메모리 할당 |
※ FSx for Lustre에 마운트된 모델 파라미터는 vLLM engine
에서 직접 file read 로 로딩됨
2️⃣ 사용자 요청 (Prompt) → WebUI
- 사용자가 Web UI(Open WebUI 등)에서 프롬프트 입력
/generate
또는/completion
REST API 형태로 vLLM API 서버에 전달
3️⃣ 입력 토크나이징 (Tokenization)
- vLLM은 입력 문자열을 모델에 맞는 토큰 단위로 변환 (예:
"What"
→1314
) - 사용 중인 모델(Mistral, LLaMA 등)의 tokenizer.json 또는
tokenizer.model
기반 처리 - 이 토크나이저도 모델 디렉토리(즉, FSx 마운트 경로)에 포함됨
4️⃣ 인퍼런스 수행 (Neural Forward)
- 입력 토큰들을 Transformer 모델에 전달
5️⃣ 출력 토큰 생성
- 마지막 softmax layer에서 토큰 확률 분포 생성
- Top-K, Top-P, Sampling 방식에 따라 다음 토큰 선택
- 반복적으로 다음 토큰을 입력으로 받아 디코딩 반복
6️⃣ 디토크나이징 → 사용자 출력
- 출력 토큰들을 원래 문자열로 디코딩
- Web UI에 응답으로 반환
Amazon FSx for Lustre + S3 스토리지 구성
FSx for Lustre 파일 시스템을 생성할 때 또는 생성 후에 S3 버킷(또는 접두사)과 데이터 리포지토리 연결(Data Repository Association, DRA)을 설정할 수 있습니다. 이 연결을 통해 S3 버킷의 객체가 Lustre 파일 시스템 내에서 파일로 자동으로 표시됩니다. 🔗
이로 인해 S3 객체를 로컬 파일시스템에서 파일로 인식 및 조회가 가능하고,
S3로 양방향 동기화 및 내보내기 (r/w)가 가능합니다.
https://swsmith.cc/posts/fsx-lustre-cache.html
사용 사례
FSx for Lustre는 S3 버킷을 "직접 mount"하는 것이 아니라, S3와의 데이터 리포지토리 연결을 통해 Lustre 파일 시스템에서 S3 데이터를 파일로 노출하는 방식입니다. 고성능 컴퓨팅(HPC), 머신러닝, 대규모 데이터 분석 등에서 S3 데이터를 빠르게 처리해야 할 때 적합합니다.
캐싱 매커니즘
동작 방식: DRA를 설정하면 S3 버킷(또는 프리픽스)과 FSx for Lustre 파일 시스템의 특정 디렉터리가 연결됩니다. 이때 S3의 파일·디렉터리 메타데이터가 FSx for Lustre 파일 시스템에 로드되어, 사용자는 S3 객체를 파일처럼 볼 수 있습니다. 실제 파일 내용(데이터)은 사용자가 해당 파일을 처음 읽을 때 S3에서 FSx for Lustre로 온디맨드로 가져와 캐싱됩니다 🔗
'AWS > EKS' 카테고리의 다른 글
K8s 시크릿 관리 with Vault (0) | 2025.04.13 |
---|---|
EKS Upgrades (0) | 2025.04.06 |
K8S 환경에서 CI/CD 구축하기 - 2 (0) | 2025.03.30 |
K8S 환경에서 CI/CD 구축하기 - 1 (0) | 2025.03.30 |
EKS Auto Mode (0) | 2025.03.23 |