KubeRay·vLLM 쿠버네티스 서빙 실무: 오토스케일링과 프로덕션 인프라 운영 방법
KubeRay 오퍼레이터와 vLLM을 활용해 쿠버네티스 환경에서 대규모 LLM 추론 클러스터를 오토스케일링 아키텍처로 구현하는 매니페스트 설계, 메트릭 기반 확장 파이프라인, 운영 트러블슈팅 절차를 정리합니다. 베어메탈이나 일반 가상 머신(VM) 인프라 위에서 멀티 GPU 구성을 완료했더라도, 실제 대고객 서비스나 전사 시스템에 배포할 때는 트래픽 변동에 따른 유연한 자원 제어가 필수적입니다. 야간이나 주말처럼 사용량이 적은 시간대에도 고가의 GPU 노드를 고정적으로 켜두면 인프라 비용 소모가 커지고, 반대로 피크 타임에 요청이 몰리면 모델 로딩 지연과 큐 적체로 응답 품질이 흔들리기 때문인데요. 이전 리포트인 Ray와 vLLM 멀티노드 분산 추론 구축 가이드: TP·PP·NCCL 설정 실무가 가상 서버들을 묶어 자원 한계를 극복하는 클러스터링 공정이었다면, 이번 글에서는 클라우드 네이티브 환경인 쿠버네티스(Kubernetes)로 시스템을 이관하여 트래픽에 맞춰 GPU 워커 파드(Pod)를 자동으로 늘리고 줄이는 프로덕션 운영 체계를 구축하는 실무 방법을 다룹니다.
이 글에서 바로 확인할 수 있는 내용
- 가상 머신 단독 구성 대비 쿠버네티스 기반 KubeRay 서빙 환경이 지닌 운영·비용상 이점을 이해합니다.
- KubeRay 오퍼레이터의 RayCluster, RayService, 헤드 파드, 워커 파드 구조를 구분합니다.
- 프로덕션 배포 전 점검해야 할 RayCluster GPU 워커 풀 매니페스트 설계 기준을 확인합니다.
- vLLM의 대기 요청 수, KV 캐시 사용률, TTFT 지표를 활용한 오토스케일링 판단 원리를 정리합니다.
- HPA가 RayCluster를 직접 스케일링한다고 오해하지 않도록 Ray Autoscaler와 HPA의 역할을 분리합니다.
- 이미지 다운로드 지연, 모델 가중치 로딩, 스케일다운 세션 유실, NCCL 통신 오류에 대한 대응 절차를 확인합니다.
1. 왜 프로덕션 LLM 서빙에 KubeRay를 도입해야 할까?
가상 머신 단위로 분산 추론 환경을 직접 관리하면 트래픽 변화에 기민하게 대응하기 어렵습니다. 새로운 요청이 폭증할 때 가상 서버의 OS 부팅부터 GPU 드라이버 초기화, 모델 가중치 적재, vLLM 런타임 준비까지 여러 단계의 지연 시간이 발생하여 초기 사용자 이탈을 유발하기 쉬운데요. 반대로 트래픽이 급감하는 구간에서 유휴 GPU 자원을 수동으로 격리하지 못하면 막대한 인프라 유지비가 그대로 청구되는 악순환을 겪게 됩니다.
쿠버네티스 환경 위에서 Ray 클러스터를 자율 제어하는 KubeRay 오퍼레이터를 도입하면 이러한 스케일링 문제를 클라우드 네이티브 아키텍처 안에서 다룰 수 있습니다. KubeRay는 RayCluster 커스텀 리소스(CRD)를 기준으로 헤드 파드와 워커 파드의 생명주기를 관리하며, Ray 워크로드가 요구하는 자원 변화에 맞춰 워커 파드를 추가하거나 회수하는 구조를 제공합니다. 이때 중요한 점은 단순히 파드 수를 늘리는 것이 아니라, GPU 자원 요청량, 모델 병렬화 방식, 요청 대기열, KV 캐시 사용률, 네트워크 통신 안정성까지 함께 고려해야 한다는 점입니다.
즉, KubeRay를 도입하는 목적은 “GPU 파드를 무조건 자동으로 늘리기”가 아니라 “서비스가 감당 가능한 범위 안에서 자원을 예측 가능하게 늘리고, 유휴 시에는 안전하게 줄이는 운영 체계”를 만드는 데 있습니다. LLM 서빙은 일반 웹 서버보다 기동 비용이 크기 때문에 오토스케일링 정책을 잘못 잡으면 비용 절감보다 지연 증가가 먼저 나타날 수 있습니다. 따라서 실제 프로덕션 환경에서는 최소 워커 수, 모델 캐시 전략, 스케일다운 유예 시간, 장애 복구 정책을 함께 설계해야 안전합니다.
2. KubeRay 오퍼레이터 아키텍처와 자원 분할 원리
KubeRay 시스템은 쿠버네티스 제어 평면(Control Plane)에 상주하는 오퍼레이터가 RayCluster 또는 RayService 리소스를 감시하는 구조로 동작합니다. 사용자가 선언적 요구사항을 담은 매니페스트를 제출하면 오퍼레이터는 이를 해석하여 컨트롤러 역할을 수행할 헤드 파드와, 실제 연산을 처리할 워커 파드 세트를 프로비저닝합니다.
여기서 헤드 파드는 Ray 클러스터의 진입점과 스케줄링 두뇌 역할을 맡고, 워커 파드는 실제 추론 작업에 필요한 CPU, 메모리, GPU를 소비합니다. vLLM 기반 LLM 서빙을 Ray 위에서 운영할 경우, 요청을 처리하는 서빙 레이어는 Ray Serve 또는 별도 API 게이트웨이와 연결될 수 있으며, GPU 워커 풀은 Ray Autoscaler의 판단에 따라 확장됩니다. 따라서 쿠버네티스 HPA가 RayCluster를 직접 늘리고 줄인다고 이해하기보다는, HPA·KEDA·게이트웨이 메트릭은 외부 트래픽 압력을 감지하고, Ray Autoscaler는 Ray 작업 자원 수요에 따라 워커 수를 조정한다고 나누어 보는 편이 정확합니다.
이 구조에서 vLLM 엔진은 GPU 워커 자원 위에서 모델 추론을 수행하며, 요청이 몰릴 때는 대기열과 KV 캐시 사용률이 먼저 상승합니다. 이러한 인프라 조율 방식은 모델 배포 무결성 면에서 앞서 정리한 AX 시스템 관측성 구축 방법 리포트의 통합 제어 규칙과도 이어지는데요. 자원 모니터링 에이전트, Prometheus, Grafana, 로그 수집 레이어를 함께 붙여야 단순 파드 개수뿐 아니라 실제 서비스 품질까지 확인할 수 있습니다.
3. RayCluster, RayService, HPA의 역할을 먼저 구분해야 하는 이유
검색자가 가장 많이 헷갈리는 지점은 “Kubernetes HPA로 RayCluster를 바로 스케일링하면 되는가?”라는 질문입니다. 결론부터 정리하면, 일반적인 프로덕션 설계에서는 RayCluster 워커 수 조정은 KubeRay와 Ray Autoscaler 중심으로 두고, HPA는 API 게이트웨이, 라우터, 별도 vLLM 프론트엔드 Deployment처럼 Kubernetes 기본 스케일 대상이 명확한 리소스에 적용하는 편이 안전합니다.
| 구성 요소 | 주요 역할 | 실무 설계 포인트 |
|---|---|---|
| RayCluster | Ray 헤드 및 워커 파드 생명주기 관리 | 개발, 배치, 장기 실행 클러스터, GPU 워커 풀 구성에 적합 |
| RayService | RayCluster와 Ray Serve 배포 그래프를 함께 관리 | 모델 서빙, 무중단 전환, 고가용성 운영에 적합 |
| Ray Autoscaler | Ray 작업의 자원 요구량을 기반으로 워커 파드 증감 | GPU 워커 수량 조정의 중심 축으로 사용 |
| HPA 또는 KEDA | Kubernetes 워크로드를 메트릭 기준으로 확장 | API 게이트웨이, 라우터, 별도 Deployment 확장에 활용 |
이 구분이 중요한 이유는 LLM 서빙의 병목이 CPU 사용률 하나로 설명되지 않기 때문입니다. GPU 메모리는 모델 가중치 때문에 높은 수준으로 고정될 수 있고, GPU utilization은 배치 상태에 따라 순간적으로 출렁일 수 있습니다. 따라서 오토스케일링의 직접 기준은 CPU보다는 vLLM 요청 대기열, 요청 큐 시간, TTFT(Time To First Token), KV 캐시 사용률을 중심으로 잡는 편이 더 자연스럽습니다.
4. 프로덕션 KubeRay 및 vLLM 배포 전제 조건
KubeRay와 vLLM을 쿠버네티스에 배포하기 전에 가장 먼저 확인해야 할 것은 버전 숫자 자체보다 구성 요소의 호환성입니다. Kubernetes 버전, NVIDIA 드라이버, NVIDIA Container Toolkit, GPU Operator, CUDA 런타임, Ray 버전, KubeRay Operator 버전, vLLM 컨테이너 이미지가 서로 맞지 않으면 YAML이 정상이어도 파드가 기동되지 않거나 NCCL 통신 오류가 발생할 수 있습니다.
운영 전 확인해야 할 최소 환경
- Kubernetes 클러스터에 GPU 노드가 정상 등록되어 있어야 합니다.
kubectl describe node결과에서nvidia.com/gpu리소스가 보이는지 확인해야 합니다.- KubeRay Operator가 별도 네임스페이스에 정상 실행 중이어야 합니다.
- vLLM 이미지에는 사용할 CUDA, NCCL, Ray, Python 의존성이 포함되어 있어야 합니다.
- 모델 가중치 접근을 위한 Hugging Face 토큰 또는 사내 모델 저장소 접근 권한이 Secret으로 분리되어야 합니다.
- Prometheus가 vLLM
/metrics엔드포인트를 스크레이프할 수 있어야 합니다.
특히 프로덕션 환경에서는 latest 태그를 그대로 쓰기보다, 사내 레지스트리에 검증된 고정 태그 이미지를 올려 사용하는 편이 안전합니다. 같은 latest라도 배포 시점에 따라 내부 라이브러리 버전이 달라질 수 있고, 이 차이가 모델 로딩 방식이나 메트릭 명칭, CUDA 동작에 영향을 줄 수 있기 때문입니다.
5. RayCluster GPU 워커 풀 매니페스트 설계 예시
아래 매니페스트는 KubeRay 오퍼레이터가 설치되어 있고, GPU 노드가 쿠버네티스 클러스터에 정상 등록되어 있다는 전제에서 작성한 RayCluster 기본 골격입니다. 실제 vLLM 서빙 애플리케이션은 RayService, Ray Job, 또는 별도 배포 파이프라인을 통해 붙이는 것이 일반적이며, 이 예시는 “GPU 워커 풀을 안전하게 준비하는 기본 RayCluster 구조”에 초점을 맞춥니다.
apiVersion: ray.io/v1
kind: RayCluster
metadata:
name: vllm-serving-cluster
namespace: llm-serving
spec:
rayVersion: "2.x"
enableInTreeAutoscaling: true
autoscalerOptions:
upscalingMode: Default
idleTimeoutSeconds: 300
imagePullPolicy: IfNotPresent
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "512Mi"
headGroupSpec:
rayStartParams:
dashboard-host: "0.0.0.0"
num-cpus: "0"
template:
spec:
containers:
- name: ray-head
image: registry.example.com/llm/vllm-ray:0.x-ray2.x
imagePullPolicy: IfNotPresent
ports:
- containerPort: 6379
name: gcs
- containerPort: 8265
name: dashboard
- containerPort: 10001
name: client
resources:
requests:
cpu: "4"
memory: "16Gi"
limits:
cpu: "4"
memory: "16Gi"
workerGroupSpecs:
- groupName: gpu-workers
replicas: 0
minReplicas: 0
maxReplicas: 4
rayStartParams: {}
template:
spec:
nodeSelector:
accelerator: nvidia-gpu
tolerations:
- key: "nvidia.com/gpu"
operator: "Exists"
effect: "NoSchedule"
containers:
- name: ray-worker
image: registry.example.com/llm/vllm-ray:0.x-ray2.x
imagePullPolicy: IfNotPresent
env:
- name: HUGGING_FACE_HUB_TOKEN
valueFrom:
secretKeyRef:
name: hf-secret
key: token
- name: NCCL_DEBUG
value: "WARN"
- name: PYTHONUNBUFFERED
value: "1"
resources:
requests:
cpu: "8"
memory: "64Gi"
nvidia.com/gpu: "1"
limits:
cpu: "8"
memory: "64Gi"
nvidia.com/gpu: "1"
이 예시에서 CPU와 메모리의 requests와 limits를 일치시킨 이유는 GPU 워커 파드가 자원 부족 상황에서 쉽게 밀려나지 않도록 안정성을 높이기 위해서입니다. Kubernetes의 QoS 분류상 Guaranteed Class를 의도한다면 컨테이너의 CPU와 메모리 요청량 및 제한량을 동일하게 맞추는 것이 중요합니다. GPU 리소스도 nvidia.com/gpu 키를 정확히 사용해야 하며, 마크다운 링크 형태로 작성하면 YAML 문법이 깨지므로 절대 넣으면 안 됩니다.
다만 모든 워커 파드를 Guaranteed Class로 고정하는 것이 항상 정답은 아닙니다. GPU 노드가 제한적이고 여러 팀이 같은 클러스터를 공유한다면 Guaranteed 파드는 안정적이지만 스케줄링 여유가 줄어들 수 있습니다. 따라서 상용 API를 처리하는 최소 리플리카는 보수적으로 잡고, 실험성 워크로드는 별도 네임스페이스와 ResourceQuota로 분리하는 방식이 안전합니다.
6. vLLM 서빙 레이어는 어디에 붙이는 것이 좋을까?
vLLM을 KubeRay 위에서 운영할 때는 “RayCluster만 만들면 바로 API 서버가 열린다”고 생각하면 안 됩니다. RayCluster는 Ray 런타임 인프라를 준비하는 리소스이고, 실제 모델 엔드포인트는 별도 애플리케이션 레이어에서 실행되어야 합니다. 운영 방식은 크게 세 가지로 나눌 수 있습니다.
| 방식 | 적합한 상황 | 주의할 점 |
|---|---|---|
| RayService | Ray Serve 기반 모델 API를 안정적으로 운영할 때 | Serve 배포 그래프와 모델 로딩 절차를 별도로 관리해야 함 |
| Ray Job | 배치 추론 또는 일회성 작업을 실행할 때 | 상시 API 서비스에는 별도 수명주기 설계가 필요함 |
| 별도 API 게이트웨이 + Ray 백엔드 | 인증, 라우팅, 과금, 부서별 격리를 앞단에서 처리할 때 | 게이트웨이와 Ray 워커 확장 정책을 분리해 설계해야 함 |
실무적으로는 외부 사용자 요청을 바로 Ray 헤드 파드에 붙이는 구조보다, 앞단에 API 게이트웨이 또는 Ingress Controller를 두고 인증, 요청 크기 제한, rate limit, timeout, 로깅 정책을 먼저 처리하는 방식이 안전합니다. LLM 요청은 일반 API보다 입력 프롬프트 길이와 출력 토큰 수에 따라 자원 사용량 차이가 매우 크기 때문입니다.
7. 메트릭 기반 GPU 파드 오토스케일링 파이프라인 구성 원리
쿠버네티스 환경에서 대형 언어 모델 서빙의 오토스케일링은 일반적인 웹 서버처럼 단순 CPU나 메모리 가동률만 기준으로 삼으면 안 됩니다. LLM 추론은 모델 가중치가 메모리에 올라간 상태로 유지되고, 배치 구성에 따라 GPU 사용률이 순간적으로 요동칠 수 있기 때문인데요. 따라서 실제 부하 변동을 추적하려면 vLLM 엔진이 노출하는 Prometheus 메트릭을 함께 관측해야 합니다.
운영자가 우선적으로 확인해야 할 지표는 다음과 같습니다.
| 메트릭 | 의미 | 운영 판단 |
|---|---|---|
vllm:num_requests_waiting |
처리 대기 중인 요청 수 | 지속적으로 증가하면 워커 확장 또는 요청 제한 필요 |
vllm:num_requests_running |
현재 실행 배치 안에서 처리 중인 요청 수 | running은 높고 waiting이 낮으면 현재 용량 안에서 처리 중인 상태 |
vllm:kv_cache_usage_perc |
KV 캐시 사용률, 1이면 100%에 가까운 상태 | 높은 상태가 지속되면 max_model_len, 동시성, GPU 메모리 재검토 |
vllm:time_to_first_token_seconds |
요청 후 첫 토큰이 나오기까지 걸린 시간 | 사용자 체감 지연을 판단하는 핵심 지표 |
vllm:request_queue_time_seconds |
요청이 대기열에서 머문 시간 | 스케일아웃 임계값과 게이트웨이 제한 기준으로 활용 |
메트릭을 Kubernetes 오토스케일링에 연결할 때는 Prometheus Adapter 또는 KEDA를 통해 외부 메트릭 형태로 변환해야 합니다. 다만 이 메트릭을 RayCluster에 직접 붙여 확장한다고 단정해서는 안 됩니다. 더 안전한 방식은 API 게이트웨이, 라우터, 프론트엔드 Deployment의 확장 기준으로 사용하거나, Ray 작업 제출량과 리소스 요구량을 조절하는 신호로 활용하는 것입니다.
# 개념 예시: vLLM 대기 요청 수를 API 게이트웨이 HPA 판단 지표로 사용하는 구조
# 실제 metric.name은 Prometheus Adapter rules 설정 후 노출되는 이름을 확인해야 합니다.
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: vllm-gateway-hpa
namespace: llm-serving
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: vllm-gateway
minReplicas: 2
maxReplicas: 10
behavior:
scaleDown:
stabilizationWindowSeconds: 600
policies:
- type: Percent
value: 25
periodSeconds: 60
metrics:
- type: External
external:
metric:
name: vllm_num_requests_waiting
target:
type: AverageValue
averageValue: "5"
위 예시는 RayCluster 자체를 HPA 대상으로 삼는 구성이 아니라, 외부 요청을 받는 게이트웨이 워크로드의 수평 확장 예시입니다. 실제 GPU 워커 파드는 Ray Autoscaler가 Ray 작업의 자원 요구량을 기준으로 늘리고 줄이는 구조가 더 자연스럽습니다. 이렇게 역할을 분리하면 API 요청 급증에 대응하는 프론트엔드 확장과, GPU 연산 자원 확장을 서로 다른 안정화 시간으로 제어할 수 있습니다.
8. 벤치마크 환경 명세와 오토스케일링 검증 방법
상위 환경에 바로 반영하기 전에, 스테이징 네임스페이스에서 부하 테스트를 먼저 수행해야 합니다. 이때 “처리량이 몇 tokens/sec 나왔다”는 결과값만 기록하면 운영 판단에 큰 도움이 되지 않습니다. 모델 크기, 양자화 여부, tensor parallel 크기, 입력 토큰 수, 출력 토큰 수, 동시성 증가 패턴, GPU 모델, 네트워크 구조를 함께 기록해야 동일 조건에서 재현 가능한 판단이 가능합니다.
검증 환경 기록 예시: Kubernetes v1.x / KubeRay Operator v1.x / Ray 2.x / vLLM 0.x 또는 1.x / NVIDIA A100 80GB 또는 L40S / 테스트 모델명 / tensor_parallel_size / max_model_len / 평균 입력 토큰 수 / 평균 출력 토큰 수 / 동시 요청 수 증가 방식
아래 표는 특정 수치를 실제 성능이라고 단정하기 위한 표가 아니라, 운영자가 스테이징에서 반드시 비교해야 할 검증 항목을 정리한 것입니다. 프로덕션 글에서는 과장된 성능 수치보다, 어떤 기준으로 측정하고 어떤 조건에서 병목을 판단할지 제시하는 편이 검색자에게 더 유용합니다.
| 검증 항목 | 고정형 VM 클러스터에서 확인할 내용 | KubeRay 오토스케일링 환경에서 확인할 내용 | 판단 기준 |
|---|---|---|---|
| 첫 토큰 지연 시간 | 피크 유입 시 TTFT가 급격히 증가하는지 확인 | 워커 확장 전후 TTFT 회복 시간을 비교 | 사용자 체감 지연이 허용 범위 안에 있는지 확인 |
| 요청 대기열 | 대기 요청 수가 계속 누적되는지 확인 | 스케일아웃 후 대기열이 줄어드는 시점을 기록 | 확장 임계값이 너무 늦거나 빠르지 않은지 판단 |
| 모델 로딩 시간 | 서버 재시작 시 모델 가중치 적재 시간을 측정 | 신규 워커 파드 Ready까지 걸린 시간을 측정 | 이미지 캐싱과 모델 스토리지 분리 필요성 판단 |
| 유휴 시간대 비용 | 사용량이 낮아도 GPU 인스턴스가 계속 유지되는지 확인 | 최소 워커 수까지 안정적으로 줄어드는지 확인 | 비용 절감 효과와 콜드스타트 리스크를 함께 판단 |
9. 프로덕션 환경에서 자주 발생하는 장애 패턴과 트러블슈팅
문제 1: 스케일아웃 시 이미지 다운로드와 모델 가중치 로딩이 너무 오래 걸리는 경우
새로운 GPU 워커 파드가 생성될 때 컨테이너 이미지와 대형 모델 가중치를 매번 외부 저장소에서 받아오면, 트래픽 피크가 이미 지나간 뒤에야 파드가 Ready 상태가 되는 문제가 생길 수 있습니다. 특히 Llama 계열 대형 모델이나 멀티 GPU 병렬 구성이 필요한 모델은 가중치 로딩 시간이 전체 스케일아웃 시간의 대부분을 차지할 수 있습니다.
이를 줄이려면 컨테이너 이미지는 노드에 미리 풀링되도록 DaemonSet이나 이미지 캐시 정책을 검토하고, 모델 가중치는 컨테이너 이미지 안에 무리하게 넣기보다 고속 스토리지, 사내 모델 레지스트리, 로컬 NVMe 캐시, ReadOnlyMany 볼륨 등으로 분리하는 방식이 안정적입니다. 다만 공유 스토리지를 사용할 경우 모든 워커가 동시에 모델을 읽을 때 I/O 병목이 생길 수 있으므로, 스케일아웃 부하 테스트에서 모델 로딩 시간을 반드시 따로 기록해야 합니다.
문제 2: 스케일다운 시 진행 중인 추론 세션이 끊기는 경우
트래픽이 줄어 HPA나 Ray Autoscaler가 워커를 회수할 때, 해당 파드에서 긴 답변을 생성 중인 요청이 있으면 연결이 끊길 수 있습니다. LLM 응답은 짧은 REST API와 달리 스트리밍 방식으로 수십 초 이상 이어질 수 있으므로, 일반적인 파드 종료 정책만으로는 충분하지 않을 때가 많습니다.
기본적으로는 terminationGracePeriodSeconds와 preStop 훅을 설정하여 파드가 즉시 종료되지 않도록 유예 시간을 확보합니다. 다만 sleep 30만 넣는 방식은 단순 지연일 뿐 완전한 드레이닝 로직은 아닙니다. 실제 운영에서는 게이트웨이에서 해당 파드로 신규 요청을 보내지 않도록 먼저 제외하고, 진행 중인 요청이 끝난 뒤 종료되도록 애플리케이션 레벨의 graceful shutdown을 함께 설계해야 안전합니다.
# 파드 템플릿 내 종료 유예 설정 예시
# 실제 운영에서는 신규 요청 차단, readiness 전환, 진행 요청 완료 확인 로직을 함께 구성해야 합니다.
terminationGracePeriodSeconds: 120
containers:
- name: ray-worker
lifecycle:
preStop:
exec:
command: ["/bin/sh", "-c", "sleep 30"]
문제 3: GPU 노드가 있는데도 워커 파드가 Pending 상태에 머무르는 경우
GPU 노드가 존재하는데도 워커 파드가 Pending에 머문다면 가장 먼저 kubectl describe pod 결과에서 스케줄링 실패 사유를 확인해야 합니다. 자주 보이는 원인은 GPU 리소스 부족, nodeSelector 불일치, taint/toleration 누락, 네임스페이스 ResourceQuota 제한, CPU·메모리 requests 과다 설정입니다.
kubectl describe pod -n llm-serving <ray-worker-pod-name>
kubectl describe node <gpu-node-name>
kubectl get resourcequota -n llm-serving
kubectl get events -n llm-serving --sort-by=.lastTimestamp
이 단계에서 Insufficient nvidia.com/gpu 메시지가 보이면 실제 가용 GPU가 부족한 상태입니다. 반면 taint 관련 메시지가 보이면 GPU 노드에 걸린 taint를 워커 파드 toleration이 허용하지 못하는 상태입니다. 비용 절감을 위해 스팟 인스턴스 노드를 섞어 쓰는 경우에도, 최소 운영 워커는 온디맨드 노드에 배치하고 확장 여유분만 스팟 풀로 보내는 식의 분리가 필요합니다.
문제 4: NCCL 통신 오류 또는 멀티 GPU 초기화 실패가 발생하는 경우
vLLM을 Ray와 함께 멀티 GPU 또는 멀티 노드로 운영할 때 NCCL 통신 오류가 발생하면 단순 애플리케이션 오류가 아니라 네트워크, 드라이버, CUDA, 컨테이너 권한, 인터페이스 선택 문제가 얽혀 있을 수 있습니다. 같은 노드 안의 1 GPU 테스트는 통과했는데 멀티 노드에서만 실패한다면, 노드 간 통신 인터페이스와 보안 그룹, CNI 정책, NCCL 환경 변수를 먼저 확인해야 합니다.
env:
- name: NCCL_DEBUG
value: "WARN"
- name: NCCL_SOCKET_IFNAME
value: "eth0"
- name: NCCL_IB_DISABLE
value: "0"
위 값은 환경에 따라 달라질 수 있습니다. InfiniBand나 EFA를 사용하는 클러스터와 일반 VPC 네트워크를 사용하는 클러스터는 권장 값이 다를 수 있으므로, 사내 네트워크 구조에 맞게 조정해야 합니다. 중요한 것은 NCCL 오류를 vLLM 코드 문제로만 단정하지 않고, GPU 드라이버·노드 네트워크·컨테이너 런타임·Ray worker placement를 함께 점검하는 것입니다.
10. 프로덕션 클러스터 배포 전 실무 체크리스트
- ✅ GPU 노드에서
nvidia.com/gpu리소스가 정상 노출되는지 확인했나요? - ✅ RayCluster의 헤드 파드와 워커 파드 역할을 구분하고, 헤드 파드에 불필요한 GPU를 할당하지 않았나요?
- ✅ 프로덕션 이미지에
latest태그 대신 검증된 고정 태그를 사용했나요? - ✅ 모델 가중치 로딩 시간을 줄이기 위해 이미지 캐시, 모델 캐시, 공유 스토리지 전략을 검토했나요?
- ✅
vllm:num_requests_waiting,vllm:kv_cache_usage_perc,vllm:time_to_first_token_seconds지표를 대시보드에서 볼 수 있나요? - ✅ HPA를 RayCluster에 직접 붙이는 대신, Ray Autoscaler와 게이트웨이 확장 정책을 분리했나요?
- ✅ 스케일다운 시 진행 중인 스트리밍 응답이 끊기지 않도록 종료 유예와 드레이닝 정책을 설계했나요?
- ✅ 네임스페이스별 ResourceQuota와 LimitRange를 설정하여 부서별 GPU 자원 충돌을 방지했나요?
- ✅ 외부 요청 경로에는 인증, rate limit, 요청 크기 제한, timeout, 로깅 정책이 적용되어 있나요?
11. 검색자가 자주 궁금해하는 KubeRay·vLLM 실무 Q&A
Q. KubeRay만 설치하면 vLLM API 서버가 자동으로 열리나요?
A. 아닙니다. KubeRay는 Ray 클러스터의 생명주기를 관리하는 오퍼레이터이고, vLLM 모델 API 서버는 별도 애플리케이션 레이어에서 실행해야 합니다. RayService를 사용해 Ray Serve 배포 그래프를 관리하거나, 별도 API 게이트웨이를 두고 Ray 백엔드와 연결하는 방식으로 구성할 수 있습니다. 따라서 운영 설계에서는 “클러스터 인프라”와 “모델 서빙 엔드포인트”를 분리해서 보는 것이 안전합니다.
Q. GPU 워커 파드를 0개까지 줄이는 scale-to-zero 구성이 가능할까요?
A. 워커 그룹 기준으로는 최소 리플리카를 0에 가깝게 낮추는 설계를 검토할 수 있지만, 상용 API에서는 콜드스타트 비용을 반드시 계산해야 합니다. 대형 모델은 새 워커가 뜬 뒤 이미지 풀링, 모델 다운로드, 가중치 적재, CUDA 초기화까지 시간이 걸립니다. 즉, 비용만 보면 scale-to-zero가 매력적이지만, 사용자 요청이 갑자기 들어오는 서비스라면 최소 1개 이상의 warm worker를 유지하는 편이 더 안정적일 수 있습니다.
Q. CPU 사용률 기반 HPA로 LLM 서빙을 확장하면 왜 위험한가요?
A. LLM 추론 병목은 CPU보다 GPU 메모리, KV 캐시, 요청 큐, 모델 로딩, 토큰 생성 속도에서 발생하는 경우가 많습니다. CPU 사용률이 낮아 보여도 GPU 쪽은 이미 포화 상태일 수 있고, 반대로 CPU가 순간적으로 높아도 실제 사용자가 느끼는 지연은 크지 않을 수 있습니다. 그래서 vLLM의 대기 요청 수, 큐 시간, TTFT, KV 캐시 사용률을 함께 봐야 합니다.
Q. 스팟 인스턴스 노드를 GPU 워커 풀로 쓰면 비용을 크게 줄일 수 있나요?
A. 비용 절감 효과는 기대할 수 있지만, 상용 서비스의 기본 워커를 모두 스팟 인스턴스로 두는 것은 위험합니다. 스팟 인스턴스는 회수될 수 있고, 대형 LLM 워커는 대체 파드가 Ready가 되기까지 시간이 오래 걸릴 수 있습니다. 실무적으로는 최소 운영 리플리카를 온디맨드 노드에 두고, 버스트 트래픽 대응용 확장 여유분에만 스팟 노드를 혼용하는 방식이 더 안전합니다.
Q. 부서별로 KubeRay 클러스터를 나누는 것이 비효율적인가요?
A. 단순 자원 활용률만 보면 하나의 공용 클러스터가 효율적으로 보일 수 있지만, 엔터프라이즈 환경에서는 네임스페이스와 ResourceQuota를 기준으로 분리하는 편이 운영 안정성에 유리합니다. 특정 부서의 버스트 트래픽이 전체 GPU 풀을 잠식하면 다른 서비스까지 영향을 받을 수 있기 때문입니다. 비용 정산, 보안 격리, 장애 영향 범위 축소가 중요하다면 부서별 네임스페이스 분리와 GPU 쿼터 설정이 현실적인 운영 방식입니다.
참고한 기술 자료
- Ray on Kubernetes 공식 문서
- KubeRay 오퍼레이터 클라우드 네이티브 분산 아키텍처 공식 명세 가이드 문서
- vLLM 프로덕션 메트릭 공식 문서
- vLLM 프로덕션 메트릭 및 Prometheus 노출 공식 문서
- Kubernetes HPA 시스템 선언적 매니페스트 구성 규칙 표준 매뉴얼
결론: 통제된 자율 스케일링 구조가 프로덕션 AI 인프라의 지속 가능성을 보장합니다
엔터프라이즈 AI 서비스를 대규모 실시간 사용자망에 안착시키는 마지막 단계는 단순한 가속 기술의 구현을 넘어, 변화하는 트래픽 곡선 아래서 자원 비용 유출을 줄이고 응답 안정성을 유지하는 인프라 통제력 확보에 있습니다. 고정된 하드웨어 규모에 모델 서빙 환경을 맞추는 단선적 관리 방식에서 벗어나, vLLM의 대기열·KV 캐시·TTFT 메트릭을 관측하고 KubeRay의 RayCluster 및 RayService 운영 구조와 연결하는 클라우드 네이티브 튜닝이 핵심입니다.
다만 오토스케일링을 단순히 “파드를 자동으로 늘리는 기능”으로만 이해하면 실패하기 쉽습니다. Ray 워커 확장은 Ray Autoscaler가 담당하고, 외부 요청 압력은 게이트웨이·Prometheus·HPA 또는 KEDA 레이어에서 관리하며, 모델 로딩 시간과 스케일다운 유예 정책은 별도 운영 기준으로 통제해야 합니다. 이 세 가지 축이 함께 맞물릴 때, 비로소 유휴 시간대의 예산 낭비를 줄이면서도 트래픽 폭증 속에서 쉽게 무너지지 않는 LLM 서빙 시스템을 구성할 수 있습니다.
작성자 메모: 이 리포트는 2026년 6월 기준 Ray, KubeRay, vLLM, Kubernetes 공식 문서에서 확인 가능한 구조를 바탕으로 정리한 실무형 설계 가이드입니다. 실제 매니페스트 인자, vLLM 메트릭 명칭, Prometheus Adapter 변환 이름, GPU 드라이버 및 NCCL 설정값은 조직의 Kubernetes 배포판, CNI, 클라우드 노드 타입, vLLM 이미지 빌드 버전에 따라 달라질 수 있습니다. 프로덕션망 반영 전에는 반드시 스테이징 네임스페이스에서 모델 로딩 시간, TTFT, 요청 대기열, 스케일아웃 완료 시간, 스케일다운 종료 유예 동작을 먼저 검증해 주시기 바랍니다.
⚙️ 클라우드 자율 확장을 넘어 딥하드웨어 연산 가속 단계로
KubeRay 오퍼레이터를 활용해 쿠버네티스 환경에서 파드 단위의 자율 오토스케일링 체계를 안착시켰다면, 이제는 개별 연산 노드의 물리적 처리량을 극한으로 쥐어짜낼 차례입니다. 다음 리포트 TensorRT-LLM 가속 최적화 실무: 엔진 컴파일과 고처리량 프로덕션 서빙 구축 방법에서 언어 모델의 신경망 레이어 자체를 하드웨어 전용 정적 실행 파일로 빌드하고 인플라이트 배칭 스케줄러를 활성화하는 딥 컴파일 가속 솔루션을 확인해 보세요.
디지털 아키텍트 (Digital Architect)
댓글
댓글 쓰기