vLLM on EKS

DevOps를 위한 LLM 서빙 도입 가이드

Amazon EKS + vLLM + RayServe를 활용한 프로덕션 레벨 LLM 추론 인프라 구축 | 1시간 세션

오늘 세션 구성

총 60min 세션

1
vLLM 기초 & 핵심 기술 15분
2
EKS 아키텍처 & 인프라 구성 15분
3
Ray-vLLM 배포 딥다이브 15분
4
운영 베스트 프랙티스 & 비용 최적화 15분

GPU 자원 관리
  • • A10G(24GB) 1장에 7B 모델 1개
  • • 70B 모델은 8×A100 필요
  • • 수백만 원/월 인스턴스 비용
⏱️
레이턴시 요구사항
  • • TTFT < 500ms 목표
  • • ITL < 100ms 스트리밍
  • • 사용자 이탈률과 직결
📈
동적 스케일링
  • • 트래픽 변동 10× 이상
  • • GPU 노드 시작 5~10분
  • • Cold Start 문제
💸
비용 폭발
  • • GPU On-Demand $3~30/hr
  • • 유휴 GPU = 비용 낭비
  • • Spot 중단 리스크

핵심 기능
PagedAttention v2 — KV Cache 파편화 제거, 메모리 효율 극대화
Continuous Batching — v0.6+ 기준 처리량 2.7배 향상
V1 Engine (2025) — Disaggregated Serving 지원
OpenAI 호환 API — base_url 변경만으로 전환
프로덕션 채택
Amazon Rufus: 80,000 chip 규모 | Stripe: GPU 73% 절감
GitHub Stars 75K+ | 기여자 2,000+
프레임워크 성능 비교 (8×H100, Llama-3.1 70B)
프레임워크 tok/s 강점
vLLM ⭐ 권장 ~12,500 범용, 최대 HW 지원
SGLang ~16,200 RAG, Agent 최적화
TGI ~11,000 HuggingFace 통합
TensorRT-LLM ~18,000 NVIDIA 전용 최고 성능
※ 처리량 단독이 아닌 안정성·생태계·운영 편의성 종합 시 vLLM이 1위

기존 방식 — 정적 메모리 할당
✗ 최대 시퀀스(4096 token)로 VRAM 사전 예약
✗ 실제 512 token 사용 → VRAM 87.5% 낭비
✗ 요청 간 메모리 파편화 → 동시 처리 급감
✗ 실측 메모리 낭비율: 60~80%
메모리 예약 vs 실제 사용
실사용 12.5% 낭비 87.5%
PagedAttention — 동적 페이지 관리
✓ KV Cache를 16-token 블록 단위로 분할
✓ 논리 블록 ↔ 물리 블록 동적 매핑
✓ 필요한 만큼만 할당, 완료 즉시 반환
✓ 메모리 낭비율 <4% → 동시 처리 2~4배↑
V2 추가 기능 (2024+)
KV Cache 멀티 파티션 → Multi-Thread Block 병렬 처리
긴 컨텍스트(128k+) 처리 최적화 | FP8 네이티브

V1 Engine 개편 포인트
Multi-Process 분리
API Server ↔ Inference Engine 별도 프로세스 → Python GIL 병목 제거
Chunked Prefill
긴 입력을 청크로 분할 스케줄링 → Decode stall 방지
Async Output Processing
GPU 연산과 출력 처리 비동기 중첩 → E2E 처리량 ~24%↑
Multi-Step Scheduling
여러 스텝 미리 스케줄링 → CPU-GPU 동기화 오버헤드 제거
Disaggregated Serving (P/D 분리)
Prefill(연산 집약)과 Decode(메모리 대역폭 집약)를 물리적으로 분리하여 각 단계 최적화
Prefill Nodes
연산 집약적
High TFLOPS
H100 / A100
KV→
Decode Nodes
메모리 대역폭
High VRAM
A10G / L40S
• P/D 독립 스케일링 → 비용 최적화
• EKS: Karpenter로 두 NodePool 분리 관리
• 2025년 초기 프로덕션 채택 단계

