Cấu hình NodeSelector và GPU Resources cho Pod
Bước đầu tiên là xác định chính xác các node trong cụm Kubernetes có gắn card GPU và đảm bảo driver NVIDIA (NVIDIA Container Toolkit) đã được cài đặt trên các node đó.
Chúng ta cần thêm label vào node GPU để vLLM có thể tìm và schedule pod vào đúng máy chủ đó. Nếu không có label này, Kubernetes sẽ coi node GPU như node CPU thông thường và không phân bổ tài nguyên GPU.
kubectl label nodes nvidia.com/gpu=true --overwrite
Kết quả mong đợi: Command chạy thành công, node đã được gắn label `nvidia.com/gpu=true`.
Tiếp theo, ta cần xác định loại GPU cụ thể (ví dụ: A100, V100, RTX4090) để tối ưu hóa việc chọn model. Trong bài này, ta sẽ dùng label mặc định `nvidia.com/gpu-type` hoặc tự tạo label riêng nếu cần.
kubectl get nodes -L nvidia.com/gpu
Kết quả mong đợi: Danh sách các node hiện lên, cột `nvidia.com/gpu` hiển thị giá trị `true` đối với node có GPU.
Để Pod vLLM có thể sử dụng GPU, chúng ta phải khai báo `resources.limits` với key `nvidia.com/gpu` trong manifest deployment. Kubernetes sẽ tự động tìm node có đủ GPU để chạy pod này.
Tạo file cấu hình deployment cơ bản để test khả năng nhận diện GPU trước khi chạy vLLM.
cat > /opt/vllm/deployment-gpu-test.yaml
Đưa manifest này vào cluster để verify GPU scheduler.
kubectl apply -f /opt/vllm/deployment-gpu-test.yaml -n llm-infra
Kiểm tra trạng thái pod, đảm bảo nó đang chạy trên node có GPU và trạng thái là `Running`.
kubectl get pods -n llm-infra -o wide | grep vllm-gpu-test
Kết quả mong đợi: Pod hiển thị `STATUS` là `Running` và `NODE` là tên node có GPU mà bạn đã label ở trên. Nếu pod ở trạng thái `Pending` trong hơn 2 phút, kiểm tra lại NodeSelector hoặc số lượng GPU available.
Xóa pod test để chuẩn bị cho deployment chính thức.
kubectl delete deployment vllm-gpu-test -n llm-infra
Deploy vLLM Server với Docker Image và Model HuggingFace
Chúng ta sẽ sử dụng Docker image chính thức của vLLM từ NVIDIA Container Registry (`nvcr.io`). Đây là image đã được tối ưu hóa sẵn cho CUDA và các thư viện PyTorch cần thiết.
Chọn model cụ thể để load vào server. Trong phần này, ta sử dụng model `meta-llama/Llama-2-7b-hf` (hoặc một model open-source khác tương thích). Bạn cần có token HuggingFace để tải model này nếu nó yêu cầu.
Tạo directory để lưu trữ model cache và config, đồng thời tạo secret chứa HuggingFace Token để Pod có thể pull model.
mkdir -p /opt/vllm/config
kubectl create secret generic huggingface-token --from-literal=HF_TOKEN= -n llm-infra
Tạo file Deployment chính thức cho vLLM server. File này bao gồm cấu hình nodeSelector, GPU resources, volume mount cho model cache, và các environment variables.
cat > /opt/vllm/vllm-deployment.yaml
Giải thích các thành phần trong config:
- `nodeSelector`: Buộc pod chạy trên node có GPU.
- `args`: Chỉ định model path và port listen.
- `env`: Mount secret chứa token để tải model từ HuggingFace Hub.
- `resources`: Yêu cầu 1 GPU card.
Deploy service để expose port 8000 của vLLM ra bên ngoài hoặc cho các service nội bộ khác gọi.
cat > /opt/vllm/vllm-service.yaml
kubectl apply -f /opt/vllm/vllm-deployment.yaml -n llm-infra && kubectl apply -f /opt/vllm/vllm-service.yaml -n llm-infra
Chờ pod khởi động. Quá trình load model đầu tiên có thể mất vài phút để download và load vào VRAM.
kubectl logs -f -n llm-infra -l app=vllm-server
Kết quả mong đợi: Trong log, bạn thấy dòng `Loading model weights`, sau đó là `INFO vllm.engine: Engine is ready` hoặc `Server is running on 0.0.0.0:8000`.
Verify kết quả bằng cách gọi API `/v1/models` từ bên ngoài cluster hoặc từ pod khác.
kubectl port-forward -n llm-infra svc/vllm-service 8000:8000 &
curl http://localhost:8000/v1/models
Kết quả mong đợi: JSON trả về chứa thông tin model `meta-llama/Llama-2-7b-hf` đang được load.
Cấu hình vLLM Parameters: Tensor Parallel và GPU Memory
Để tối ưu hiệu năng trên GPU, chúng ta cần điều chỉnh các tham số quan trọng của vLLM: `tensor-parallel-size`, `gpu-memory-utilization`, và `max-num-seqs`.
`tensor-parallel-size` (TP): Xác định số lượng GPU dùng để chia nhỏ model. Nếu bạn có 1 GPU, giá trị này phải là 1. Nếu có 8 GPU A100 cho model Llama-70B, bạn cần set TP=8. Trong bài này với 1 GPU, ta set TP=1.
`gpu-memory-utilization`: Tỷ lệ VRAM được phép dùng để lưu model và context. Mặc định là 0.9. Với model nhỏ trên GPU lớn, ta có thể tăng lên 0.95 để tăng context window, nhưng cần để lại khoảng trống cho OS.
Sửa lại file deployment để thêm các args này vào command vLLM.
cat > /opt/vllm/vllm-deployment-optimized.yaml
Cập nhật deployment với cấu hình mới. Kubernetes sẽ tự động rolling update pod cũ bằng pod mới.
kubectl apply -f /opt/vllm/vllm-deployment-optimized.yaml -n llm-infra
Quan sát log để xem vLLM load model với các tham số mới.
kubectl logs -f -n llm-infra -l app=vllm-server | grep -E "tensor_parallel|gpu_memory|max_num_seqs"
Kết quả mong đợi: Log hiển thị các dòng xác nhận:
- `tensor_parallel_size: 1`
- `gpu_memory_utilization: 0.95`
- `max_num_seqs: 256`
- `max_model_len: 8192`
Test khả năng sinh text (completion) để verify các tham số hoạt động đúng. Nếu `gpu-memory-utilization` quá cao và model quá lớn, pod sẽ bị OOM Kill. Nếu `max-num-seqs` quá thấp, hệ thống sẽ từ chối request mới khi có nhiều request đồng thời.
curl http://localhost:8000/v1/completions -H "Content-Type: application/json" -d '{
"model": "meta-llama/Llama-2-7b-hf",
"prompt": "Hello, I am a test from vLLM on Kubernetes.",
"max_tokens": 50,
"temperature": 0.7
}'
Kết quả mong đợi: JSON trả về chứa phần `choices` với `text` là câu trả lời từ model. Nếu lỗi, kiểm tra log xem có thông báo OOM hay không.
Để verify GPU usage thực tế trong khi inference, dùng `nvidia-smi` từ pod đang chạy.
kubectl exec -it -n llm-infra -l app=vllm-server -- nvidia-smi
Kết quả mong đợi: Bảng hiển thị GPU đang được sử dụng, VRAM usage tăng lên đáng kể so với khi idle, và process `python` hoặc `vllm` đang chiếm dụng GPU.
Điều hướng series:
Mục lục: Series: Xây dựng nền tảng Private LLM với vLLM, RAG và VectorDB trên hạ tầng Kubernetes
« Phần 4: Đưa dữ liệu vào VectorDB và kiểm tra truy vấn
Phần 6: Xây dựng ứng dụng RAG Backend kết nối vLLM và VectorDB »