Pod는 GPU workload로 정상 기동했고 restart 없이 Ready 1/1 상태를 유지했다. model cache PVC는 local-path StorageClass에서 40Gi volume에 Bound됐고, Service는 Pod label app.kubernetes.io/name=gemma4-vllm을 선택해 cluster 내부 8000/TCP를 노출했다. Node가 광고한 GPU resource도 1개로 확인했다.
Kubernetes 리소스 및 GPU 할당 결과
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESpod/gemma4-12b-6c5cc87ffd-s7gxn 1/1 Running 0 24m 10.42.0.26 momindesktop <none> <none>NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS VOLUMEATTRIBUTESCLASS AGE VOLUMEMODEpersistentvolumeclaim/gemma4-model-cache Bound pvc-0e91bd3f-a2a2-460e-8031-124cf7f1c17c 40Gi RWO local-path <unset> 24m FilesystemNAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE SELECTORservice/gemma4-vllm ClusterIP 10.43.124.212 <none> 8000/TCP 24m app.kubernetes.io/name=gemma4-vllmmomindesktop 1
이 결과로 Device Plugin이 nvidia.com/gpu resource를 Node에 노출했고, GPU limit을 요청한 vLLM Pod가 scheduling되어 Ready 상태까지 도달한 것을 확인했다.
2. model endpoint 검증
ClusterIP Service와 WSL localhost의 차이
처음에는 Service port를 8100으로 열면 WSL에서 localhost:8100으로 접근할 수 있을 것으로 생각했지만 요청이 실패했다. 원인은 Kubernetes ClusterIP Service의 port가 WSL host의 loopback port를 직접 여는 것이 아니기 때문이다.
구분
의미
WSL 127.0.0.1:8100
현재 WSL 환경의 loopback 주소와 port
Service 8000/TCP
Kubernetes cluster network 내부에서 사용하는 가상 Service port
kubectl port-forward
WSL local port와 Kubernetes workload 사이에 임시 터널을 생성하는 명령
따라서 Service만 생성된 상태에서 WSL의 localhost:8100을 호출하면 해당 port를 수신하는 host process가 없어 연결되지 않는다. 다음 port-forward 명령을 실행한 동안에만 kubectl이 WSL의 127.0.0.1:8100을 수신하고 vLLM workload의 8000으로 요청을 전달한다.
WSL curl 요청: 127.0.0.1:8100 → kubectl port-forward local listener → Kubernetes API의 port-forward 터널 → Service가 선택한 vLLM Pod:8000
엄밀히 말하면 port-forward 요청이 일반 Service traffic처럼 ClusterIP data path를 통과하는 것은 아니다. service/gemma4-vllm의 selector와 port 정보로 대상 Pod를 정한 뒤 그 Pod로 터널링한다. 여기서 8100은 WSL에 임시로 여는 local port이고, 8000은 Kubernetes Service가 노출한 port다. 상시 외부 접근이 필요하면 임시 port-forward 대신 NodePort, Ingress, LoadBalancer 등의 노출 방식을 별도로 구성해야 한다.
{ "id": "chatcmpl-b5f96d2f94e971fa", "object": "chat.completion", "created": 1784090416, "model": "gemma-4-12b-q4", "choices": [ { "index": 0, "message": { "role": "assistant", "content": "저는 **Gemma 4**입니다. Google DeepMind에서 개발한 오픈 가중치(open weights) 대규모 언어 모델입니다.\n\n저는 텍스트와 이미지를 이해하고 처리할 수 있으며, 질문에 답하거나 글을 쓰는 등 다양한 언어 관련 작업을 수행할 수 있습니다. 무엇", "refusal": null, "annotations": null, "audio": null, "function_call": null, "reasoning": null }, "logprobs": null, "finish_reason": "length", "stop_reason": null, "token_ids": null, "routed_experts": null } ], "service_tier": null, "system_fingerprint": "vllm-0.24.0-583965f1", "usage": { "prompt_tokens": 17, "total_tokens": 81, "completion_tokens": 64, "prompt_tokens_details": null }, "prompt_logprobs": null, "prompt_token_ids": null, "prompt_text": null, "kv_transfer_params": null}
주요 key-value를 추리면 다음과 같다.
key
값
해석
model
gemma-4-12b-q4
요청한 served model과 일치
choices[0].message.content
마지막 문장이 무엇에서 중단
생성 길이 제한으로 응답이 완결되지 않음
choices[0].finish_reason
length
설정한 최대 생성 token에 도달
usage.prompt_tokens
17
입력 prompt token 수
usage.completion_tokens
64
입력의 max_tokens: 64와 정확히 일치
usage.total_tokens
81
prompt와 completion을 합한 전체 token 수
두 번째 요청은 오류나 model 중단이 아니라 max_tokens: 64 제한에 정확히 도달해 끝났다. 긴 답변이 필요하면 max_tokens를 128 또는 256으로 높이고, 짧은 검증 응답은 prompt에서 한 문장으로 제한한다.