Karpenter GPU 동적 프로비저닝
NodePool 설정만으로 GPU 인스턴스 자동 확장/축소 | Spot 활용으로 비용 60~70% 절감 | g5, g6, p4d, p5 자동 선택
관리형 컨트롤 플레인
EKS가 Master 노드 운영 부담 제거 | EKS Auto Mode로 노드 관리까지 위임 | 99.95% SLA 보장
풍부한 GPU 생태계
Prometheus + Grafana 모니터링 | KubeRay 분산 추론 오케스트레이션 | NVIDIA Device Plugin + DCGM Exporter
운영 표준화
기존 K8s CI/CD 파이프라인 재활용 | Helm Chart 배포 표준화 | ArgoCD GitOps 통합

github.com/awslabs/ai-on-eks — AWS Solution Architects가 관리하는 프로덕션 레퍼런스 (Apache 2.0)
Layer 1
infra/base/terraform/
재사용 가능 Terraform 모듈 | VPC, EKS, Karpenter, 40+ 애드온 자동 설치
Layer 2
infra/<architecture>/
레퍼런스 아키텍처 | JARK Stack, Triton, Neuron, Dynamo
Layer 3
blueprints/
엔드투엔드 예제 | 18+ 추론 블루프린트, Helm Chart, K8s 매니페스트
Workshop
genai.eksworkshop.com
Helm Charts
awslabs/ai-on-eks-charts
Docs
awslabs.github.io/ai-on-eks

🧠
PagedAttention
OS 페이지 테이블 방식
KV Cache 낭비 <4%
Continuous Batching
Iteration-level Scheduling
처리량 2.7배, TPOT 5배
🏗️
EKS + Karpenter
GPU 동적 프로비저닝
Spot 활용 비용 60~70%↓
블록 내비게이션
← 목차로 돌아가기 다음: EKS 아키텍처 & 인프라 →

Part 2 — EKS 아키텍처 & 인프라

Inference-Ready Cluster 구성, GPU 스택, Karpenter 동작 원리

VPC + EKS Cluster
EKS Control Plane (Managed)
API Server | etcd | Scheduler | 99.95% SLA
CPU Nodes
System Pods
Karpenter
GPU Nodes
vLLM Pods
g5/g6/p4d/p5
애드온 (자동 설치)
KubeRay Operator | NVIDIA Device Plugin
Karpenter | Prometheus + Grafana
AWS LB Controller | EBS/EFS CSI
AWS 관리 서비스
ECR — 컨테이너 이미지
S3 — 모델 아티팩트 캐시
EFS — 공유 모델 스토리지
Secrets Manager — HF Token 보안 관리
EKS Pod Identity / IRSA — Pod 레벨 권한
CloudWatch — 로그 & 감사 추적

배포 패턴 적합 시나리오 복잡도 스케일링 GPU
Ray-vLLM ⭐ 권장 프로덕션, 자동 스케일링 중간 RayServe 내장 1+
vLLM Standalone PoC, 빠른 시작 낮음 HPA 1+
Triton-vLLM 멀티모델, A/B 테스트 높음 HPA + Custom 1+/모델
AIBrix-vLLM 관리형, 라우팅 최적화 낮음 내장 옵티마이저 1+
LWS-vLLM 초대형 모델 (405B+) 높음 멀티노드 4+ 노드
Dynamo-vLLM KV-aware 라우팅 매우 높음 SLA 기반 2+
⭐ Ray-vLLM 권장 이유
RayServe 오토스케일링 내장 (요청 수 기반 자동 확장) | Karpenter와 연동하여 GPU 노드 자동 프로비저닝 | Helm Chart 3줄로 배포 가능 (inference-charts) | 프로덕션 환경에서 가장 검증된 패턴

