이 페이지 개선에 도움 주기
이 사용자 가이드에 기여하려면 모든 페이지의 오른쪽 창에 있는 GitHub에서 이 페이지 편집 링크를 선택합니다.
Terraform을 사용하여 AI/ML 워크로드용 Amazon EKS 클러스터 설정
작은 정보
향후 예정된 Amazon EKS AI/ML 워크숍에 등록
이 섹션에서는 Terraform을 사용하여 Amazon EKS에서 훈련 또는 추론 워크로드를 실행하는 데 필요한 인프라를 생성하는 단계를 안내합니다. 이 단계에는 EKS 클러스터 생성, EKS 자율 모드 또는 Karpenter를 사용하는 GPU 지원 노드, Prometheus 및 Grafana를 사용하는 모니터링 스택, 모델 가중치를 위한 Amazon S3 스토리지가 포함됩니다.
이러한 기능이 EKS 클러스터에서 EC2 인스턴스를 프로비저닝하고 자동으로 규모를 조정하는 방법에 대한 자세한 내용은 EKS 자율 모드 및 Karpenter
상위 수준 아키텍처 및 워크플로
다이어그램은 이 섹션의 설정에 대한 전체적인 AWS 아키텍처를 보여줍니다.
사전 조건
중요
EKS 클러스터, GPU 인스턴스, Application Load Balancer, Amazon Managed Service for Prometheus를 포함하여 이 자습서에서 생성하는 리소스에는 요금이 부과됩니다. 지속적으로 요금이 부과되는 것을 방지하려면 완료 후 리소스를 삭제하세요.
-
Terraform >= 1.15.0. 설정 지침은 Installing Terraform
을 참조하세요. -
kubectl>= 1.36. 설정 지침은 kubectl 및 eksctl 설정 섹션을 참조하세요. -
AWS CLI >= 2.27. 설정 지침은 설치를 참조하세요.
-
jq. 설정 지침은 jq 다운로드를 참조하세요.
도구 버전 확인:
terraform --version aws --version kubectl version --client jq --version
1단계: Terraform 코드 다운로드 및 배포
이 연습에서는 sample-eks-docs
git clone git@github.com:aws-samples/sample-eks-docs.git cd sample-eks-docs/ai-ml/set-up-cluster
리포지토리는 방금 이동한 ai-ml/set-up-cluster/ 디렉터리 아래에 다음과 같은 구조를 가지고 있습니다.
set-up-cluster/
├── scripts/
│ └── cleanup.sh
└── terraform/
├── auto-mode/
└── karpenter/
리포지토리는 두 개의 배포 경로를 제공합니다. 가이드 전체에서 하나만 선택하여 사용하세요.
-
EKS Auto Mode(
terraform/auto-mode/) - EKS Auto Mode는 핵심 네트워킹, 스토리지, 로드 밸런싱 추가 기능 외에도 훈련 및 추론 워크로드를 위한 다음 기능을 포함하고 관리합니다. EKS 노드 모니터링 에이전트, 자동 노드 복구, 빠른 컨테이너 풀을 위한 SOCI스냅샷터, 기본 NodeClass의 GPU 준비 상태. NVIDIA 디바이스 플러그인은 EKS 자율 모드가 GPU 지원 노드에 사용하는 Bottlerocket 가속 AMI에 포함되어 있습니다. -
자체 관리형 Karpenter(
terraform/karpenter/) - EKS Auto Mode가 없는 EKS 클러스터에서는 Terraform 코드가 훈련 및 추론 워크로드에 필요한 구성 요소를 설치하고 구성합니다. 여기에는 네트워킹 추가 기능(VPC CNI, CoreDNS, kube-proxy), Karpenter, EKS 노드 모니터링 에이전트, NVIDIA 디바이스 플러그인 및 빠른 컨테이너 풀을 위한 SOCI 스냅샷터가 포함됩니다.
중요
EKS Auto Mode 또는 자체 관리형 Karpenter를 선택하고 가이드 전체에서 사용합니다. 중간에 전환하려면 클러스터를 삭제하고 다시 시작해야 합니다.
EKS 클러스터 옵션: EKS 자율 모드와 자체 관리형 Karpenter
Grafana는 기본 자격 증명을 사용하여 HTTP를 통해 공개적으로 액세스할 수 있음
Grafana ALB Ingress는 var.my_cidr의 기본값을 0.0.0.0/0으로 설정합니다. 이로 인해 Grafana는 기본 관리자 자격 증명을 사용하여 일반 HTTP를 통해 퍼블릭 인터넷에 노출됩니다. 자동 스캐너는 몇 분 안에 퍼블릭 로드 밸런서를 검색합니다. 반드시 자체 IP 주소로 var.my_cidr을 재정의하여 액세스를 제한해야 합니다.
export MY_CIDR="$(curl -s https://checkip.amazonaws.com)/32" terraform apply -var "my_cidr=${MY_CIDR}"
소스 IP 허용 목록을 완전한 보호 수단이 아닌 최소한의 보호 수단으로 취급하세요. 또한 처음 로그인한 후 기본 Grafana 관리자 암호를 변경해야 합니다. 더 강력한 보안 태세를 위해 alb.ingress.kubernetes.io/scheme을 internal(VPC 또는 연결된 VPN 내에서만 연결 가능)로 변경하고 TLS 인증서를 추가하세요.
클러스터 배포
선택한 경로의 디렉터리로 이동하여 Terraform을 초기화한 후 다음을 적용합니다.
두 변형 모두 기본적으로 us-east-2 리전으로 설정됩니다. 다른 리전에 배포하려면 다음 단계의 terraform apply 명령에 -var "region=을 추가합니다. 여기서 region-code"region-code는 배포하려는 AWS 리전입니다.
Terraform 코드는 대상 리전의 사용 가능한 가용 영역을 모두 사용하지만, Amazon EKS는 use1-az3, usw1-az2 및 cac1-az3 가용 영역에서 컨트롤 플레인 배치를 지원하지 않으므로
Terraform 출력 검토
적용이 완료되면 Terraform은 다음 출력을 인쇄합니다(값은 구성에 따라 다름).
Apply complete! Resources: 74 added, 0 changed, 0 destroyed. Outputs: cluster_name = "ai-eks-docs" configure_kubectl = "aws eks update-kubeconfig --region us-east-2 --name ai-eks-docs --alias ai-eks-docs" configure_model_bucket = "export MODEL_BUCKET=ai-eks-docs-models-20250612abc1" model_bucket = "ai-eks-docs-models-20250612abc1" node_iam_role_name = "ai-eks-docs-eks-auto-20250612..." region = "us-east-2"
configure_kubectl 출력은 kubectl이 해당 클러스터를 가리키도록 하는 실행 가능한 명령입니다. model_bucket 출력에는 모델 가중치를 위한 S3 버킷 이름이 포함됩니다. node_iam_role_name 출력에는 노드가 사용하는 IAM 역할이 표시됩니다.
kubectl 구성
kubectl이 새 클러스터를 가리키도록 합니다. configure_kubectl 출력은 실행 가능한 명령입니다.
eval "$(terraform output -raw configure_kubectl)"
클러스터 확인
2단계: 동적 GPU NodePool 생성
GPU NodePool은 옵트인 방식입니다. 기본적으로 terraform apply는 GPU 용량 및 GPU 청구 없이 클러스터 및 모니터링 스택을 생성합니다. GPU 노드를 프로비저닝하려면 nodepools 변수에 전략 이름을 전달합니다.
온디맨드를 폴백으로 사용하는 스팟 용량을 사용하여 4세대보다 상위의 G 패밀리 GPU 인스턴스를 프로비저닝하는 spot-ondemand 전략을 활성화합니다.
terraform apply -var 'nodepools={"spot-ondemand"={}}'
이 명령은 nodepools/spot-ondemand/ 디렉터리의 NodePool 및 NodeClass 템플릿을 적용합니다. 두 경로 모두 동일한 NodePool API를 사용하지만 NodePool이 참조하는 NodeClass에서 차이가 있습니다.
두 경로 모두 GPU 워크로드가 예약될 때까지 gpu-inf의 0 노드를 표시합니다. EKS Auto Mode 및 Karpenter는 보류 중인 포드에 필요한 경우에만 노드를 시작합니다.
3단계: 샘플 포드로 테스트
nvidia-smi 포드를 사용하여 GPU NodePool 설정을 테스트합니다.
cat << EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: nvidia-smi labels: guide: ai-eks-docs spec: restartPolicy: OnFailure tolerations: - key: "nvidia.com/gpu" operator: "Exists" effect: "NoSchedule" containers: - name: nvidia-smi image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal command: ["nvidia-smi"] resources: limits: nvidia.com/gpu: 1 EOF
포드가 예약되고 성공적으로 완료되었는지 확인합니다.
kubectl get pods nvidia-smi
예상 결과:
NAME READY STATUS RESTARTS AGE nvidia-smi 0/1 Completed 0 67s
STATUS: Completed는 nvidia-smi 명령이 실행되고 종료되었음을 의미합니다. 포드 로그를 확인하여 노드에서 감지된 GPU를 확인합니다.
kubectl logs nvidia-smi
예상 결과:
+-----------------------------------------------------------------------------------------+ | NVIDIA-SMI 580.159.03 Driver Version: 580.159.03 CUDA Version: 13.0 | +-----------------------------------------+------------------------+----------------------+ | GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC | | Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. | | | | MIG M. | |=========================================+========================+======================| | 0 NVIDIA L4 On | 00000000:31:00.0 Off | 0 | | N/A 41C P8 13W / 72W | 0MiB / 23034MiB | 0% Default | | | | N/A | +-----------------------------------------+------------------------+----------------------+
출력에는 GPU 모델, 드라이버 버전, CUDA 버전, 사용 가능한 메모리가 표시됩니다. 이 예제에서 Karpenter는 메모리가 24GB인 NVIDIA L4 GPU가 있는 G6 인스턴스를 프로비저닝했습니다. GPU 모델 및 메모리는 Karpenter가 선택하는 인스턴스 유형에 따라 달라집니다. G5 인스턴스에는 NVIDIA A10G GPU(24GB)가 있고, G6 인스턴스에는 NVIDIA L4 GPU(24GB)가 있고, G6e 인스턴스에는 NVIDIA L40S GPU(48GB)가 있습니다.
노드를 프로비저닝하고 포드를 배치하기 위해 Karpenter와 Kubernetes 스케줄러가 어떻게 조정되는지 이해하려면 포드의 수명 주기 이벤트를 확인하세요.
kubectl describe pod nvidia-smi
예상 결과:
Events: Type Reason Age From Message ---- ------ ---- ---- ------- Warning FailedScheduling 75s default-scheduler 0/2 nodes are available: 2 node(s) had untolerated taint(s). Normal Nominated 74s eks-auto-mode/compute Pod should schedule on: nodeclaim/gpu-inf-z6q75 Normal Scheduled 35s default-scheduler Successfully assigned default/nvidia-smi to i-0eb897a8302551589 Normal Pulling 27s kubelet spec.containers{nvidia-smi}: Pulling image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" Normal Pulled 22s kubelet spec.containers{nvidia-smi}: Successfully pulled image "public.ecr.aws/amazonlinux/amazonlinux:2023-minimal" in 5.625s (5.626s including waiting). Image size: 37440620 bytes. Normal Created 22s kubelet spec.containers{nvidia-smi}: Container created Normal Started 21s kubelet spec.containers{nvidia-smi}: Container started
이러한 이벤트는 포드 예약 시퀀스를 보여줍니다. 처음에 포드가 GPU 노드가 없어 예약에 실패하고(FailedScheduling), Karpenter가 새 NodeClaim을 지명하고(Nominated), 노드가 준비되면 스케줄러가 포드를 할당한 다음(Scheduled) 컨테이너 이미지를 가져와 시작합니다. EKS Auto Mode는 기본적으로 G, P 및 Trn 인스턴스에 SOCI(Seekable OCI) 병렬 풀이 설치 및 구성되어 있으며 자체 관리형 Karpenter 경로는 FastImagePull 기능 게이트를 통해 이를 명시적으로 구성합니다.
참고
자체 관리형 Karpenter 클러스터에서 Nominated 이벤트는 eks-auto-mode/compute 대신 karpenter/compute를 표시합니다.
NodeClaim은 Karpenter가 특정 노드를 프로비저닝하기 위해 생성하는 요청입니다. 이 요청은 인스턴스 유형, 용량 유형, AZ, 노드 준비 여부를 보여줍니다.
kubectl get nodeclaims
예상 결과:
NAME TYPE CAPACITY ZONE NODE READY AGE gpu-inf-z6q75 g6.xlarge spot us-east-2a i-0eb897a8302551589 True 5m
인스턴스 유형 및 AZ는 다양합니다. 4세대보다 상위의 G 패밀리 인스턴스는 모두 사용할 수 있습니다.
작은 정보
노드가 표시되지 않으면 용량 부족 오류를 확인합니다.
kubectl get events | grep InsufficientCapacityError
Karpenter는 사용할 수 없는 오퍼링을 3분 동안 캐싱합니다. NodePool에서 허용되는 인스턴스 유형과 AZ를 확장하면 랜딩 용량이 늘어납니다.
참고
Karpenter가 시작한 스팟 인스턴스는 EC2 스팟 요청 콘솔에 표시되지 않습니다. Karpenter는 type: instant와 함께 EC2 CreateFleet API를 사용합니다. 인스턴스는 spot 수명 주기와 함께 EC2 인스턴스 콘솔에 표시됩니다.
4단계: NodePool에 예약 용량 추가(선택 사항)
2단계의 GPU NodePool은 스팟 또는 온디맨드 인스턴스를 동적으로 프로비저닝하지만 일부 사용 사례에서는 보장된 용량이 필요합니다. 필요할 때 GPU 용량을 사용할 수 있도록 온디맨드 용량 예약(ODCR)을 생성할 수 있습니다.
Terraform을 사용하면 단일 명령으로 태그별로 예약을 참조하는 사용자 지정 NodeClass인 ODCR을 생성하고, reserved를 용량 유형으로 포함하도록 NodePool을 업데이트합니다. Terraform은 ODCR에 nodepool=reserved-spot-ondemand 태그를 지정하고 NodeClass는 해당 태그로 ODCR을 선택합니다.
주의
다음 명령은 ODCR을 생성합니다. ODCR은 노드 실행 여부에 관계없이 즉시 요금 청구를 시작하고 terraform destroy 또는 정리 스크립트를 사용하여 폐기할 때까지 청구를 계속합니다.
기본값을 사용합니다(g6e.4xlarge, 인스턴스 1개, 첫 번째 클러스터 AZ).
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={}}}'
인스턴스 유형, 개수 및 AZ를 선택합니다.
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={instance_type="g6e.2xlarge",instance_count=1,az="us-east-2a"}}}'
reservation 객체는 다음 필드를 지원합니다.
-
instance_type- 예약할 GPU 인스턴스 유형입니다. 기본값:g6e.4xlarge. -
instance_count- 예약할 인스턴스 수입니다. 기본값:1. -
az- 예약의 가용 영역입니다. 기본값:""(첫 번째 클러스터 AZ 사용).
중요
spot-ondemand 및 reserved-spot-ondemand 전략은 함께 사용할 수 없습니다. nodepools 변수에서 최대 1개를 활성화할 수 있습니다. 이전에 2단계에서 spot-ondemand를 사용한 경우, 둘 다 동일한 gpu-inf NodePool을 관리하기 때문에 reserved-spot-ondemand 명령이 이를 대체합니다.
InsufficientInstanceCapacity 오류가 발생하면 지정된 AZ에서 예약을 이행할 수 없습니다. Terraform 작업을 취소(Ctrl+C)한 다음 다른 az 값으로 다시 실행합니다.
terraform apply -var 'nodepools={"reserved-spot-ondemand"={reservation={instance_type="g6e.4xlarge",az="us-east-2b"}}}'
적용 후 Terraform은 용량 유형 요구 사항에 reserved, spot, on-demand를 포함하도록 NodePool을 업데이트합니다. Karpenter는 reserved를 가장 비용 효율적인 옵션으로 취급하고 먼저 시작합니다. 예약이 가득 차면 스팟 또는 온디맨드로 대체합니다.
EKS Auto Mode 경로에서 Terraform은 capacityReservationSelectorTerms을 통해 태그별로 ODCR을 참조하는 사용자 지정 gpu-inf NodeClass(번들 default NodeClass가 읽기 전용이기 때문)를 생성합니다. 자체 관리형 Karpenter 경로에서 Terraform은 capacityReservationSelectorTerms가 추가된 gpu-inf EC2NodeClass를 다시 적용하고 reserved를 포함하도록 NodePool을 업데이트합니다.
ODCR이 생성되었는지 확인합니다.
aws ec2 describe-capacity-reservations \ --filters "Name=state,Values=active" "Name=tag:nodepool,Values=reserved-spot-ondemand" \ --query 'CapacityReservations[0].{Id:CapacityReservationId,State:State,InstanceType:InstanceType,AvailableCount:AvailableInstanceCount}' \ --output table \ --region $(terraform output -raw region)
NodeClass가 ODCR을 참조하는지 확인합니다.
NodePool이 준비되었는지 확인합니다.
kubectl get nodepools gpu-inf
예상 결과:
NAME NODECLASS NODES READY AGE gpu-inf gpu-inf 0 True 30s
변경 사항을 적용한 후 Karpenter가 예약 용량의 우선 순위를 지정하고 스팟 또는 온디맨드로 대체하는지 확인합니다. 포드당 GPU 1개를 요청하는 2-복제본 배포를 배포합니다. ODCR은 인스턴스 1개(GPU 1개)용이므로 첫 번째 포드는 Karpenter가 예약 노드를 시작하도록 트리거합니다. 두 번째 포드는 예약된 노드에 맞을 수 없으며 Karpenter가 스팟 또는 온디맨드 용량에서 다른 노드를 시작하도록 트리거합니다.
cat << 'EOF' | kubectl apply -f - apiVersion: apps/v1 kind: Deployment metadata: name: gpu-overflow-test labels: guide: ai-eks-docs spec: replicas: 2 selector: matchLabels: app: gpu-overflow-test template: metadata: labels: app: gpu-overflow-test guide: ai-eks-docs spec: tolerations: - key: nvidia.com/gpu operator: Exists effect: NoSchedule containers: - name: nvidia-smi image: public.ecr.aws/amazonlinux/amazonlinux:2023-minimal command: ["sh", "-c", "nvidia-smi && sleep infinity"] resources: limits: nvidia.com/gpu: 1 EOF
실행하고 종료한 3단계의 nvidia-smi 테스트 포드와 달리 이 배포는 포드를 계속 실행(sleep infinity)하므로 GPU가 유지되고 노드가 통합되지 않습니다.
다른 노드에 예약된 포드를 확인합니다.
kubectl get pods -l app=gpu-overflow-test -o wide
예상 결과:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES gpu-overflow-test-55d55ff5b9-dvg52 1/1 Running 0 4m42s 10.0.75.210 i-08741a36089ff2088 <none> <none> gpu-overflow-test-55d55ff5b9-hw4m9 1/1 Running 0 4m43s 10.0.82.49 i-0f50cdbacb2017202 <none> <none>
NodeClaim에서 용량 유형을 확인합니다.
kubectl get nodeclaims
예상 결과:
NAME TYPE CAPACITY ZONE NODE READY AGE gpu-inf-vw99m g6e.4xlarge reserved us-east-2c i-0f50cdbacb2017202 True 6m gpu-inf-s65s6 g6.xlarge spot us-east-2b i-08741a36089ff2088 True 5m59s
예약 노드가 먼저 시작된 후 예약이 가득 차면 스팟 또는 온디맨드 노드가 시작됩니다.
테스트 배포 정리:
kubectl delete deployment gpu-overflow-test
모니터링
Terraform은 1단계의 terraform apply 동안 이미 전체 모니터링 스택을 프로비저닝했습니다. 이 스택에는 Amazon Managed Service for Prometheus(AMP) 워크스페이스, Prometheus 원격 쓰기 및 Grafana 쿼리 액세스를 위한 IAM 정책 및 EKS Pod Identity 연결, kube-prometheus-stack 헬름 차트(Prometheus, Grafana, kube-state-metrics, node-exporter), GPU 지표를 위한 NVIDIA DCGM Exporter가 포함됩니다.
이 섹션에서는 배포된 모니터링 구성 요소의 확인을 다룹니다.
모니터링 포드 확인
모든 모니터링 포드가 준비될 때까지 기다립니다.
kubectl wait --for=condition=Ready pod --all -n monitoring --timeout=300s kubectl get pods -n monitoring
예상 결과:
NAME READY STATUS RESTARTS AGE kube-prometheus-stack-grafana-7c58f54f77-rftrj 3/3 Running 0 5m kube-prometheus-stack-kube-state-metrics-d68dcbc84-5smxq 1/1 Running 0 5m kube-prometheus-stack-operator-5895df479f-ttm47 1/1 Running 0 5m kube-prometheus-stack-prometheus-node-exporter-t9q7s 1/1 Running 0 5m kube-prometheus-stack-prometheus-node-exporter-x6vfb 1/1 Running 0 5m prometheus-kube-prometheus-stack-prometheus-0 2/2 Running 0 5m
Grafana에 액세스
Grafana는 var.my_cidr에서 설정한 CIDR로 제한된 인터넷 경계 AWS Application Load Balancer(ALB)를 통해 노출됩니다. 로드 밸런서 URL을 출력합니다(ALB가 프로비저닝하는 데 1~2분 소요).
echo "http://$(kubectl get ingress kube-prometheus-stack-grafana -n monitoring -o jsonpath='{.status.loadBalancer.ingress[0].hostname}')"
브라우저에서 URL을 엽니다. 다음 명령에서 사용자 이름 admin과 암호를 사용하여 로그인합니다.
kubectl --namespace monitoring get secrets kube-prometheus-stack-grafana -o jsonpath="{.data.admin-password}" | base64 -d ; echo
지표 파이프라인 확인
지표 파이프라인이 종단 간 작동하는지 확인하려면:
-
연결 > 데이터 소스로 이동하여 Amazon-Managed-Prometheus가 기본 데이터 소스로 나열되었는지 확인합니다.
Grafana에서 AMP 데이터 소스 검증
-
드릴다운 > 지표로 이동하여
up지표를 검색합니다. 클러스터의 스크레이프 대상의 결과가 표시되어야 합니다.Grafana에서
up지표 검증
up에 결과가 표시되면 파이프라인(클러스터 → Prometheus → AMP → Grafana)이 작동하는 것입니다.
DCGM GPU 지표 검증
DCGM Exporter DaemonSet는 GPU 노드에서 실행되며 GPU 사용률, 메모리, 온도, 전력 소비, NVLink 대역폭 및 텐서 활동 지표를 보고합니다.
DCGM Exporter DaemonSet를 확인합니다.
kubectl get daemonset dcgm-exporter -n monitoring
GPU 노드가 실행되면(2단계 또는 4단계) 하나 이상의 준비된 포드가 표시됩니다. DCGM 지표를 검증하려면 Grafana에서 드릴다운 > 지표로 이동하여 DCGM_을 검색합니다.
Grafana에서 DCGM 지표 검증
대시보드를 보려면 대시보드 > GPU 모니터링 > NVIDIA DCGM Exporter Dashboard로 이동합니다.
Grafana의 NVIDIA DCGM Exporter Dashboard
모델 가중치 S3 버킷
Terraform은 이미 모델 가중치를 저장하기 위한 Amazon S3 버킷, default 네임스페이스의 model-storage-sa ServiceAccount, 버킷으로 범위가 지정된 IAM 정책, 그리고 이들을 연결하는 EKS Pod Identity 연결을 생성했습니다. serviceAccountName: model-storage-sa를 설정하는 워크로드 포드는 버킷에서 읽고 쓸 수 있습니다.
버킷 확인
Terraform 출력에서 버킷 이름을 검색합니다.
MODEL_BUCKET=$(terraform output -raw model_bucket) echo ${MODEL_BUCKET}
버킷이 존재하는지 확인합니다.
aws s3api head-bucket --bucket ${MODEL_BUCKET}
예상 결과:
{
"BucketArn": "arn:aws:s3:::ai-eks-docs-models-20250612abc1",
"BucketRegion": "us-east-2",
"AccessPointAlias": false
}
model-storage-sa ServiceAccount를 사용하여 AWS CLI 이미지로 일회성 포드를 실행하여 EKS Pod Identity가 연결되어 있고 S3 액세스가 작동하는지 확인합니다.
cat << EOF | kubectl apply -f - apiVersion: v1 kind: Pod metadata: name: s3-test labels: guide: ai-eks-docs spec: serviceAccountName: model-storage-sa containers: - name: aws-cli image: public.ecr.aws/aws-cli/aws-cli:2.27.0 command: - sh - -c - | echo "=== Caller Identity ===" aws sts get-caller-identity echo "" echo "=== S3 Write Test ===" echo "pod identity works" | aws s3 cp - s3://${MODEL_BUCKET}/test.txt echo "" echo "=== S3 List Test ===" aws s3 ls s3://${MODEL_BUCKET}/ echo "" echo "=== S3 Delete Test ===" aws s3 rm s3://${MODEL_BUCKET}/test.txt restartPolicy: Never EOF
포드가 완료될 때까지 기다렸다가 로그를 확인합니다.
kubectl wait --for=jsonpath='{.status.phase}'=Succeeded pod/s3-test --timeout=300s kubectl logs s3-test
예상 결과:
=== Caller Identity ===
{
"UserId": "AROA...:eks-ai-eks-docs-model-s-...",
"Account": "123456789012",
"Arn": "arn:aws:sts::123456789012:assumed-role/ai-eks-docs-models-.../eks-ai-eks-docs-..."
}
=== S3 Write Test ===
upload: - to s3://ai-eks-docs-models-20250612abc1/test.txt
=== S3 List Test ===
2026-07-15 12:00:00 19 test.txt
=== S3 Delete Test ===
delete: s3://ai-eks-docs-models-20250612abc1/test.txt호출자 자격 증명은 포드가 EKS Pod Identity를 통해 모델 스토리지 역할을 수임했음을 확인합니다. S3 명령은 읽기 및 쓰기 액세스를 확인합니다.
테스트 포드를 정리합니다.
kubectl delete pod s3-test
다음 단계
클러스터가 준비되면 모델 로드 및 제공으로 이동하여 대규모 언어 모델을 배포하고 추론 엔드포인트와 상호 작용할 수 있습니다.
정리
작은 정보
이 가이드의 다음 섹션을 계속 진행하려면 전체 정리를 건너뛰세요. 완료한 경우에만 정리를 실행합니다.
GPU 노드를 보유한 포드가 없도록 테스트 워크로드를 삭제합니다.
kubectl delete pod nvidia-smi --ignore-not-found kubectl delete deployment gpu-overflow-test --ignore-not-found
ODCR만 릴리스하고 스팟 및 온디맨드 용량으로 대체하려면 nodepools 변수를 spot-ondemand 전략으로 다시 전환합니다.
terraform apply -var 'nodepools={"spot-ondemand"={}}'
이렇게 하면 NodePool 용량 유형 요구 사항에서 reserved가 제거되고 ODCR이 삭제되며 클러스터, 모니터링 스택 및 S3 버킷은 그대로 유지됩니다.
중요
예약을 취소해도 이미 실행 중인 인스턴스는 종료되지 않습니다. 이러한 인스턴스는 종료될 때까지 표준 온디맨드 요금으로 계속 실행됩니다. 예약이 해제되기 전에 예약된 노드가 드레이닝되도록 위와 같이 GPU 워크로드를 먼저 삭제합니다.
삭제하기 전에 Karpenter 관리형 노드를 드레이닝합니다. 이렇게 하면 진행 중인 노드 수명 주기가 삭제를 차단하지 않습니다. 드레이닝을 방해할 수 있는 PodDisruptionBudget을 모두 삭제한 다음 NodeClaim을 삭제합니다.
kubectl delete pdb -A --all --ignore-not-found kubectl delete nodeclaim --all --wait=true --timeout=900s
그런 다음 EKS 클러스터, VPC, 모니터링 스택, NodePool 및 NodeClass, S3 모델 버킷, ODCR을 포함하여 Terraform이 생성한 모든 항목을 삭제합니다.
terraform destroy
주의
모델 가중치 S3 버킷은 force_destroy = true를 사용하여 생성되므로 terraform destroy는 버킷에 업로드한 모델 가중치와 함께 버킷을 삭제합니다. 보관하려는 모든 항목을 먼저 다른 위치에 복사합니다.
참고
또한 리포지토리는 위의 드레이닝 및 삭제 단계를 실행한 다음 클러스터 이름으로 태그가 지정된 분리된 EBS 볼륨을 모두 스윕하는 scripts/cleanup.sh 헬퍼를 제공합니다. 적용을 실행한 terraform/<mode>/ 디렉터리 내에서 이 헬퍼를 실행하고 --auto-approve를 전달하여 Terraform 확인 프롬프트를 건너뜁니다.
클러스터에 활성 용량 예약이 남아 있지 않은지 확인합니다.
aws ec2 describe-capacity-reservations \ --filters "Name=state,Values=active" "Name=tag:nodepool,Values=reserved-spot-ondemand" \ --query 'CapacityReservations[].CapacityReservationId' \ --output text
결과가 비어 있으면 활성화된 예약이 없으며 추가 요금이 부과되지 않습니다.