[AWS EKS] (30) EKS 스터디 11주차 ( AWS EKS ML Infra(GPU) workshop )
CloudNet@팀의 EKS 스터디 AEWS 2기에 작성된 자료를 토대로 작성합니다.
- Amazon EKS 클러스터에 vLLM과 WebUI 파드를 배포하여 생성형 AI 챗봇 애플리케이션을 Kubernetes에 배포합니다.
Mistral-7B 모델은 Amazon FSx for Lustre 및 Amazon S3를 사용하여 저장하고 액세스하며, 생성형 AI 워크로드를 위해 AWS Inferentia 가속 컴퓨팅을 활용합니다. - 추가 파드 요청으로 인해 추가 노드가 필요한 경우, Karpenter를 사용하여 EKS 노드 수를 자동으로 확장하여 확장성과 운영 효율성을 확보합니다.
Build Gen AI & ML using EKS , Amazon FSx and AWS Inferentia
- Cloud9 검색 하여 클릭
- Select genaifsxworkshoponeks
- Click the Open under the Cloud9 IDE to launch the Cloud9 environment.
대부분의 경우 Cloud9은 IAM 자격 증명을 동적으로 관리하지만, 현재는 Amazon EKS IAM 인증과 호환되지 않습니다. 따라서 이를 비활성화하고 대신 AWS IAM 역할을 사용해야 합니다
# AWS IAM 설정 비활성화
aws cloud9 update-environment --environment-id ${C9_PID} --managed-credentials-action DISABLE
rm -vf ${HOME}/.aws/credentials
# 사용할 assume role 의 arn을 확인한다.
aws sts get-caller-identity
# The output assumed-role name should look like the following:
{
"UserId": "AROA5FD66U2OXT7GULSMN:i-089c79db4f72948fd",
"Account": "904356865693",
"Arn": "arn:aws:sts::904356865693:assumed-role/genaifsxworkshoponeks-C9Role-IZ3MRtV3LetW/i-089c79db4f72948fd"
}
- region 환경설정 + token 설정
- eksctl 사용 위해 Cluster name env 등록
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=eksworkshop
- 확인
echo $AWS_REGION
echo $CLUSTER_NAME
- kubeconfig 설정
aws eks update-kubeconfig --name $CLUSTER_NAME --region $AWS_REGION
- 확인
kubectl get nodes
NAME STATUS ROLES AGE VERSION
ip-10-0-63-76.us-west-2.compute.internal Ready <none> 11h v1.30.9-eks-5d632ec
ip-10-0-71-68.us-west-2.compute.internal Ready <none> 11h v1.30.9-eks-5d632ec
EKS Blueprints for Terraform
The Amazon Elastic Kubernetes Service (EKS) cluster in this workshop was created with Terraform using the EKS Blueprints for Terraform .
- 이 섹션에서는 Amazon EKS 클러스터에 사전 설치된 Karpenter를 확인합니다.
- Karpenter는 공식 Helm 차트를 사용하여 설치할 수 있지만, 이 클러스터는 Amazon EKS 블루프린트를 사용하여 프로비저닝되었으며, Karpenter가 미리 설치되어 있습니다.
kubectl -n karpenter get deploy/karpenter -o yaml
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
deployment.kubernetes.io/revision: "1"
meta.helm.sh/release-name: karpenter
meta.helm.sh/release-namespace: karpenter
creationTimestamp: "2025-04-17T01:03:21Z"
generation: 1
labels:
app.kubernetes.io/instance: karpenter
app.kubernetes.io/managed-by: Helm
app.kubernetes.io/name: karpenter
app.kubernetes.io/version: 1.0.1
helm.sh/chart: karpenter-1.0.1
name: karpenter
namespace: karpenter
resourceVersion: "2893"
uid: 77394dea-7e6f-4f60-8ae1-9c8244e154d1
spec:
progressDeadlineSeconds: 600
replicas: 2
revisionHistoryLimit: 10
selector:
matchLabels:
app.kubernetes.io/instance: karpenter
app.kubernetes.io/name: karpenter
strategy:
rollingUpdate:
maxSurge: 25%
maxUnavailable: 1
type: RollingUpdate
template:
metadata:
creationTimestamp: null
labels:
app.kubernetes.io/instance: karpenter
app.kubernetes.io/name: karpenter
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: karpenter.sh/nodepool
operator: DoesNotExist
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/instance: karpenter
app.kubernetes.io/name: karpenter
topologyKey: kubernetes.io/hostname
containers:
- env:
- name: KUBERNETES_MIN_VERSION
value: 1.19.0-0
- name: KARPENTER_SERVICE
value: karpenter
- name: WEBHOOK_PORT
value: "8443"
- name: WEBHOOK_METRICS_PORT
value: "8001"
- name: DISABLE_WEBHOOK
value: "false"
- name: LOG_LEVEL
value: info
- name: METRICS_PORT
value: "8080"
- name: HEALTH_PROBE_PORT
value: "8081"
- name: SYSTEM_NAMESPACE
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: metadata.namespace
- name: MEMORY_LIMIT
valueFrom:
resourceFieldRef:
containerName: controller
divisor: "0"
resource: limits.memory
- name: FEATURE_GATES
value: SpotToSpotConsolidation=false
- name: BATCH_MAX_DURATION
value: 10s
- name: BATCH_IDLE_DURATION
value: 1s
- name: CLUSTER_NAME
value: eksworkshop
- name: CLUSTER_ENDPOINT
value: https://1162655CEF80DBC83049FA585E24F646.gr7.us-west-2.eks.amazonaws.com
- name: VM_MEMORY_OVERHEAD_PERCENT
value: "0.075"
- name: INTERRUPTION_QUEUE
value: karpenter-eksworkshop
- name: RESERVED_ENIS
value: "0"
image: public.ecr.aws/karpenter/controller:1.0.1@sha256:fc54495b35dfeac6459ead173dd8452ca5d572d90e559f09536a494d2795abe6
imagePullPolicy: IfNotPresent
livenessProbe:
failureThreshold: 3
httpGet:
path: /healthz
port: http
scheme: HTTP
initialDelaySeconds: 30
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 30
name: controller
ports:
- containerPort: 8080
name: http-metrics
protocol: TCP
- containerPort: 8001
name: webhook-metrics
protocol: TCP
- containerPort: 8443
name: https-webhook
protocol: TCP
- containerPort: 8081
name: http
protocol: TCP
readinessProbe:
failureThreshold: 3
httpGet:
path: /readyz
port: http
scheme: HTTP
initialDelaySeconds: 5
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 30
resources: {}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop:
- ALL
readOnlyRootFilesystem: true
runAsGroup: 65532
runAsNonRoot: true
runAsUser: 65532
seccompProfile:
type: RuntimeDefault
terminationMessagePath: /dev/termination-log
terminationMessagePolicy: File
dnsPolicy: ClusterFirst
nodeSelector:
kubernetes.io/os: linux
priorityClassName: system-cluster-critical
restartPolicy: Always
schedulerName: default-scheduler
securityContext:
fsGroup: 65532
serviceAccount: karpenter
serviceAccountName: karpenter
terminationGracePeriodSeconds: 30
tolerations:
- key: CriticalAddonsOnly
operator: Exists
topologySpreadConstraints:
- labelSelector:
matchLabels:
app.kubernetes.io/instance: karpenter
app.kubernetes.io/name: karpenter
maxSkew: 1
topologyKey: topology.kubernetes.io/zone
whenUnsatisfiable: DoNotSchedule
status:
availableReplicas: 2
conditions:
- lastTransitionTime: "2025-04-17T01:03:32Z"
lastUpdateTime: "2025-04-17T01:03:32Z"
message: Deployment has minimum availability.
reason: MinimumReplicasAvailable
status: "True"
type: Available
- lastTransitionTime: "2025-04-17T01:03:21Z"
lastUpdateTime: "2025-04-17T01:03:32Z"
message: ReplicaSet "karpenter-5b8d8d5b9" has successfully progressed.
reason: NewReplicaSetAvailable
status: "True"
type: Progressing
observedGeneration: 1
readyReplicas: 2
replicas: 2
updatedReplicas: 2
- CLUSTER_ENDPOINT: 신규 노드들이 연결할 외부 Kubernetes 클러스터 엔드포인트입니다. 이 값을 명시하지 않으면, 노드들은 DescribeCluster API를 통해 클러스터 엔드포인트를 자동으로 탐색합니다.
- INTERRUPTION_QUEUE: EKS Terraform 블루프린트의 일부로 생성된 SQS 큐의 엔드포인트입니다. 이 SQS 큐는 Spot 인스턴스 중단 알림과 AWS Health 이벤트를 수신하는 데 사용됩니다.
karpenter 확인
$ kubectl get pods --namespace karpenter
NAME READY STATUS RESTARTS AGE
karpenter-5b8d8d5b9-cd6f5 1/1 Running 0 11h
karpenter-5b8d8d5b9-dnh6f 1/1 Running 0 11h
alias kl='kubectl -n karpenter logs -l app.kubernetes.io/name=karpenter --all-containers=true -f --tail=20'
FSx for Lustre 인스턴스를 배포하고 Amazon EKS 클러스터와 통합
이번 워크숍에서는 Mistral-7B-Instruct 모델이 Amazon S3 버킷에 저장되어 있으며,
해당 버킷은 Amazon FSx for Lustre 파일 시스템과 연결되어 있습니다.
vLLM 컨테이너는 이를 사용하여 생성형 AI 챗봇 애플리케이션을 구동하게 됩니다.
이 모듈에서는 FSx for Lustre 인스턴스를 배포하고 Amazon EKS 클러스터와 통합하는 과정을 다룹니다.
FSx for Lustre는 모델 데이터를 제공하고, Amazon EKS는 생성형 AI 애플리케이션이 구동되는 플랫폼 역할을 합니다.
또한, 다음과 같은 Kubernetes 스토리지 개념을 학습하게 됩니다:
- CSI 드라이버
- Persistent Volumes (PV)
- StorageClass
- 정적(Static) 및 동적(Dynamic) 스토리지 프로비저닝 방식
이 모듈의 인프라는 다음으로 구성되어 있습니다:
- Amazon EKS 클러스터 (EC2 워커 노드 2개 포함)
- Amazon FSx for Lustre 파일 시스템
- Amazon S3 버킷
- Amazon FSx for Lustre
- 속도가 중요한 워크로드(예: 머신 러닝, 분석, 고성능 컴퓨팅)를 위한 고성능 병렬 파일 시스템을 제공하는 완전 관리형 서비스
- 밀리초 미만의 대기 시간으로 데이터에 액세스하고 TB/s의 처리량과 수백만 개의 IOPS로 확장 가능
- Amazon S3와도 통합되어 있어 클라우드 데이터의 대량을 쉽게 저장, 액세스 및 처리
Amazon S3와 통합되면 다음과 같은 이점이 있습니다:
- FSx for Lustre 파일 시스템은 S3 버킷의 객체들을 파일처럼 투명하게 사용자에게 제공합니다.
- 사용자가 Lustre 파일 시스템에 파일을 추가, 수정, 삭제하면 해당 변경 사항이 S3 버킷에 자동으로 반영됩니다.
즉, 클라우드 데이터의 대량 저장, 액세스 및 처리를 고성능 파일 시스템 환경에서 효율적으로 수행할 수 있습니다.
쿠버네티스 환경에서 FSx 파일시스템을 사용하면?
CSI 드라이버 (Container Storage Interface)
CSI는 Kubernetes와 같은 컨테이너 오케스트레이션 시스템에 블록 및 파일 스토리지를 제공하는 표준 인터페이스입니다.
이를 통해 Kubernetes가 컨테이너화된 애플리케이션을 위한 영구 스토리지(persistent storage)를 네이티브로 관리할 수 있습니다.
FSx for Lustre CSI 드라이버는 Amazon EKS 클러스터가 FSx for Lustre 기반의 Persistent Volume의 수명 주기를 관리할 수 있도록 합니다.
이를 통해 고성능, 저지연의 스토리지를 컨테이너 워크로드에 쉽고 빠르게 통합할 수 있습니다.
StorageClass
StorageClass는 EKS 관리자들이 제공하는 스토리지의 '클래스'를 정의하는 방법입니다.
각 StorageClass는 서로 다른 AWS 스토리지 서비스(Amazon FSx, Amazon EBS, Amazon EFS 등) 또는 백업 정책에 매핑될 수 있습니다.
Kubernetes는 StorageClass가 실제로 어떤 스토리지인지에 대해 특별한 제약 없이 유연하게 정의할 수 있도록 지원합니다.
Persistent Volume (PV)
PV는 관리자가 사전에 프로비저닝한 스토리지 볼륨으로, EKS 클러스터에 매핑됩니다.
PV는 Pod의 수명보다 더 오래 유지되며, 여러 Pod이 공유 데이터를 필요로 하는 경우에 적합합니다.
Persistent Volume Claim (PVC)
PVC는 사용자가 요청하는 스토리지 볼륨입니다.
요청 시, 스토리지의 크기와 액세스 모드(예: ReadWriteOnce, ReadOnlyMany, ReadWriteMany 등)를 지정할 수 있습니다.
✅ 정적(Static) vs 동적(Dynamic) 스토리지 프로비저닝
🔹 정적 프로비저닝 (Static provisioning)
- 관리자가 먼저 스토리지 인스턴스(FSx for Lustre 등)를 생성하고, 해당 인스턴스를 위한 **Persistent Volume(PV)**를 Kubernetes 클러스터에 생성합니다.
- 이후 애플리케이션 개발자가 PVC 요청을 통해 해당 PV를 Pod에서 사용할 수 있도록 설정합니다.
🔹 동적 프로비저닝 (Dynamic provisioning)
- PVC 요청이 들어올 때마다 자동으로 스토리지를 생성 및 연결합니다.
- 관리자가 미리 PV를 생성할 필요가 없으며, PVC 요청 시 FSx for Lustre 인스턴스 및 PV가 자동 생성됩니다.
- 사용자 입장에서 더 편리하고 유연하게 스토리지 자원을 사용할 수 있는 방식입니다.
deploy CSI Driver
Deploy CSI Driver
- csi 드라이버 설치를 위해서 준비
- 환경 변수를 설정하고, 서비스 계정을 생성하며, IAM 정책을 생성 및 연결하게 됩니다. ( IRSA 방식 )
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":[
"*"
]
}
]
}
EOF
aws 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
- Copy and run the below command to save the 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)
- CSI driver 설치 ( FSx for Lustre )
kubectl 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 get pods -n kube-system -l app.kubernetes.io/name=aws-fsx-csi-driver
NAME READY STATUS RESTARTS AGE
fsx-csi-controller-6f4c577bd4-l9xnk 4/4 Running 0 12s
fsx-csi-controller-6f4c577bd4-vvwp4 4/4 Running 0 12s
fsx-csi-node-h54lv 3/3 Running 0 12s
fsx-csi-node-nxw2g 3/3 Running 0 12s
- annotation 을 통해 서비스 어카운트에 ROLE_ARN을 삽입해준다.
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
$ kubectl get sa/fsx-csi-controller-sa -n kube-system -o yaml
apiVersion: v1
kind: ServiceAccount
metadata:
annotations:
eks.amazonaws.com/role-arn: arn:aws:iam::904356865693:role/eksctl-eksworkshop-addon-iamserviceaccount-ku-Role1-E5Z7hc16bMMV
kubectl.kubernetes.io/last-applied-configuration: |
{"apiVersion":"v1","kind":"ServiceAccount","metadata":{"annotations":{},"labels":{"app.kubernetes.io/name":"aws-fsx-csi-driver"},"name":"fsx-csi-controller-sa","namespace":"kube-system"}}
creationTimestamp: "2025-04-17T13:01:01Z"
labels:
app.kubernetes.io/managed-by: eksctl
app.kubernetes.io/name: aws-fsx-csi-driver
name: fsx-csi-controller-sa
namespace: kube-system
resourceVersion: "396978"
uid: 9875151c-42d7-42a2-a513-4532eca361d1
이 섹션에서는 다음과 같은 사전 작업을 완료했습니다:
- 환경 변수 생성
- 적절한 IAM 정책과 역할 ARN을 가진 서비스 계정 생성
- FSx for Lustre용 CSI 드라이버 배포
이제 다음 섹션에서는 FSx for Lustre를 위한 다음 리소스들을 생성하게 됩니다:
- Persistent Volume (PV)
- Persistent Volume Claim (PVC)
- StorageClass
이를 통해 Kubernetes 환경에서 FSx for Lustre 스토리지를 실제로 사용할 수 있도록 설정하게 됩니다.
PV 생성
Create Persistent Volume on EKS Cluster
이 랩 섹션에서는 정적 프로비저닝(Static Provisioning) 방식을 사용하여 Persistent Volume(PV)을 설정합니다.
이미 여러분을 위해 FSx for Lustre 인스턴스가 사전 프로비저닝되어 있으며,
이 인스턴스는 Mistral-7B 모델이 저장된 Amazon S3 버킷과 연결되어 있습니다.
이제 여러분은 다음 작업을 수행하게 됩니다:
- Persistent Volume (PV) 정의 생성
- Persistent Volume Claim (PVC) 생성
이러한 설정을 통해 vLLM 파드에서 Mistral-7B 모델 데이터에 접근할 수 있는 스토리지 볼륨을 사용할 수 있게 됩니다.
cd /home/ec2-user/environment/eks/FSxL
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)
Persistent Volume 생성
이번 단계에서는 fsxL-persistent-volume.yaml이라는 YAML 파일을 사용해 Persistent Volume(PV)를 생성합니다.
이 PV 정의 파일에는 미리 준비된 1200GiB 크기의 FSx for Lustre 인스턴스를 EKS 클러스터 리소스로 등록하는 내용이 포함되어 있습니다.
- PV의 이름을 fsx-pv 로 지정
- 해당 FSx for Lustre 인스턴스를 참조하도록 구성
- 용량은 1200GiB로 설정
# cat fsxL-persistent-volume.yaml
# fsxL-persistent-volume.yaml
apiVersion: v1
kind: PersistentVolume
metadata:
name: fsx-pv
spec:
persistentVolumeReclaimPolicy: Retain
capacity:
storage: 1200Gi
volumeMode: Filesystem
accessModes:
- ReadWriteMany
mountOptions:
- flock
csi:
driver: fsx.csi.aws.com
volumeHandle: FSXL_VOLUME_ID
volumeAttributes:
dnsname: DNS_NAME
mountname: MOUNT_NAME
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 배포 (apply)
kubectl apply -f fsxL-persistent-volume.yaml
- 확인
$ kubectl get pv
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
fsx-pv 1200Gi RWX Retain Available <unset> 5s
pvc-c98a27e4-0bfe-41fc-bd4c-f37f1ab14f92 50Gi RWO Delete Bound kube-prometheus-stack/data-prometheus-kube-prometheus-stack-prometheus-0 gp3 <unset> 22h
- pvc 배포
# fsxL-claim.yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: fsx-lustre-claim
spec:
accessModes:
- ReadWriteMany
storageClassName: ""
resources:
requests:
storage: 1200Gi
volumeName: fsx-pv
kubectl apply -f fsxL-claim.yaml
WSParticipantRole:~/environment/eks/FSxL $ kubectl get pv,pvc
NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS VOLUMEATTRIBUTESCLASS REASON AGE
persistentvolume/fsx-pv 1200Gi RWX Retain Bound default/fsx-lustre-claim <unset> 3m57s
persistentvolume/pvc-c98a27e4-0bfe-41fc-bd4c-f37f1ab14f92 50Gi RWO Delete Bound kube-prometheus-stack/data-prometheus-kube-prometheus-stack-prometheus-0 gp3 <unset> 23h
NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE
persistentvolumeclaim/fsx-lustre-claim Bound fsx-pv 1200Gi RWX <unset> 7s
WSParticipantRole:~/environment/eks/FSxL $
FSx console에서 확인
View options and performance details in the Amazon FSx console
- In the FSx console you will see a list of your FSx Instances, including the details of the FSx for Lustre instance that was pre-provisioned for you as part of the lab (which you then configured as a Persistent Volume in the EKS cluster).
- FSx 콘솔에서 FSx 인스턴스 목록을 확인할 수 있으며, 이미 1200GiB 크기의 FSx for Lustre 인스턴스가 사전 프로비저닝되어 있는 것을 볼 수 있습니다.
이 인스턴스는 Persistent-SSD 스토리지를 사용하며, 스토리지 단위(1TiB)당 250MB/s의 처리량(Throughput Capacity)을 제공합니다. - FSx 인스턴스와 관련된 세부 정보를 확인할 수 있으며, 온라인에서 업데이트할 수 있는 항목들도 함께 표시됩니다.
여기서 스토리지 용량(Storage Capacity)과 스토리지 단위당 처리량(Throughput per unit of storage)을
업데이트할 수 있는 옵션이 제공되는 것을 확인할 수 있습니다.
Gen AI 어플리케이션 배포
Deploy Generative AI Chat application
✅ 모듈 개요
이 모듈에서는 Kubernetes 위에 생성형 AI 챗봇 애플리케이션을 배포하는 방법을 학습합니다.
Amazon EKS 클러스터에 vLLM 파드와 WebUI 파드를 배포하고, Amazon FSx for Lustre 및 Amazon S3를 활용해 Mistral-7B 모델을 저장하고 액세스합니다.
또한, 생성형 AI 워크로드를 위해 AWS Inferentia 가속기를 사용하는 방법을 배웁니다.
✅ 생성형 AI와 머신러닝 (ML)
생성형 AI와 머신러닝은 기업이 운영 방식과 혁신 방식을 변화시키는 데 큰 역할을 하고 있습니다.
생성형 AI는 대규모 언어 모델(LLM)을 기반으로 텍스트, 이미지, 오디오, 소프트웨어 코드 등 새로운 콘텐츠를 프롬프트로부터 생성하는 AI의 한 형태입니다.
✅ 대규모 언어 모델(LLM)이란?
LLM은 방대한 텍스트 데이터를 학습하여 자연어의 패턴과 구조를 이해하는 머신러닝 모델입니다.
이러한 모델은 텍스트 생성, 질의 응답, 번역 등 다양한 자연어 처리 작업에 사용됩니다.
이 랩에서는 오픈소스 모델인 Mistral-7B-Instruct를 사용합니다.
이 모델은 70억 개의 파라미터를 가진 LLM이며, 단순한 텍스트 생성 이상의 작업을 수행할 수 있도록 지시문(instruction)을 따르는 방식으로 훈련되었습니다.
따라서 챗봇 애플리케이션에 적합한 모델입니다.
✅ vLLM이란?
vLLM(Virtual Large Language Model)은 LLM 추론 및 서빙을 위한 오픈소스 라이브러리입니다.
Mistral-7B-Instruct와 같은 모델을 배포하여 텍스트 생성 기능을 제공하며, OpenAI API와 호환되는 인터페이스를 제공하여 통합이 용이합니다.
vLLM의 특징:
✅ 성능:
- 최첨단 추론 처리량
- PagedAttention을 활용한 키/값 메모리 효율 관리
- 요청의 연속적 배치 처리
- CUDA/HIP 그래프를 통한 빠른 실행
✅ 유연성:
- HuggingFace 모델과의 통합
- OpenAI 호환 API 서버
- Prefix caching 지원
- 다양한 칩셋 지원: AWS Neuron, NVIDIA GPU 등
✅ vLLM을 Amazon EKS에 배포하기
생성형 텍스트 추론 기능을 OpenAI API 호환 엔드포인트 형태로 제공하기 위해,
Amazon EKS 클러스터 위에 vLLM 프레임워크를 사용해 Mistral-7B-Instruct 모델을 배포합니다.
이 과정에서는 Karpenter를 통해 AWS Inferentia2 EC2 노드(생성형 AI용 가속 컴퓨팅 인스턴스)를 자동 생성하며,
vLLM 파드는 해당 노드에서 컨테이너 이미지로 실행됩니다.
✅ AWS Inferentia 가속기란?
AWS Inferentia는 AWS가 생성형 AI 및 딥러닝 추론을 가속화하기 위해 설계한 맞춤형 머신러닝 칩입니다.
Amazon EC2에서 낮은 비용으로 높은 성능을 제공하며, TensorFlow, PyTorch, MXNet 등의 프레임워크를 지원합니다.
특히, 대규모 언어 모델(LLM) 및 잠재 디퓨전 모델(latent diffusion model) 같은 복잡한 모델을 대규모로 배포하는 데 최적화되어 있습니다.
Inferentia는 추론(Inference) 단계의 성능을 가속화합니다.
이 단계는 훈련된 모델이 새로운 데이터에 대해 예측을 수행하는 것으로, 실시간 서비스에 중요한 낮은 지연 시간과 높은 처리량이 요구됩니다.
Inferentia2의 주요 사양:
- 2개의 2세대 NeuronCore를 탑재한 가속기 최대 12개 (EC2 Inf2 인스턴스당)
- 각 가속기는 FP16 기준 최대 190 TFLOPS 성능
- 가속기당 32GB HBM 메모리
- 이전 세대 대비 4배의 총 메모리 및 10배의 메모리 대역폭 제공
✅ AWS Neuron SDK
AWS Neuron SDK는 컴파일러, 런타임, 프로파일링 도구를 포함한 SDK로,
딥러닝 추론을 고성능·저비용으로 실행할 수 있게 해줍니다.
- PyTorch, TensorFlow 등 주요 ML 프레임워크와 네이티브 통합
- 최소한의 코드 변경으로 Inferentia에서 모델 배포 가능
- NLP, 번역, 텍스트 요약, 이미지·비디오 생성, 음성 인식, 개인화, 사기 탐지 등 다양한 생성형 AI 워크로드에 활용 가능
이 모듈을 통해 사용자는 EKS 기반의 생성형 AI 서비스 인프라를 구성하고 최적화된 컴퓨팅 리소스와 스토리지를 통합하는 전체 흐름을 학습하게 됩니다.
Karpenter 구성은 NodePool 커스텀 리소스(Custom Resource, CR) 형태로 제공됩니다.
NodePool은 Karpenter가 생성할 수 있는 노드와 해당 노드에서 실행될 수 있는 파드에 대한 제약 조건을 설정합니다.
NodePool을 사용하면,
- 특정 컴퓨팅 아키텍처로만 노드를 생성하도록 제한할 수 있고,
- 여러 아키텍처를 유연하게 사용할 수 있도록 구성할 수도 있습니다.
하나의 Karpenter NodePool은 다양한 형태의 파드(Pod shapes)를 처리할 수 있습니다.
Karpenter는 파드의 라벨, 어피니티(Affinity) 등의 속성을 기준으로 스케줄링 및 노드 프로비저닝 결정을 내립니다.
클러스터에는 여러 개의 NodePool을 생성할 수 있지만,
Gen AI 어플리케이션 배포
- 이번에는 추가적인 하나의 NodePool, 즉 Inferentia 전용 NodePool을 선언합니다.
- Lets take a look at the Karpenter NodePool definition that we will deploy.
- It will create a new nodepool for AWS Inferentia INF2 Accelerated Compute nodes that we will use to power our Generative AI application (vLLM pod)
$ cd /home/ec2-user/environment/eks/genai
$ cat 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: karpenter
$ kubectl get nodepool,ec2nodeclass inferentia
NAME NODECLASS NODES READY AGE
nodepool.karpenter.sh/inferentia inferentia 0 True 11m
NAME READY AGE
ec2nodeclass.karpenter.k8s.aws/inferentia True 11m
이제 EKS 클러스터에 Neuron Device Plugin과 Neuron Scheduler를 설치해야 합니다.
✅ Neuron Device Plugin
Neuron Device Plugin은 Neuron 코어 및 디바이스를 Kubernetes 리소스로 노출시켜 사용할 수 있도록 합니다.
아래 명령어를 실행하여 Neuron Device Plugin을 설치하세요
(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
Neuron Scheduler 확장 기능은 하나 이상의 Neuron 코어나 디바이스 리소스를 요구하는 파드의 스케줄링을 위해 필요합니다.
이 스케줄러는 연속되지 않은(non-contiguous) 코어/디바이스 ID를 가진 노드를 필터링하고,
연속된(contiguous) 코어/디바이스 ID를 요구하는 파드에 대해 올바르게 할당되도록 보장합니다.
아래 명령어를 실행하여 Neuron 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 apply -f mistral-fsxl.yaml
deployment.apps/vllm-mistral-inf2-deployment created
service/vllm-mistral7b-service created
$ kubectl get pod
NAME READY STATUS RESTARTS AGE
kube-ops-view-5d9d967b77-4nq6b 1/1 Running 0 24h
vllm-mistral-inf2-deployment-7d886c8cc8-6w49z 0/1 Pending 0 19s
WSParticipantRole:~/environment/eks/genai $
- Navigate to the Amazon EKS cluster Console
Click on the Compute tab, you will see there is now a new AWS Inferentia inf2.xlarge compute node
Model 배포
워크숍에서 배포하게 될 vLLM 기반 Mistral-7B-Instruct 모델은 OpenAI 호환 엔드포인트를 제공합니다.
이 엔드포인트를 사용하기 위해, "Open WebUI" 애플리케이션을 이용할 수 있습니다.
Open WebUI는 사용자들이 채팅 기반 인터페이스를 통해 LLM 모델과 상호작용할 수 있도록 설계된 애플리케이션입니다.
이 애플리케이션은 백엔드에서 vLLM 모델과 통신하며, 사용자는 직관적인 웹 UI를 통해 자연스럽게 대화를 이어갈 수 있습니다.
사용 방법은 다음과 같습니다:
- Open WebUI 애플리케이션 컨테이너를 배포합니다.
- 제공되는 WebUI URL에 접속합니다.
- LLM 모델과 대화를 시작하면 됩니다.
$ kubectl apply -f open-webui.yaml
$ kubectl get ing
NAME CLASS HOSTS ADDRESS PORTS AGE
open-webui-ingress alb * open-webui-ingress-1236350700.us-west-2.elb.amazonaws.com 80 14s