인스턴스 GPU VRAM $/hr 적합 모델 비고
g5.xlarge 1× A10G 24 GB ~$1.01 7B (Mistral, Llama-3.2) 가장 경제적
g6.xlarge 1× L4 24 GB ~$0.80 7B g5 대비 저렴
g5.12xlarge 4× A10G 96 GB ~$5.67 13B~34B TP=4 분산
g6e.12xlarge 4× L40S 192 GB ~$8.49 34B~70B 차세대 GPU
p4d.24xlarge 8× A100 320 GB ~$32.77 70B 고성능
p5.48xlarge 8× H100 640 GB ~$98.32 405B+ 최대 성능
VRAM 계산 공식 (BF16 기준):
모델 가중치(GB) ≈ 파라미터 수(B) × 2  |  7B ≈ 14GB → g5.xlarge 충분  |  70B ≈ 140GB → p4d.24xlarge TP=8
Spot 절감: g5 Spot = On-Demand 대비 60~70% 할인 (가용성 사전 확인 필수)

# ai-on-eks/infra/solutions/inference-ready-cluster/
# 1. Clone & Configure
git clone https://github.com/awslabs/ai-on-eks.git
cd ai-on-eks/infra/solutions/inference-ready-cluster
# 2. blueprint.tfvars 편집
region = "us-west-2"
enable_karpenter = true
enable_kuberay = true
enable_lws = true
enable_nvidia_plugin = true
enable_observability = true
# 3. Deploy (약 20분)
terraform init && terraform apply -var-file=blueprint.tfvars
자동 설치 컴포넌트
✦ VPC (Multi-AZ, Private Subnet)
✦ EKS Cluster + Managed Node Group
✦ Karpenter (GPU/CPU NodePools)
✦ KubeRay Operator
✦ NVIDIA Device Plugin + NFD
✦ DCGM Exporter
✦ Prometheus + Grafana
✦ AWS LB Controller + EBS CSI

Application
vLLM Engine — CUDA 애플리케이션, PyTorch, FlashAttention-2
K8s Metrics
DCGM Exporter — GPU 활용률, 온도, 전력, VRAM 메트릭 노출
K8s Discovery
Node Feature Discovery — GPU 특성 자동 라벨링 (CUDA 버전, GPU 모델)
K8s Plugin
NVIDIA Device Plugin — GPU 리소스 등록 및 Pod 할당 관리
Container
NVIDIA Container Toolkit — GPU를 컨테이너에 노출 (nvidia-docker2)
Hardware
NVIDIA GPU — A10G 24GB / L4 24GB / A100 80GB / H100 80GB

🏗️
클러스터 아키텍처
EKS + Terraform
40+ 애드온 자동 설치
🎯
Ray-vLLM 권장
6가지 패턴 중
프로덕션 검증 완료
🖥️
GPU 스택
Device Plugin →
DCGM → vLLM
Karpenter
Pending → Node Ready
2~5분 자동 프로비저닝
← 목차로 돌아가기 다음: Ray-vLLM 배포 딥다이브 →

Part 3 — Ray-vLLM 배포 딥다이브

Helm Chart, RayService 매니페스트, 파라미터 튜닝, 모델별 최적 설정

apiVersion: karpenter.sh/v1
kind: NodePool
metadata:
  name: g5-gpu-karpenter
spec:
  template:
    metadata:
      labels:
        NodeGroupType: g5-gpu-karpenter
    spec:
      requirements:
        - key: node.kubernetes.io/instance-type
          operator: In
          values: ["g5.xlarge","g5.2xlarge","g5.4xlarge"]
        - key: karpenter.sh/capacity-type
          operator: In
          values: ["on-demand", "spot"]
      taints:
        - key: nvidia.com/gpu
          effect: NoSchedule
  limits:
    resources:
      nvidia.com/gpu: "8"
  disruption:
    consolidationPolicy: WhenEmpty
핵심 포인트
NodeGroupType 라벨
Pod nodeSelector로 GPU 전용 노드 타겟
GPU Taint
nvidia.com/gpu NoSchedule로 일반 Pod 방지
Spot + On-Demand 혼합
비용 절감 + 가용성 확보
limits.gpu: "8"
과다 프로비저닝 방지 상한
WhenEmpty Consolidation
빈 GPU 노드 즉시 종료

apiVersion: ray.io/v1
kind: RayService
metadata:
  name: vllm
  namespace: rayserve-vllm
