개요
이 문서는 솔루션 참조 구현 (SRI) 가이드로, Distributed Cloud 소프트웨어 전용의 오픈 모델 서빙 솔루션을 배포, 서빙, 검증하는 데 필요한 구체적인 단계를 설명합니다.
이 가이드에서는 실제 NVIDIA GPU 리소스 (예: RTX PRO 6000)를 활용하여 Distributed Cloud 소프트웨어 전용 에지 배포용 단일 노드 클러스터 구성에서 Gemma 4 (google/gemma-4-31B-it)를 실행하는 최적화된 vLLM 서빙 엔진의 배포를 구현합니다.
이 둘러보기는 Distributed Cloud 소프트웨어 전용 클러스터에 대한 kubectl 액세스 권한이 있는 CLI 터미널 클라이언트에서 실행하도록 설계되었습니다.
목표
이 솔루션 참조 구현을 완료하면 다음을 수행할 수 있습니다.
- 로컬
.env파일을 통해 서빙 환경 매개변수를 구성합니다. local-shared스토리지 클래스를 사용하여 모델 가중치를 유지하는 영구 볼륨 클레임 (PVC)을 배포합니다.- Vertex AI 인증 컨테이너를 활용하여 최적화된 vLLM 서빙 엔진을 배포하고 실제
nvidia.com/gpu리소스를 매핑합니다. - Gradio 웹 UI를 배포하여 대화형 채팅 인터페이스를 제공합니다.
- API 및 웹 UI를 통해 서비스 응답성을 검증하기 위해 로컬 포트 전달 터널을 설정합니다.
- Cloud Logging 및 Cloud Monitoring에 로그 및 측정항목(GPU 텔레메트리 포함)이 수집되는지 확인하여 관측 가능성 통합을 확인합니다.
시작하기 전에
기본 요건 (클러스터 설정)
이 가이드에서는 GPU 지원이 구성된 Distributed Cloud 소프트웨어 전용 클러스터가 실행 중이라고 가정합니다. 클러스터 설치는 공식 베어메탈용 Distributed Cloud 소프트웨어 전용 문서를 참고하세요. GPU 구성은 NVIDIA GPU 설정 및 사용에 관한 공식 Google Cloud 문서를 준수해야 합니다.
클라이언트 워크스테이션 기본 요건
로컬 터미널 환경에 다음 도구가 설치되고 구성되어 있는지 확인합니다.
- gcloud CLI: 프로젝트 구성 및 로그 쿼리에 필요합니다.
인증 (
gcloud auth login)을 받아야 하며 Distributed Cloud 소프트웨어 전용 클러스터가 등록된 활성Google Cloud 프로젝트로 구성되어야 합니다. - kubectl: 클러스터 리소스 관리에 필요합니다. 타겟 Distributed Cloud 소프트웨어 전용 클러스터에 액세스할 수 있는 적절한 컨텍스트로 구성해야 합니다 (예: 연결 게이트웨이 또는 직접 로컬 네트워크 액세스를 통해).
- curl: 서빙 엔드포인트에 테스트 요청을 보내는 데 필요합니다.
- jq: 서빙 엔드포인트에서 JSON 출력을 파싱하는 데 필요합니다.
Hugging Face 모델 액세스
Gemma 4 모델을 다운로드하고 배포하려면 Hugging Face 저장소에 액세스할 수 있어야 합니다.
- Hugging Face 계정: Hugging Face에 등록된 계정이 있는지 확인합니다.
- 모델 라이선스 수락: Gemma 4 31B IT 모델 페이지로 이동하여 라이선스 조건에 동의하면 게이트된 모델 가중치에 액세스할 수 있습니다.
- 액세스 토큰 생성: Hugging Face 계정 설정(설정 -> 액세스 토큰)에서 읽기 권한이 있는 사용자 액세스 토큰을 생성합니다. 이 토큰은 구성에서
HF_TOKEN로 사용됩니다.
중앙 참조 구성
모든 배포 매개변수는 <local-config-dir>/.env에 있는 중앙 .env 파일을 통해 관리됩니다. 이 파일이 존재하고 특정 매개변수 (Hugging Face 토큰, 네임스페이스, 모델 이름 등)가 포함되어 있는지 확인합니다.
.env 구조 예시:
# GDCso Cluster Namespace
NAMESPACE_NAME="your-custom-namespace"
# Hugging Face Token (Required to download gated Gemma models)
HF_TOKEN="your-hf-token-here"
# Model Sizing Parameters
MODEL_NAME="google/gemma-4-31B-it"
SAFE_MODEL_NAME="google-gemma-4-31B-it"
# Hyperparameters
MAX_MODEL_LEN=8192
GPU_MEMORY_UTILIZATION=0.95
MAX_NUM_SEQS=512
MAX_NUM_BATCHED_TOKENS=4096
DTYPE="bfloat16"
# Pod Sizing Requests
CPU_REQUEST="4"
MEMORY_REQUEST="80"
환경 및 사용자 인증 정보 설정
네임스페이스 및 Hugging Face 보안 비밀 만들기
배포하기 전에 네임스페이스와 Hugging Face 토큰 시크릿을 만들어야 합니다.
# Navigate to your project root
cd <local-working-dir>
# Sourced from your local .env file
source <local-config-dir>/.env
# Create namespace
kubectl create namespace ${NAMESPACE_NAME} --dry-run=client -o yaml | kubectl apply -f -
# Create Hugging Face token secret
kubectl create secret generic hf-token-secret \
--from-literal=token="${HF_TOKEN}" \
-n "${NAMESPACE_NAME}" --dry-run=client -o yaml | kubectl apply -f -
Kubernetes의 vLLM 배포
배포는 PVC, 서비스, 배포의 세 가지 기본 매니페스트로 구성됩니다. 이러한 템플릿은 배포 시 대체되는 환경 변수를 사용합니다.
영구 볼륨 클레임 (PVC)
PVC는 Distributed Cloud 소프트웨어의 local-shared 스토리지 클래스만 사용하여 포드 재시작 시 모델 가중치가 유지되도록 합니다.
다음 콘텐츠로 vllm-pvc.yaml이라는 파일을 만듭니다.
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-cache-pvc
namespace: ${NAMESPACE_NAME}
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-shared
resources:
requests:
storage: 100Gi
서비스
포트 8000에서 vLLM API 서버를 내부적으로 노출합니다.
다음 콘텐츠로 vllm-service.yaml이라는 파일을 만듭니다.
apiVersion: v1
kind: Service
metadata:
name: vllm-service
namespace: ${NAMESPACE_NAME}
labels:
app: vllm
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/metrics"
prometheus.io/port: "8000"
spec:
ports:
- name: http
port: 8000
targetPort: 8000
selector:
app: vllm
type: ClusterIP
배포
vLLM 컨테이너를 실행하고, 모델 캐시 볼륨을 마운트하고, 물리적 GPU 리소스를 요청합니다. 96GB의 VRAM은 양자화되지 않은 BF16 가중치 (~62GB)에 적합하지만 이 참조 구현에서는 Blackwell FP8 양자화(--quantization=fp8, ~31GB 가중치)를 사용하여 KV 캐시를 56.53GiB(61,728 토큰)로 확장하여 동시 처리량을 높입니다.
다음 콘텐츠로 vllm-deployment.yaml이라는 파일을 만듭니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-deployment
namespace: ${NAMESPACE_NAME}
labels:
app: vllm
ai.gke.io/inference-server: vllm
ai.gke.io/model: ${SAFE_MODEL_NAME}
spec:
replicas: 1
strategy:
type: Recreate
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
examples.ai.gke.io/source: user-guide
ai.gke.io/inference-server: vllm
ai.gke.io/model: ${SAFE_MODEL_NAME}
spec:
runtimeClassName: nvidia
containers:
- name: vllm-container
image: us-docker.pkg.dev/vertex-ai/vertex-vision-model-garden-dockers/pytorch-vllm-serve:gemma4
imagePullPolicy: IfNotPresent
command: ["python3", "-m", "vllm.entrypoints.openai.api_server"]
args:
- --model=$(MODEL_ID)
- --host=0.0.0.0
- --port=8000
- --tensor-parallel-size=1
- --enable-log-requests
- --max-model-len=${MAX_MODEL_LEN}
- --gpu-memory-utilization=${GPU_MEMORY_UTILIZATION}
- --max-num-seqs=${MAX_NUM_SEQS}
- --max-num-batched-tokens=${MAX_NUM_BATCHED_TOKENS}
- --dtype=${DTYPE}
- --trust-remote-code
- --enable-prefix-caching
- --enable-chunked-prefill
- --quantization=fp8
env:
- name: MODEL_ID
value: ${MODEL_NAME}
- name: HUGGING_FACE_HUB_TOKEN
valueFrom:
secretKeyRef:
name: hf-token-secret
key: token
- name: LD_LIBRARY_PATH
value: "/usr/local/nvidia/lib64"
ports:
- name: http
containerPort: 8000
resources:
requests:
cpu: ${CPU_REQUEST}
memory: "${MEMORY_REQUEST}Gi"
nvidia.com/gpu: "1"
limits:
cpu: ${CPU_REQUEST}
memory: "${MEMORY_REQUEST}Gi"
nvidia.com/gpu: "1"
volumeMounts:
- mountPath: /root/.cache/huggingface
name: cache-volume
- mountPath: /dev/shm
name: dshm
volumes:
- name: cache-volume
persistentVolumeClaim:
claimName: model-cache-pvc
- name: dshm
emptyDir:
medium: Memory
sizeLimit: 16Gi
Gradio UI 배포
Gradio UI는 모델과 채팅할 수 있는 대화형 웹 인터페이스를 제공합니다. 클러스터 내에 배포되며 내부 Kubernetes 네트워크를 통해 vLLM 서비스에 연결됩니다.
Gradio 배포
다음 콘텐츠로 gradio-deployment.yaml이라는 파일을 만듭니다.
apiVersion: apps/v1
kind: Deployment
metadata:
name: gradio-deployment
namespace: ${NAMESPACE_NAME}
labels:
app: gradio
spec:
replicas: 1
selector:
matchLabels:
app: gradio
template:
metadata:
labels:
app: gradio
spec:
containers:
- name: gradio
image: us-docker.pkg.dev/google-samples/containers/gke/gradio-app:v1.0.4
resources:
requests:
cpu: "250m"
memory: "512Mi"
limits:
cpu: "500m"
memory: "512Mi"
env:
- name: CONTEXT_PATH
value: "/v1/chat/completions"
- name: HOST
value: "http://vllm-service:8000"
- name: MODEL_ID
value: "${MODEL_NAME}"
ports:
- containerPort: 7860
Gradio 서비스
다음 콘텐츠로 gradio-service.yaml이라는 파일을 만듭니다.
apiVersion: v1
kind: Service
metadata:
name: gradio-service
namespace: ${NAMESPACE_NAME}
spec:
selector:
app: gradio
ports:
- protocol: TCP
port: 8080
targetPort: 7860
type: ClusterIP
모니터링 가능성 구성
애플리케이션 로깅 및 모니터링 구성에 대한 자세한 내용은 공식 애플리케이션 로깅 및 모니터링 가이드를 참고하세요.
vLLM 모니터링
Google Cloud Managed Service for Prometheus (GMP)가 vLLM 측정항목을 스크래핑할 수 있도록 vLLM 포드를 타겟팅하는 PodMonitoring 리소스를 배포합니다.
다음 콘텐츠로 vllm-pod-monitoring.yaml이라는 파일을 만듭니다.
apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
name: vllm-pod-monitoring
namespace: ${NAMESPACE_NAME}
spec:
selector:
matchLabels:
app: vllm
endpoints:
- port: http
interval: 30s
GPU 모니터링
Google Cloud Managed Service for Prometheus (GMP)가 NVIDIA DCGM 내보내기 도구에서 GPU 측정항목을 스크래핑할 수 있도록 gpu-operator 네임스페이스에 PodMonitoring 리소스를 배포합니다. 자세한 내용은 Cloud Monitoring으로 GPU 측정항목 전송을 참고하세요.
다음 콘텐츠로 gpu-pod-monitoring.yaml이라는 파일을 만듭니다.
apiVersion: monitoring.googleapis.com/v1
kind: PodMonitoring
metadata:
name: dcgm-gmp
namespace: gpu-operator
spec:
selector:
matchLabels:
app: nvidia-dcgm-exporter
endpoints:
- port: metrics
interval: 30s
실행 단계
매니페스트 배포
클러스터에 매니페스트를 적용합니다. YAML 파일에는 환경 변수 자리표시자가 포함되어 있으므로 envsubst를 사용하여 .env 파일의 변수를 대체한 후 적용하세요.
YAML 파일이 포함된 작업 디렉터리로 이동합니다.
cd <local-working-dir>환경 변수를 소싱합니다.
source <local-config-dir>/.env매니페스트를 순서대로 적용합니다.
# Apply core serving manifests envsubst < vllm-pvc.yaml | kubectl apply -f - envsubst < vllm-service.yaml | kubectl apply -f - envsubst < vllm-deployment.yaml | kubectl apply -f - # Apply observability manifests envsubst < vllm-pod-monitoring.yaml | kubectl apply -f - kubectl apply -f gpu-pod-monitoring.yaml # Apply Gradio UI manifests envsubst < gradio-deployment.yaml | kubectl apply -f - envsubst < gradio-service.yaml | kubectl apply -f -
인증
포드 부팅 시퀀스 모니터링
컨테이너 로그를 스트리밍하여 시작 시퀀스를 추적합니다.
# 1. Check pod status (wait until it is Running)
kubectl get pods -n ${NAMESPACE_NAME} -l app=vllm
# 2. Stream logs to verify model loading
kubectl logs -f -l app=vllm -n ${NAMESPACE_NAME}
로그에 활성 게재 준비 신호가 표시될 때까지 기다립니다.
INFO: Application startup complete.
포트 전달 터널 설정
엔드포인트를 로컬에서 테스트하려면 서비스 포트 8000을 전달합니다.
kubectl port-forward service/vllm-service 8000:8000 -n ${NAMESPACE_NAME}
이 터미널을 열어 두거나 백그라운드에서 실행합니다.
서빙 엔드포인트 쿼리
별도의 터미널에서 API 응답성을 테스트합니다.
1. 모델 목록 쿼리
curl -s http://localhost:8000/v1/models | jq
2. 채팅 완성 쿼리
curl -s http://localhost:8000/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{
"model": "'"${MODEL_NAME}"'",
"messages": [
{"role": "user", "content": "What is AGI in 100 words"}
],
"max_tokens": 150
}' | jq
GPU 및 VRAM 할당 확인
모델이 하드웨어를 효율적으로 활용하고 메모리 사용 공간이 올바른지 확인하려면 GPU 감사를 실행하면 됩니다.
포드 내부에서 nvidia-smi를 통해 GPU 감사
활성 vLLM 포드의 이름을 가져오고 컨테이너 내에서 nvidia-smi을 실행합니다.
# Dynamically get the pod name
export VLLM_POD_NAME=$(kubectl get pods -n ${NAMESPACE_NAME} -l app=vllm -o jsonpath='{.items[0].metadata.name}')
# Run nvidia-smi inside the container
kubectl exec ${VLLM_POD_NAME} -n ${NAMESPACE_NAME} -- nvidia-smi
예상 출력: 출력은 GPU_MEMORY_UTILIZATION 매개변수와 일치하는 실제 VRAM 사용률을 보고해야 합니다. 예를 들어 GPU_MEMORY_UTILIZATION=0.95로 google/gemma-4-31B-it를 실행하는 NVIDIA RTX PRO 6000 (약 96GB VRAM)이 있는 워크스테이션에서는 VLLM::EngineCore에 할당된 ~95,800MiB가 표시됩니다.
+-----------------------------------------------------------------------------------------+
| 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 RTX PRO 6000 Blac... On | 00000000:05:00.0 Off | 0 |
| N/A 36C P0 85W / 600W | 95805MiB / 97887MiB | 0% Default |
+-----------------------------------------+------------------------+----------------------+
로그에서 KV 캐시 할당 확인
vLLM 내부 할당 로그를 확인하여 KV 캐시 크기와 토큰 동시성을 확인할 수도 있습니다.
kubectl logs ${VLLM_POD_NAME} -n ${NAMESPACE_NAME} | grep -E "Available KV cache|GPU KV cache size"
예상 출력:
(EngineCore pid=362) INFO 06-18 15:03:43 [gpu_worker.py:456] Available KV cache memory: 56.53 GiB
(EngineCore pid=362) INFO 06-18 15:03:43 [kv_cache_utils.py:1316] GPU KV cache size: 61,728 tokens
이를 통해 컨텍스트 KV 캐시에 56.53GiB의 VRAM이 예약되어 많은 수의 동시 토큰이 허용됨을 확인할 수 있습니다.
Gradio UI 배포 확인
Gradio 포드가 실행되면 포트 전달 터널을 설정하여 UI에 액세스할 수 있습니다.
Gradio 포드 상태 모니터링
Gradio 포드가 실행 중인지 확인합니다.
kubectl get pods -n ${NAMESPACE_NAME} -l app=gradio
예상 출력:
NAME READY STATUS RESTARTS AGE
gradio-deployment-yyyyyyyy-yyyyy 1/1 Running 0 1m
Gradio에 포트 전달 터널 설정
Gradio 서비스 포트 8080을 로컬 포트 7860으로 전달합니다.
kubectl port-forward service/gradio-service 7860:8080 -n ${NAMESPACE_NAME}
이 터미널을 열어 두거나 백그라운드에서 실행합니다.
kubectl port-forward service/gradio-service 7860:8080 -n ${NAMESPACE_NAME} > pf_gradio.log 2>&1 & sleep 3
웹 UI 액세스
- 로컬 워크스테이션에서 실행하는 경우: 브라우저를 열고
http://localhost:7860로 직접 이동합니다. - Cloud Shell 내에서 실행하는 경우: 웹 미리보기 버튼을 사용하고 포트 변경을 선택하고
7860을 입력한 다음 변경 및 미리보기를 클릭합니다.
Gradio 챗봇 인터페이스가 표시됩니다. 메시지를 입력하여 Gemma 모델과 상호작용할 수 있습니다. Gradio 포드는 요청을 내부적으로 vllm-service 엔드포인트로 라우팅합니다.
터널 정리
포트 전달 터널을 중지하려면 다음 단계를 따르세요.
pkill -f "port-forward service/gradio-service"
모니터링 확인
vLLM이 배포되고 PodMonitoring 리소스가 적용되면 측정항목이 Cloud Monitoring에 수집되고 있는지 확인할 수 있습니다.
PodMonitoring 상태 확인
PodMonitoring 리소스가 생성되고 활성 상태인지 확인합니다.
kubectl get podmonitoring -n ${NAMESPACE_NAME}
Google Cloud 콘솔을 사용하여 측정항목 수집 확인
Google Cloud 콘솔(측정항목 탐색기)을 사용하여 측정항목이 수집되고 있는지 확인할 수 있습니다.
- Google Cloud 콘솔에서 측정항목 탐색기를 엽니다.
https://console.cloud.google.com/monitoring/metrics-explorer로 이동합니다(프로젝트${GCP_PROJECT_ID}선택).
- 측정항목 선택 드롭다운에서 다음을 검색하여 선택합니다.
prometheus.googleapis.com/vllm:num_requests_running/gauge를 사용하여 vLLM 측정항목을 확인합니다.prometheus.googleapis.com/DCGM_FI_DEV_GPU_UTIL/gauge를 사용하여 GPU 사용률 측정항목을 확인합니다.
- 차트를 관찰하여 데이터 포인트가 활발하게 표시되는지 확인합니다.
로깅 확인
워크로드가 실행되면 로그가 Cloud Logging으로 내보내지는지 확인할 수 있습니다.
vLLM 로그 수집 확인
vLLM 컨테이너 로그가 Cloud Logging으로 내보내지고 있는지 확인합니다.
project_id=$(gcloud config get-value project)
gcloud logging read "resource.type=\"k8s_container\" AND resource.labels.namespace_name=\"${NAMESPACE_NAME}\" AND resource.labels.container_name=\"vllm-container\"" --limit=10 --project=${project_id}
GPU 내보내기 도구 로그 수집 확인
GPU 내보내기 컨테이너 로그가 Cloud Logging으로 내보내지는지 확인합니다.
project_id=$(gcloud config get-value project)
gcloud logging read "resource.type=\"k8s_container\" AND resource.labels.namespace_name=\"gpu-operator\" AND resource.labels.container_name=\"nvidia-dcgm-exporter\"" --limit=10 --project=${project_id}
Google Cloud 콘솔 (로그 탐색기)을 사용하여 로그 확인
Google Cloud 콘솔을 사용하여 로그 수집을 확인할 수도 있습니다.
- Google Cloud 콘솔에서 로그 탐색기를 엽니다.
https://console.cloud.google.com/logs/query로 이동합니다(프로젝트${GCP_PROJECT_ID}선택).
쿼리 상자에 다음 쿼리를 입력하여 vLLM 로그를 확인합니다.
resource.type="k8s_container" resource.labels.namespace_name="<NAMESPACE_NAME>" resource.labels.container_name="vllm-container"(
<NAMESPACE_NAME>을 실제 네임스페이스(예:your-custom-namespace)로 대체)쿼리 실행을 클릭합니다. vLLM 컨테이너의 로그 항목이 표시됩니다.
GPU 내보내기 로그를 확인하려면 다음 쿼리를 실행하세요.
resource.type="k8s_container" resource.labels.namespace_name="gpu-operator" resource.labels.container_name="nvidia-dcgm-exporter"