托管模型 API 仍然是许多业务的合适选择:接入快、运维负担低,也容易按调用量扩展。自托管并不是要取代它,而是提供另一种部署路径。当团队需要控制模型版本、数据流向、推理配置或基础设施成本时,可以考虑在 Kubernetes 中运行 vLLM,把 GPU 推理服务纳入现有的调度、发布和监控体系。
自托管真正改变了什么
调用托管 API 时,团队主要管理请求、密钥、配额和业务降级。切换到集群内推理后,责任边界会明显扩大:
- Kubernetes 负责放置 Pod,但 GPU 驱动、设备插件和节点兼容性仍需平台团队维护。
- vLLM 负责模型推理服务,模型权重下载、缓存和版本固定需要自行设计。
- 服务是否存活不能只看进程,还要验证模型是否加载完成、接口能否生成结果。
- GPU 利用率、排队时间、首 Token 延迟和整体吞吐量会直接影响容量规划。
- 模型许可证、权重访问凭证以及输入输出日志都需要纳入安全治理。
因此,自托管更适合已经具备 Kubernetes 和 GPU 运维能力,并且确实需要更强控制力的团队。对于低流量、模型变化频繁或缺少 GPU 平台经验的项目,托管 API 往往仍然更经济。
部署前先确认 GPU 调度链路
下面的命令假设集群使用 NVIDIA GPU,并且已经安装匹配的驱动与 Kubernetes 设备插件。不同云厂商和本地集群的安装方式不同,应先按平台文档完成 GPU 节点配置。
检查节点是否向 Kubernetes 暴露了 GPU 资源:
kubectl get nodes -o custom-columns='NAME:.metadata.name,GPU:.status.allocatable.nvidia\.com/gpu'
如果 GPU 列为空,不要急着部署模型。先检查设备插件和节点状态:
kubectl get pods -A | grep -i nvidia
kubectl describe node <GPU_NODE_NAME>
还需要提前估算显存。模型权重、KV Cache、运行时缓冲区和并发请求都会占用显存;仅根据模型文件大小选择 GPU,容易在加载模型或提高并发时触发 OOM。
一份可改造的 vLLM Deployment
下面是一份最小化实践示例,假设使用支持 GPU 的官方 vLLM OpenAI 兼容服务镜像,并加载一个公开的小型指令模型。镜像标签、模型名称和参数应在生产环境中固定为团队验证过的版本。
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm
labels:
app: vllm
spec:
replicas: 1
selector:
matchLabels:
app: vllm
template:
metadata:
labels:
app: vllm
spec:
containers:
- name: vllm
image: vllm/vllm-openai:latest
args:
- --model
- Qwen/Qwen2.5-0.5B-Instruct
- --host
- 0.0.0.0
- --port
- '8000'
- --dtype
- auto
- --gpu-memory-utilization
- '0.90'
ports:
- name: http
containerPort: 8000
resources:
requests:
cpu: '2'
memory: 8Gi
nvidia.com/gpu: '1'
limits:
cpu: '4'
memory: 16Gi
nvidia.com/gpu: '1'
readinessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 30
periodSeconds: 10
failureThreshold: 30
livenessProbe:
httpGet:
path: /health
port: http
initialDelaySeconds: 120
periodSeconds: 30
failureThreshold: 5
---
apiVersion: v1
kind: Service
metadata:
name: vllm
spec:
selector:
app: vllm
ports:
- name: http
port: 8000
targetPort: http
type: ClusterIP
将内容保存为 vllm.yaml 后,可以这样部署和观察模型加载过程:
kubectl apply -f vllm.yaml
kubectl rollout status deployment/vllm --timeout=15m
kubectl logs -f deployment/vllm
这里使用 latest 只是为了让示例简洁。生产环境应替换为明确的镜像标签或镜像摘要,否则重新调度后可能运行不同版本。若模型仓库需要访问令牌,应通过 Kubernetes Secret 注入环境变量,避免把凭证写入 YAML 或容器参数。
从本地验证 OpenAI 兼容接口
可以先用端口转发验证服务,不必立即配置 Ingress:
kubectl port-forward service/vllm 8000:8000
另开终端发送请求。请求中的 model 必须与服务启动时加载的模型一致:
curl http://127.0.0.1:8000/v1/chat/completions \
-H 'Content-Type: application/json' \
-d '{
"model": "Qwen/Qwen2.5-0.5B-Instruct",
"messages": [
{"role": "system", "content": "You are a concise engineering assistant."},
{"role": "user", "content": "Explain Kubernetes readiness probes in two sentences."}
],
"temperature": 0.2,
"max_tokens": 120
}'
确认接口可用后,再决定是否通过内部网关、Service Mesh 或 Ingress 暴露服务。不要直接把未鉴权的推理端点发布到公网。至少应增加身份认证、请求大小限制、超时、并发控制和审计策略。
扩容不能只看 CPU
普通 Web 服务常根据 CPU 或请求数扩容,但 LLM 推理的瓶颈通常与 GPU 显存、Token 数量、批处理效率和排队深度有关。直接配置 HPA 并不意味着能够高效扩容:新 Pod 还要等待 GPU 调度、下载权重并完成模型初始化。
更稳妥的做法是先采集以下指标,再设计扩容策略:
- 请求排队时间与队列长度;
- 首 Token 延迟和每 Token 延迟;
- 输入、输出 Token 数量及其分布;
- GPU 利用率与显存占用;
- 模型加载时间、失败次数和 OOM 重启次数。
模型权重可以放入节点缓存、持久卷或预制镜像,但三种方式各有代价。节点缓存启动快却依赖节点;持久卷便于集中管理,但吞吐量可能成为瓶颈;把权重打入镜像能够固定版本,却会产生体积很大的镜像。应根据模型大小、发布频率和集群网络条件选择。
上线前的决策清单
将 vLLM 放进 Kubernetes 之前,可以用以下问题做一次评审:
- 是否有稳定可用的 GPU 节点、驱动和设备插件?
- 模型、vLLM 镜像及 CUDA 依赖是否固定版本?
- 模型许可证是否允许当前使用和分发方式?
- 权重下载失败或节点替换时,恢复时间是否可接受?
- 推理端点是否具备认证、限流、超时和日志脱敏?
- 是否以真实 Prompt 长度和并发量完成压测?
- 托管 API 是否保留为溢出容量或故障降级路径?
自托管与托管 API 可以并存。实际架构中,可以把稳定、高流量且数据敏感的任务送入集群内 vLLM,把突发流量或特殊模型请求交给托管服务。关键不是把模型跑起来,而是明确团队愿意承担哪些运维责任,并用真实负载证明这条路径在成本、延迟和可靠性上成立。