spec:
  serveConfigV2: |
    applications:
      - name: mistral
        import_path: "vllm_serve:deployment"
        runtime_env:
          env_vars:
            MODEL_ID: "mistralai/Mistral-7B-Instruct-v0.2"
            GPU_MEMORY_UTILIZATION: "0.9"
            MAX_MODEL_LEN: "8192"
        deployments:
          - name: mistral-deployment
            autoscaling_config:
              min_replicas: 1
              max_replicas: 4
              target_num_ongoing_requests_per_replica: 20
            ray_actor_options:
              num_gpus: 1
  rayClusterConfig:
    workerGroupSpecs:
      - replicas: 1
        minReplicas: 1
        maxReplicas: 4
        template:
          spec:
            nodeSelector:
              NodeGroupType: g5-gpu-karpenter
            tolerations:
              - key: "nvidia.com/gpu"
                effect: "NoSchedule"

파라미터 기본값 권장 범위 설명 영향
GPU_MEMORY_UTILIZATION 0.9 0.85~0.95 vLLM 엔진 전체가 사용할 VRAM 비율 (가중치+KV Cache+Activation) 높을수록 동시처리↑, OOM↑
MAX_MODEL_LEN 8192 2048~32768 최대 입출력 시퀀스 길이 길수록 메모리↑, 유연성↑
TENSOR_PARALLEL_SIZE 1 1/2/4/8 모델을 분산할 GPU 수 GPU 수에 맞게 설정
MAX_NUM_SEQ 256 32~256 동시 처리 시퀀스 수 높을수록 처리량↑, 레이턴시↑
dtype auto bfloat16 추론 정밀도 bfloat16 권장 (H100+)
튜닝 시작점: GPU_MEMORY_UTILIZATION=0.9에서 시작 → OOM 발생 시 0.85로 낮춤
메모리 계산: 모델 크기(GB) ≈ 파라미터 수(B) × 2 (BF16 기준). 나머지가 KV Cache
Prefix Caching: 반복 프롬프트(RAG, 시스템 프롬프트)가 많으면 --enable-prefix-caching 추가

autoscaling_config:
  metrics_interval_s: 0.2
  min_replicas: 1
  max_replicas: 4
  look_back_period_s: 2
  downscale_delay_s: 600
  upscale_delay_s: 30
  target_num_ongoing_requests_per_replica: 20
스케일링 시나리오
요청 60개 유입 → target=20
필요 replicas = 60 ÷ 20 = 3
현재 1개 → 30초 후 3개로 확장
→ Karpenter가 g5 노드 2개 추가 (2~5분)
파라미터별 의미
target_num_ongoing_requests
레플리카당 목표 동시 요청 수. 낮으면 빠른 확장(비용↑), 높으면 느린 확장(레이턴시↑). 권장: 15~25
downscale_delay_s: 600
트래픽 감소 후 10분 기다렸다가 축소. GPU 노드 프로비저닝 비용 고려 (절대 값 낮추지 말 것)
upscale_delay_s: 30
트래픽 급증 시 30초 후 확장. 지나치게 낮으면 불안정한 스케일링 발생
metrics_interval_s: 0.2
200ms마다 메트릭 수집. 빠른 반응 + 안정적 판단을 위해 look_back_period_s: 2와 조합

Step 1
~20분
인프라 배포
terraform apply -var-file=blueprint.tfvars
EKS + Karpenter
+ 모니터링 + GPU 플러그인
Step 2
~2분
Helm Repo 추가
helm repo add ai-on-eks https://awslabs.github.io/ai-on-eks-charts/
KubeRay Operator
자동 포함
Step 3
~10분
모델 배포
helm install deepseek ai-on-eks/inference-charts --values values-deepseek-r1.yaml
이미지 Pull
+ 모델 로딩
Step 4
즉시
검증
kubectl get rayservice -n default && curl http://localhost:8000/v1/chat/completions
서비스 상태
+ API 테스트

모델 크기 권장 인스턴스 TP GPU MEM MAX LEN 특이사항
DeepSeek-R1-8B 8B g5.xlarge (1×A10G) 1 0.90 32768 CoT 추론, 긴 출력 필수
Llama-3.1-8B 8B g5.xlarge (1×A10G) 1 0.90 8192 기본 채팅, 범용
Llama-3.1-70B 70B p4d.24xlarge (8×A100) 8 0.90 8192 TP=8 필수, 고성능
Qwen3-7B 7B g5.xlarge (1×A10G) 1 0.90 32768 Thinking mode 지원
Mistral-7B 7B g5.xlarge (1×A10G) 1 0.90 8192 Function Calling 강점
DeepSeek-R1 671B 671B LWS: 2×p5.48xlarge 16 0.85 32768 멀티노드 필수
VRAM 공식: 모델 크기(GB) ≈ 파라미터(B) × 2 (BF16)  |  KV Cache = (GPU VRAM × GPU_MEM_UTIL) - 모델 크기  |  DeepSeek-R1 8B: 모델 15GB + KV Cache 5GB = 총 20GB (A10G 24GB에 딱 맞음)

⚙️
Helm Chart 배포
inference-charts로
3줄 배포 완성
📊
오토스케일링
target_requests=20
RayServe 내장
🎯
모델별 최적 설정
GPU_MEM × 크기별
TP/MAX_LEN 조정
← 목차로 돌아가기 다음: 운영 & 최적화 →

Part 4 — 운영 & 최적화

모니터링, 비용 최적화, 장애 대응, OpenAI 마이그레이션

TTFT
Time to First Token
vllm:time_to_first_token_seconds
첫 토큰 생성까지 시간. 사용자 체감 응답성 핵심 지표
목표: p50 < 2s
경고: p99 > 5s
TPOT / ITL
Inter-Token Latency
vllm:time_per_output_token_seconds
토큰 간 생성 간격. 스트리밍 품질 결정
목표: < 100ms
경고: > 200ms
Queue Time
대기 시간
vllm:request_queue_time_seconds
요청 대기 시간. 서버 과부하 지표
목표: p95 < 2s
급증 시 replica↑
Preemptions
KV Cache 부족
vllm:num_preemptions_total
KV Cache 부족으로 요청 중단. 발생 시 즉시 조치
목표: 0
발생 시 MEM↓/LEN↓

Karpenter Spot 인스턴스
g5 Spot: On-Demand 대비 60~70% 할인 | capacity-type: [on-demand, spot] 혼합 전략 | vLLM Stateless → Spot 중단 시 빠른 재시작 가능
Consolidation 정책
WhenEmpty: 빈 GPU 노드 즉시 제거 (기본 권장) | downscale_delay_s=600으로 불필요한 축소 방지 | 야간/주말 min_replicas=0 설정 고려
Right-sizing
g5.xlarge(7B) → g5.2xlarge(13B) → g5.12xlarge(34B) | 모델 크기에 딱 맞는 인스턴스 선택이 핵심 | 오버프로비저닝 = 비용 낭비 (GPU 활용률 모니터링)
Multi-LoRA 서빙
Base 모델 1개 + N개 LoRA Adapter 동시 서빙 | --enable-lora --max-loras 4 설정 | 3개 태스크 = GPU 1개 (기존 3개 필요) → 비용 66% 절감

비교 항목 OpenAI GPT-4o Claude 3.5 Sonnet vLLM Llama-3 70B vLLM Llama-3 8B
입력 토큰 (1M) $5.00 $3.00 ~$0.35 ~$0.07
출력 토큰 (1M) $15.00 $15.00 ~$0.35 ~$0.07
일 1억 토큰 ~$500/day ~$400/day ~$84/day ~$17/day
월 비용 ~$15,000 ~$12,000 ~$2,520 ~$510
월 절감액 (vs GPT-4o) $3,000 ~$12,480 ~$14,490
ROI 전제: g5.xlarge On-Demand $1.01/hr × 24hr = $24.24/day (Spot 적용 시 ~$7/day)
Break-even: 초기 구축 비용 $5,000 기준, Llama-3 8B 대비 약 10일
주의: 모델 품질 트레이드오프 필수 검토 | 운영 인건비(SRE) 포함 시 ROI 재계산

vLLM은 OpenAI 호환 API 제공 → base_url + api_key 2줄 변경만으로 전환 완료
BEFORE — OpenAI API
import openai
client = openai.OpenAI(
  api_key="sk-proj-xxxxxxxxx"
)
response = client.chat.completions.create(
  model="gpt-4o",
  messages=[{"role": "user", "content": "안녕"}],
  stream=True,
  temperature=0.7
)
# GPT-4o: $5/1M input + $15/1M output
# 일 1억 토큰 → ~$500/day
AFTER — Self-hosted vLLM
import openai
client = openai.OpenAI(
  api_key="EMPTY", # vLLM 인증 불필요
  base_url="http://vllm-svc:8000/v1"
)
response = client.chat.completions.create(
  model="Llama-3.1-8B-Instruct",
  messages=[{"role": "user", "content": "안녕"}],
  stream=True,
  temperature=0.7
)
# GPU 인스턴스 비용만 발생
# g5.xlarge: ~$1.01/hr (Spot: ~$0.30)
호환 API: /v1/chat/completions | /v1/completions | /v1/embeddings | /v1/models — Function Calling / Streaming / Logprobs 모두 지원

증상 원인 진단 해결
Pod OOMKilled GPU VRAM 초과 kubectl describe pod GPU_MEM_UTIL 0.9→0.85
MAX_LEN 축소
TTFT > 10초 요청 큐 과부하 vllm:request_queue_time max_replicas 증가
target_requests 낮춤
Preemptions 급증 MAX_MODEL_LEN 실제 사용 초과 vllm:num_preemptions MAX_LEN 실측에 맞춤
MAX_NUM_SEQ 줄임
GPU 노드 미생성 EC2 가용성 부족 kubectl get nodeclaim NodePool에 인스턴스 타입 추가
Multi-AZ 확장
ImagePullBackOff ECR 권한 없음 kubectl describe pod IRSA 역할 권한 확인
ECR 이미지 존재 확인
모델 로딩 실패 HF Token 없음 kubectl logs <pod> K8s Secret 확인
모델 ID 오타 확인
RayService Unhealthy Worker CrashLoop kubectl get rayservice ray status 확인
Head Pod logs 분석
빠른 진단: kubectl get events -n <ns> --sort-by=.lastTimestamp | tail -20

준비 단계
1
GPU 요구사항 분석
모델 크기, 동시 사용자 수, SLO (TTFT/TPOT 목표)
2
인스턴스 타입 선정
모델 크기 × 2 = VRAM 필요량, Spot 가용성 확인
3
EKS 클러스터 구축
terraform apply (inference-ready-cluster)
4
Karpenter NodePool 설정
GPU/CPU NodePool, Spot 혼합, limits 설정
5
NVIDIA Device Plugin 확인
GPU 리소스 광고, NFD/DCGM Exporter 설치
배포 & 운영 단계
6
Ray-vLLM 서비스 배포
inference-charts Helm Chart, values 설정
7
모니터링 스택 구성
ServiceMonitor + Grafana 대시보드 import
8
벤치마크 실행
Inference Perf: Baseline → Saturation 테스트
9
Alert 규칙 설정
TTFT, Queue Time, Preemptions, GPU Temp
10
프로덕션 트래픽 전환
Canary → Blue-Green, base_url 변경으로 전환

GitHub Repository
github.com/awslabs/ai-on-eks
전체 Terraform, 블루프린트, Helm Charts, 문서 포함 | Apache 2.0
Hands-on Workshop
genai.eksworkshop.com
EKS Auto Mode + AMP + Grafana + vLLM 실습 | 무료
Inference Charts (Helm)
github.com/awslabs/ai-on-eks-charts
DeepSeek, Llama, Qwen3, Mistral 프리셋 포함
Grafana Dashboard
vllm-dashboard.json (ai-on-eks 레포 포함)
8개 패널: TTFT, TPOT, Queue Time, Preemptions 등
Observability Reference
github.com/awslabs/ai-ml-observability-reference-architecture
Prometheus + Grafana + OpenSearch 전체 관측 스택 자동 배포

Q & A

감사합니다

github.com/awslabs/ai-on-eks | genai.eksworkshop.com