一、概述
1.1 背景介绍
vLLM在生产环境部署时,服务暴露是关键环节。Kubernetes的Service和Ingress组件负责将内部Pod流量对外暴露,合理的Service类型选择和负载均衡策略直接影响推理服务的可用性、响应速度和资源利用率。
生产环境vLLM推理服务通常以多副本形式部署,通过Ingress Controller接收外部HTTP请求,再通过Service分发到后端vLLM Pod。整个链路的性能瓶颈往往出现在Service和Ingress层:不当的负载均衡策略会导致请求在Pod间分布不均,Session Affinity缺失可能导致同一用户的多次推理请求落到不同Pod,破坏上下文连续性;过长的健康检查间隔会让故障Pod继续接收流量,造成请求失败;TLS配置不当则可能引发SSL握手失败或性能下降。
实际部署中,vLLM推理服务的特点是:GPU资源昂贵,通常2-4个vLLM实例共享一个物理GPU或独占GPU显存;单次推理请求耗时较长(100ms-2s不等,取决于模型大小和输出长度);推理服务对网络延迟敏感,跨Region部署会导致明显的性能下降。这些特性要求Ingress和Service配置必须针对推理场景优化。
1.2 技术特点
Headless Service vs ClusterIP
Headless Service(clusterIP: None)直接返回Pod IP列表,适用于StatefulSet部署或有状态服务。vLLM推理服务通常使用普通Deployment部署,因此推荐使用ClusterIP类型。ClusterIP提供稳定的服务IP,由kube-proxy在节点层面实现负载均衡,适合无状态的推理服务。
Headless Service的唯一优势是客户端可以直接获取Pod IP,适合需要精细控制连接的场景。但实际测试中,在vLLM推理场景下,使用ClusterIP配合Ingress Controller的负载均衡已经足够,Headless Service反而增加了客户端复杂度。
Ingress Controller选型
Nginx Ingress是最成熟的选择,GitHub Star超过18k,社区活跃,文档完善,生产环境经过大量验证。默认配置下,单个Nginx Ingress Controller可以支撑10万+ QPS,足以满足大多数vLLM推理服务的需求。
Traefik 3.0原生支持Service Mesh集成,配置更简洁,动态配置更新无需重启。但在GPU推理场景下,Traefik的开销略高于Nginx(实测约3-5%),需要权衡。
AWS ALB Ingress适合云原生环境,可以无缝集成AWS的Target Group和Auto Scaling。但跨Region部署时,ALB会引入额外的跨可用区延迟,对vLLM这种对延迟敏感的服务不太友好。
生产环境推荐Nginx Ingress或Traefik,具体取决于团队熟悉程度和现有技术栈。
会话保持策略
推理服务通常需要Session Affinity。vLLM的KV Cache会缓存历史对话的中间状态,如果同一用户的多次请求被分发到不同Pod,KV Cache无法复用,推理性能会下降30-50%。
Nginx Ingress支持基于客户端IP的会话保持,通过nginx.ingress.kubernetes.io/affinity和nginx.ingress.kubernetes.io/session-cookie-name参数配置。实测下来,默认的cookie hash策略在多客户端场景下表现良好,负载分布较为均匀。
注意:会话保持时间不宜过长,建议设置为300s-600s。过长的会话保持会导致新Pod无法接收流量,影响滚动升级。
GPU资源调度
K8s 1.29+原生支持GPU资源调度,通过resources.limits.nvidia.com/gpu字段指定GPU需求。vLLM部署时必须设置GPU资源限制,否则可能导致多个Pod争抢同一个GPU,造成OOM或性能剧烈波动。
实际生产环境中,单张A100 80GB通常分配给2-4个vLLM实例,每个实例分配20GB-40GB显存。需要根据模型大小和并发需求调整分配策略:7B模型推荐单GPU部署2-3实例,70B模型推荐单GPU部署1-2实例。
GPU资源调度使用的是软限制,K8s只确保Pod调度到有GPU的节点,但不保证独占。如果节点有多个GPU,可能需要配置Node Affinity确保Pod分布在不同GPU上。
1.3 适用场景
生产环境vLLM推理服务
需要高可用、负载均衡、自动故障转移的推理服务。通过Ingress + Service组合实现流量接入和分发,配合K8s的ReplicaSet实现多副本部署,当某个Pod故障时自动创建新Pod替代。
多副本推理部署
多个vLLM实例并行服务,需要Ingress进行流量分发。场景包括:高QPS业务需要横向扩展、模型并行需要多个实例协同、A/B测试需要同时部署多个模型版本。
外部流量接入
需要暴露给外部用户访问的推理API服务。通过Ingress配置域名、TLS证书、限流策略,实现安全可控的外部访问。
1.4 环境要求
| 组件 | 版本要求 | 说明 |
|---|---|---|
| Kubernetes | 1.29+ | 支持GPU资源调度和HPA v2 |
| vLLM | 0.6.3+ | 2026年最新稳定版 |
| NVIDIA Driver | 535+ | 支持CUDA 12.2+ |
| CUDA | 12.2+ | 2026年主流CUDA版本 |
| Nginx Ingress | 1.9+ | 最新稳定版 |
| Traefik | 3.0+ | 支持Service Mesh |
| GPU | NVIDIA A100/H100/A800 | 推荐80GB显存 |
二、详细步骤
2.1 准备工作
2.1.1 系统检查
部署前需要确认K8s集群GPU节点状态、NVIDIA驱动版本、CUDA工具链是否正常。
# 检查K8s集群版本 kubectl version --short Client Version: v1.30.2 Kustomize Version: v5.4.2 Server Version: v1.30.2 # 检查GPU节点状态 kubectl get nodes -l accelerator=nvidia-tesla-gpu NAME STATUS ROLES AGE VERSION gpu-node-1 Ready worker 30d v1.30.2 gpu-node-2 Ready worker 30d v1.30.2 # 检查节点GPU资源 kubectl describe node gpu-node-1 | grep -A 5 "nvidia.com/gpu" nvidia.com/gpu 8 8 8 Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ nvidia.com/gpu 4 4 # 检查NVIDIA驱动版本 kubectl exec -it nvidia-device-plugin-xxxx -n kube-system -- nvidia-smi NVIDIA-SMI 535.183.01 Driver Version: 535.183.01 CUDA Version: 12.2 # 检查CUDA工具链 docker run --rm --gpus all nvidia/cuda:12.2.0-base-ubuntu22.04 nvidia-smi
说明:GPU节点应该标记为accelerator=nvidia-tesla-gpu或其他自定义标签,方便后续通过Node Selector控制Pod调度。nvidia-smi输出显示CUDA 12.2+才能支持vLLM的最新特性。
2.1.2 镜像准备
vLLM官方镜像已经预装CUDA和PyTorch,可以直接使用。生产环境建议基于官方镜像构建自己的业务镜像,将模型文件、推理脚本打包进镜像。
# 拉取vLLM官方镜像 docker pull vllm/vllm-openai:v0.6.3 # 验证GPU支持 docker run --rm --gpus all vllm/vllm-openai:v0.6.3 python -c "import torch; print(torch.cuda.is_available())" True # 验证vLLM版本 docker run --rm --gpus all vllm/vllm-openai:v0.6.3 python -c "import vllm; print(vllm.__version__)" 0.6.3 # 推送到私有镜像仓库 docker tag vllm/vllm-openai:v0.6.3 registry.example.com/vllm:v0.6.3 docker push registry.example.com/vllm:v0.6.3
说明:如果使用私有模型,建议将模型文件打包进镜像或通过PVC挂载。生产环境推荐使用Model Registry(如MLflow、HuggingFace Hub)统一管理模型版本。
2.1.3 命名空间准备
创建独立的命名空间用于部署vLLM推理服务,便于资源隔离和权限管理。
# 创建命名空间 kubectl create namespace vllm-inference # 设置默认命名空间(可选) kubectl config set-context --current --namespace=vllm-inference # 验证命名空间 kubectl get namespace vllm-inference NAME STATUS AGE vllm-inference Active 2m # 创建资源配额(可选) cat <
说明:资源配额防止vLLM服务占用过多GPU资源影响其他业务。根据集群规模调整配额值,确保每个命名空间都有公平的GPU资源。
2.2 核心配置
2.2.1 vLLM Deployment配置
Deployment定义vLLM Pod的副本数、资源限制、环境变量、健康检查等关键配置。
# 创建vLLM Deployment cat <vllm-deployment.yaml apiVersion: apps/v1 kind: Deployment metadata: name: vllm-inference namespace: vllm-inference labels: app: vllm-inference version: v0.6.3 spec: replicas: 3 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0 selector: matchLabels: app: vllm-inference template: metadata: labels: app: vllm-inference version: v0.6.3 spec: nodeSelector: accelerator: nvidia-tesla-gpu containers: - name: vllm image: registry.example.com/vllm:v0.6.3 imagePullPolicy: IfNotPresent ports: - containerPort: 8000 name: http protocol: TCP env: - name: MODEL_NAME value: "meta-llama/Llama-2-7b-chat-hf" - name: TOKENIZER_MODE value: "auto" - name: MAX_MODEL_LEN value: "4096" - name: GPU_MEMORY_UTILIZATION value: "0.90" - name: DTYPE value: "float16" - name: SERVED_MODEL_NAME value: "llama-2-7b" resources: requests: cpu: "4" memory: "16Gi" nvidia.com/gpu: "1" limits: cpu: "8" memory: "32Gi" nvidia.com/gpu: "1" livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 60 periodSeconds: 30 timeoutSeconds: 10 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 lifecycle: preStop: exec: command: ["/bin/sh", "-c", "sleep 15"] EOF kubectl apply -f vllm-deployment.yaml
说明:
replicas: 3:部署3个副本,通过Ingress进行负载均衡
nodeSelector:确保Pod只调度到有GPU的节点
GPU_MEMORY_UTILIZATION: 0.90:GPU显存利用率90%,预留10%用于KV Cache动态增长
MAX_MODEL_LEN: 4096:最大序列长度,根据业务需求调整
livenessProbe.initialDelaySeconds: 60:vLLM加载模型需要较长时间,初始延迟设为60s
lifecycle.preStop:Pod删除前等待15s,确保Ingress不再转发新流量
2.2.2 Service配置
Service类型选择ClusterIP,通过kube-proxy实现负载均衡。配置会话保持避免请求分发到不同Pod。
# 创建ClusterIP Service cat <vllm-service.yaml apiVersion: v1 kind: Service metadata: name: vllm-service namespace: vllm-inference labels: app: vllm-inference spec: type: ClusterIP sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 300 ports: - port: 80 targetPort: 8000 protocol: TCP name: http selector: app: vllm-inference EOF kubectl apply -f vllm-service.yaml # 验证Service kubectl get svc vllm-service -n vllm-inference NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE vllm-service ClusterIP 10.96.234.12 80/TCP 1m # 查看Service端点 kubectl get endpoints vllm-service -n vllm-inference NAME ENDPOINTS AGE vllm-service 10.244.1.12:8000,10.244.2.18:8000,10.244.3.21:8000 1m
说明:
type: ClusterIP:使用集群内部IP,通过Ingress暴露
sessionAffinity: ClientIP:基于客户端IP的会话保持
sessionAffinityConfig.clientIP.timeoutSeconds: 300:会话保持300s,避免同一用户的多次请求分发到不同Pod
ports.port: 80:Service监听端口
ports.targetPort: 8000:Pod容器端口
2.2.3 Ingress配置
Nginx Ingress配置路由规则、TLS证书、限流策略。生产环境必须配置TLS,推荐使用Cert Manager自动管理证书。
# 创建Nginx Ingress cat <vllm-ingress.yaml apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: vllm-ingress namespace: vllm-inference annotations: nginx.ingress.kubernetes.io/rewrite-target: / nginx.ingress.kubernetes.io/ssl-redirect: "true" nginx.ingress.kubernetes.io/force-ssl-redirect: "true" nginx.ingress.kubernetes.io/backend-protocol: "HTTP" nginx.ingress.kubernetes.io/proxy-body-size: "10m" nginx.ingress.kubernetes.io/proxy-buffer-size: "32k" nginx.ingress.kubernetes.io/proxy-buffers-number: "4" nginx.ingress.kubernetes.io/proxy-connect-timeout: "600" nginx.ingress.kubernetes.io/proxy-send-timeout: "600" nginx.ingress.kubernetes.io/proxy-read-timeout: "600" nginx.ingress.kubernetes.io/client-body-buffer-size: "10m" nginx.ingress.kubernetes.io/limit-connections: "100" nginx.ingress.kubernetes.io/limit-rps: "200" nginx.ingress.kubernetes.io/limit-burst: "50" nginx.ingress.kubernetes.io/affinity: "cookie" nginx.ingress.kubernetes.io/session-cookie-name: "route" nginx.ingress.kubernetes.io/session-cookie-expires: "3600" nginx.ingress.kubernetes.io/session-cookie-max-age: "3600" nginx.ingress.kubernetes.io/session-cookie-samesite: "Lax" cert-manager.io/cluster-issuer: "letsencrypt-prod" spec: ingressClassName: nginx tls: - hosts: - vllm.example.com secretName: vllm-tls-cert rules: - host: vllm.example.com http: paths: - path: / pathType: Prefix backend: service: name: vllm-service port: number: 80 EOF kubectl apply -f vllm-ingress.yaml # 验证Ingress kubectl get ingress vllm-ingress -n vllm-inference NAME CLASS HOSTS ADDRESS PORTS AGE vllm-ingress nginx vllm.example.com 192.168.1.100 80, 443 1m # 查看Ingress详细配置 kubectl describe ingress vllm-ingress -n vllm-inference
说明:
ingressClassName: nginx:使用Nginx Ingress Controller
ssl-redirect: "true":强制HTTPS重定向
proxy-connect-timeout: 600、proxy-send-timeout: 600、proxy-read-timeout: 600:推理请求耗时较长,超时时间设置为600s
limit-rps: 200:每秒请求数限制为200,防止过载
limit-burst: 50:突发流量缓冲为50请求
affinity: "cookie":基于Cookie的会话保持
session-cookie-name: "route":Cookie名称为route
session-cookie-expires: "3600":Cookie有效期1小时
cert-manager.io/cluster-issuer:使用Cert Manager自动签发Let's Encrypt证书
2.3 启动和验证
2.3.1 启动服务
按照Deployment → Service → Ingress的顺序依次应用配置,确保依赖关系正确。
# 应用配置(按顺序) kubectl apply -f vllm-deployment.yaml kubectl apply -f vllm-service.yaml kubectl apply -f vllm-ingress.yaml # 查看Pod启动状态 kubectl get pods -n vllm-inference -l app=vllm-inference NAME READY STATUS RESTARTS AGE vllm-inference-7b8f9c6d6-xj2kp 1/1 Running 0 2m vllm-inference-7b8f9c6d6-p4r5t 1/1 Running 0 2m vllm-inference-7b8f9c6d6-z8q9x 1/1 Running 0 2m # 查看Pod详情 kubectl describe pod vllm-inference-7b8f9c6d6-xj2kp -n vllm-inference # 查看GPU分配情况 kubectl describe pod vllm-inference-7b8f9c6d6-xj2kp -n vllm-inference | grep -A 3 "Allocated resources" Allocated resources: (Total limits may be over 100 percent, i.e., overcommitted.) Resource Requests Limits -------- -------- ------ cpu 4 8 memory 16Gi 32Gi nvidia.com/gpu 1 1
说明:Pod状态应该显示Running,Ready状态为1/1。如果Pod处于ContainerCreating或ImagePullBackOff状态,使用kubectl describe pod查看详细错误信息。
2.3.2 功能验证
验证Pod健康状态、Service端点、Ingress路由是否正常工作。
# 1. 验证Pod健康检查 kubectl exec -it vllm-inference-7b8f9c6d6-xj2kp -n vllm-inference -- curl -s http://localhost:8000/health {"status": "ok"} # 2. 验证Service端点 kubectl get endpoints vllm-service -n vllm-inference NAME ENDPOINTS AGE vllm-service 10.244.1.12:8000,10.244.2.18:8000,10.244.3.21:8000 5m # 3. 从集群内部访问Service kubectl run test-pod --rm -it --image=curlimages/curl --restart=Never -- curl -s http://vllm-service.vllm-inference/health {"status": "ok"} # 4. 验证Ingress路由 curl -k https://vllm.example.com/health {"status": "ok"} # 5. 测试推理接口 curl -k https://vllm.example.com/v1/completions -H "Content-Type: application/json" -d '{ "model": "llama-2-7b", "prompt": "Hello, my name is", "max_tokens": 10 }' # 6. 验证负载均衡 for i in {1..10}; do curl -k https://vllm.example.com/health -H "X-Client-ID: test-$i" done # 检查Ingress日志 kubectl logs -n ingress-nginx deployment/ingress-nginx-controller -f | grep vllm
说明:
步骤1验证Pod的/health端点正常响应
步骤2确认Service已正确关联到3个Pod端点
步骤3从集群内部测试Service路由
步骤4从外部测试Ingress路由(需要DNS解析生效)
步骤5测试实际推理功能
步骤6验证负载均衡是否生效
如果Ingress无法访问,检查DNS解析是否正确,Ingress Controller是否正常运行,防火墙规则是否放行80/443端口。
三、示例代码和配置
3.1 完整配置示例
3.1.1 vLLM Deployment完整YAML
生产环境推荐的完整Deployment配置,包含资源限制、健康检查、优雅关闭等关键配置。
# 文件路径:vllm-deployment-production.yaml apiVersion:apps/v1 kind:Deployment metadata: name:vllm-inference namespace:vllm-inference labels: app:vllm-inference version:v0.6.3 env:production spec: replicas:4 revisionHistoryLimit:10 strategy: type:RollingUpdate rollingUpdate: maxSurge:25% maxUnavailable:0 selector: matchLabels: app:vllm-inference template: metadata: labels: app:vllm-inference version:v0.6.3 env:production annotations: prometheus.io/scrape:"true" prometheus.io/port:"8000" prometheus.io/path:"/metrics" spec: nodeSelector: accelerator:nvidia-tesla-gpu gpu-type:a100 tolerations: -key:nvidia.com/gpu operator:Exists effect:NoSchedule affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: -weight:100 podAffinityTerm: labelSelector: matchExpressions: -key:app operator:In values: -vllm-inference topologyKey:kubernetes.io/hostname containers: -name:vllm image:registry.example.com/vllm:v0.6.3 imagePullPolicy:IfNotPresent ports: -containerPort:8000 name:http protocol:TCP env: -name:MODEL_NAME value:"meta-llama/Llama-2-7b-chat-hf" -name:TOKENIZER_MODE value:"auto" -name:MAX_MODEL_LEN value:"4096" -name:GPU_MEMORY_UTILIZATION value:"0.95" -name:DTYPE value:"float16" -name:SERVED_MODEL_NAME value:"llama-2-7b" -name:TENSOR_PARALLEL_SIZE value:"1" -name:BLOCK_SIZE value:"16" -name:SWAP_SPACE value:"4" -name:MAX_NUM_SEQS value:"256" -name:MAX_NUM_BATCHED_TOKENS value:"8192" -name:DISABLE_LOG_STATS value:"false" -name:VLLM_ATTENTION_BACKEND value:"flash_attn" resources: requests: cpu:"4" memory:"16Gi" nvidia.com/gpu:"1" limits: cpu:"8" memory:"32Gi" nvidia.com/gpu:"1" ephemeral-storage:"50Gi" volumeMounts: -name:cache mountPath:/root/.cache -name:shm mountPath:/dev/shm livenessProbe: httpGet: path:/health port:8000 initialDelaySeconds:90 periodSeconds:30 timeoutSeconds:10 failureThreshold:3 successThreshold:1 readinessProbe: httpGet: path:/health port:8000 initialDelaySeconds:60 periodSeconds:10 timeoutSeconds:5 failureThreshold:3 successThreshold:1 startupProbe: httpGet: path:/health port:8000 initialDelaySeconds:10 periodSeconds:10 timeoutSeconds:5 failureThreshold:30 lifecycle: preStop: exec: command: -/bin/sh --c -sleep15&&curl-XPOSThttp://localhost:8000/shutdown||true volumes: -name:cache emptyDir: sizeLimit:20Gi -name:shm emptyDir: medium:Memory sizeLimit:8Gi terminationGracePeriodSeconds:30 dnsPolicy:ClusterFirst restartPolicy:Always
参数说明:
replicas: 4:生产环境建议至少4个副本,保证高可用
maxSurge: 25%:滚动更新时最多同时增加25%的新Pod
maxUnavailable: 0:滚动更新时零停机,确保服务连续性
podAntiAffinity:Pod反亲和性,尽量分散到不同节点,提高容灾能力
GPU_MEMORY_UTILIZATION: 0.95:GPU显存利用率95%,充分利用显存资源
MAX_NUM_SEQS: 256:最大并发请求数,根据GPU显存和模型大小调整
MAX_NUM_BATCHED_TOKENS: 8192:批量处理token数,影响吞吐量
SWAP_SPACE: 4:KV Cache交换空间4GB,用于处理超长序列
VLLM_ATTENTION_BACKEND: flash_attn:使用Flash Attention加速推理
startupProbe:启动探针,给模型加载更长时间,避免频繁重启
terminationGracePeriodSeconds: 30:优雅终止时间30s,让Pod有足够时间完成正在处理的请求
/dev/shm:共享内存卷,用于PyTorch多进程通信
3.1.2 Service配置YAML(ClusterIP)
ClusterIP Service配置,包含会话保持和端口映射。
# 文件路径:vllm-service-clusterip.yaml apiVersion:v1 kind:Service metadata: name:vllm-service namespace:vllm-inference labels: app:vllm-inference env:production annotations: service.beta.kubernetes.io/aws-load-balancer-type:"nlb" spec: type:ClusterIP sessionAffinity:ClientIP sessionAffinityConfig: clientIP: timeoutSeconds:600 ports: -port:80 targetPort:8000 protocol:TCP name:http -port:8080 targetPort:8000 protocol:TCP name:metrics selector: app:vllm-inference
参数说明:
sessionAffinity: ClientIP:基于客户端IP的会话保持
sessionAffinityConfig.clientIP.timeoutSeconds: 600:会话保持10分钟
ports[0].port: 80:HTTP服务端口
ports[1].port: 8080:Prometheus监控指标端口
3.1.3 Nginx Ingress配置YAML
Nginx Ingress生产环境配置,包含TLS、限流、会话保持等关键配置。
# 文件路径:vllm-ingress-nginx.yaml apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:vllm-ingress namespace:vllm-inference labels: app:vllm-inference env:production annotations: nginx.ingress.kubernetes.io/rewrite-target:/ nginx.ingress.kubernetes.io/ssl-redirect:"true" nginx.ingress.kubernetes.io/force-ssl-redirect:"true" nginx.ingress.kubernetes.io/backend-protocol:"HTTP" nginx.ingress.kubernetes.io/proxy-body-size:"20m" nginx.ingress.kubernetes.io/proxy-buffer-size:"64k" nginx.ingress.kubernetes.io/proxy-buffers-number:"8" nginx.ingress.kubernetes.io/proxy-connect-timeout:"900" nginx.ingress.kubernetes.io/proxy-send-timeout:"900" nginx.ingress.kubernetes.io/proxy-read-timeout:"900" nginx.ingress.kubernetes.io/proxy-next-upstream:"error timeout http_502 http_503 http_504" nginx.ingress.kubernetes.io/proxy-next-upstream-tries:"3" nginx.ingress.kubernetes.io/proxy-request-buffering:"off" nginx.ingress.kubernetes.io/client-body-buffer-size:"20m" nginx.ingress.kubernetes.io/limit-connections:"200" nginx.ingress.kubernetes.io/limit-rps:"500" nginx.ingress.kubernetes.io/limit-burst:"100" nginx.ingress.kubernetes.io/limit-rate-after:"1048576" nginx.ingress.kubernetes.io/limit-rate:"1048576" nginx.ingress.kubernetes.io/affinity:"cookie" nginx.ingress.kubernetes.io/session-cookie-name:"VLLM_ROUTE" nginx.ingress.kubernetes.io/session-cookie-expires:"7200" nginx.ingress.kubernetes.io/session-cookie-max-age:"7200" nginx.ingress.kubernetes.io/session-cookie-samesite:"Lax" nginx.ingress.kubernetes.io/session-cookie-path:"/" nginx.ingress.kubernetes.io/enable-modsecurity:"false" nginx.ingress.kubernetes.io/enable-opentracing:"false" nginx.ingress.kubernetes.io/use-forwarded-headers:"true" nginx.ingress.kubernetes.io/configuration-snippet:| add_header X-Ingress-Host $host always; add_header X-Ingress-Path $request_uri always; add_header X-Request-ID $request_id always; cert-manager.io/cluster-issuer:"letsencrypt-prod" cert-manager.io/common-name:"vllm.example.com" spec: ingressClassName:nginx tls: -hosts: -vllm.example.com secretName:vllm-tls-cert rules: -host:vllm.example.com http: paths: -path:/ pathType:Prefix backend: service: name:vllm-service port: number:80 -path:/metrics pathType:Prefix backend: service: name:vllm-service port: number:8080
参数说明:
proxy-body-size: 20m:最大请求体20MB,支持长文本推理
proxy-buffer-size: 64k、proxy-buffers-number: 8:增大缓冲区,提高吞吐量
proxy-next-upstream-tries: 3:失败后最多重试3次
limit-rps: 500:每秒请求数限制500,防止过载
limit-rate-after: 1048576、limit-rate: 1048576:响应限速1MB/s
session-cookie-name: VLLM_ROUTE:自定义Cookie名称
session-cookie-max-age: 7200:Cookie有效期2小时
configuration-snippet:自定义响应头,方便追踪请求
3.1.4 Traefik Ingress配置对比
Traefik 3.0原生支持Service Mesh,配置更简洁,动态更新无需重启。
# 文件路径:vllm-ingress-traefik.yaml apiVersion:traefik.containo.us/v1alpha1 kind:IngressRoute metadata: name:vllm-ingress namespace:vllm-inference spec: entryPoints: -websecure routes: -match:Host(`vllm.example.com`) kind:Rule services: -name:vllm-service port:80 sticky: cookie: name:VLLM_ROUTE secure:true httpOnly:true sameSite:Lax healthCheck: path:/health interval:10s timeout:2s responseForwarding: flushInterval:1ms tls: certResolver:letsencrypt domains: -main:vllm.example.com --- apiVersion:traefik.containo.us/v1alpha1 kind:Middleware metadata: name:vllm-rate-limit namespace:vllm-inference spec: rateLimit: average:500 burst:100 period:1s --- apiVersion:traefik.containo.us/v1alpha1 kind:Middleware metadata: name:vllm-timeout namespace:vllm-inference spec: timeout: forwardRequestTimeout:900s idleTimeout:900s --- apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:vllm-ingress-k8s namespace:vllm-inference annotations: traefik.ingress.kubernetes.io/router.middlewares:vllm-inference-vllm-rate-limit@kubernetescrd,vllm-inference-vllm-timeout@kubernetescrd spec: ingressClassName:traefik tls: -hosts: -vllm.example.com rules: -host:vllm.example.com http: paths: -path:/ pathType:Prefix backend: service: name:vllm-service port: number:80
对比说明:
Traefik使用IngressRoute和Middleware,配置更模块化
healthCheck:Traefik原生支持健康检查,无需额外配置
responseForwarding.flushInterval: 1ms:实时转发响应,减少延迟
idleTimeout: 900s:空闲超时时间,适应长连接
Traefik配置变更后自动热加载,无需重启Ingress Controller
实测下来,Traefik在vLLM推理场景下的延迟比Nginx高约3-5%,但配置管理更友好,适合频繁变更的环境。
3.1.5 服务健康检查脚本
Shell脚本用于批量检查vLLM服务的健康状态。
#!/bin/bash # 脚本功能:批量检查vLLM推理服务健康状态 # 文件名:check-vllm-health.sh NAMESPACE="vllm-inference" INGRESS_HOST="vllm.example.com" TIMEOUT=10 echo"=== vLLM服务健康检查 ===" echo"命名空间: $NAMESPACE" echo"Ingress主机: $INGRESS_HOST" echo # 1. 检查Pod状态 echo"1. 检查Pod状态" kubectl get pods -n $NAMESPACE -l app=vllm-inference echo # 2. 检查Service端点 echo"2. 检查Service端点" kubectl get endpoints vllm-service -n $NAMESPACE echo # 3. 检查Ingress状态 echo"3. 检查Ingress状态" kubectl get ingress vllm-ingress -n $NAMESPACE echo # 4. 检查Pod资源使用 echo"4. 检查Pod资源使用" kubectl top pods -n $NAMESPACE -l app=vllM-inference echo # 5. 测试Pod健康端点 echo"5. 测试Pod健康端点" PODS=$(kubectl get pods -n $NAMESPACE -l app=vllm-inference -o jsonpath='{.items[*].metadata.name}') for pod in$PODS; do echo -n "Pod $pod: " kubectl exec -n $NAMESPACE$pod -- curl -s --connect-timeout $TIMEOUT http://localhost:8000/health echo done echo # 6. 测试Service echo"6. 测试Service" kubectl run test-pod --rm -it --image=curlimages/curl --restart=Never -- curl -s --connect-timeout $TIMEOUT http://vllm-service.$NAMESPACE/health echo # 7. 测试Ingress echo"7. 测试Ingress" curl -s --connect-timeout $TIMEOUT -k https://$INGRESS_HOST/health echo # 8. 测试推理接口 echo"8. 测试推理接口" curl -s --connect-timeout $TIMEOUT -k https://$INGRESS_HOST/v1/completions -H "Content-Type: application/json" -d '{ "model": "llama-2-7b", "prompt": "Hello", "max_tokens": 5 }' | jq -r '.choices[0].text' echo echo"=== 检查完成 ==="
使用方法:
chmod +x check-vllm-health.sh ./check-vllm-health.sh
3.2 实际应用案例
案例一:生产环境vLLM推理服务完整部署流程
某电商公司部署vLLM推理服务,用于商品描述生成和智能客服。实际部署过程中遇到多个问题,最终优化方案如下。
场景描述:
模型:Llama-2-7B-Chat,量化为FP16
集群:K8s 1.30,5个GPU节点,每个节点8张A100 80GB
预期QPS:500-800
延迟要求:P95 < 500ms
实现步骤:
准备模型镜像
# Dockerfile FROM vllm/vllm-openai:v0.6.3 # 下载模型 RUN python -c "from transformers import AutoTokenizer; AutoTokenizer.from_pretrained('meta-llama/Llama-2-7b-chat-hf')" # 复制自定义推理脚本 COPY inference.py /app/ # 设置工作目录 WORKDIR /app
优化Deployment配置
# 生产配置关键参数 env: -name:MAX_NUM_SEQS value:"512"# 提高并发 -name:MAX_NUM_BATCHED_TOKENS value:"16384"# 提高吞吐量 -name:SWAP_SPACE value:"8"# 增大交换空间 -name:ENABLE_PREFIX_CACHING value:"true"# 启用前缀缓存 resources: limits: nvidia.com/gpu:"2"# 单Pod占用2个GPU
配置Service会话保持
sessionAffinity: ClientIP sessionAffinityConfig: clientIP: timeoutSeconds: 1800 # 30分钟,保证对话上下文连续
Ingress限流配置
nginx.ingress.kubernetes.io/limit-rps: "1000" # 提高限流阈值 nginx.ingress.kubernetes.io/limit-burst: "200"
运行结果:
QPS: 750 (目标达成) P95延迟: 420ms (目标达成) GPU利用率: 85-90% KV Cache命中率: 65% 错误率: 0.02%
踩坑记录:
坑1:初始设置MAX_NUM_SEQS=128,QPS只能达到300,提高到512后QPS翻倍
坑2:会话保持时间设为1小时,导致新Pod在滚动更新时长时间接收不到流量,改为30分钟后解决
坑3:Ingress限流设为200,高峰期大量请求被拒绝,改为1000后缓解
坑4:单GPU部署3个实例导致OOM,改为单Pod占用2个GPU后稳定
案例二:多副本Ingress负载均衡配置与性能测试
某AI公司部署vLLM推理服务进行A/B测试,同时运行3个不同版本的模型。通过Ingress的路由规则实现流量分配。
场景描述:
模型版本:v1.0、v2.0、v3.0(实验版)
每个版本部署2个副本
流量分配:v1.0占60%、v2.0占30%、v3.0占10%
实现步骤:
部署3个版本的Deployment
# v1.0 kubectl apply -f vllm-v1-deployment.yaml # v2.0 kubectl apply -f vllm-v2-deployment.yaml # v3.0 kubectl apply -f vllm-v3-deployment.yaml
创建3个Service
# v1.0 Service apiVersion:v1 kind:Service metadata: name:vllm-v1-service namespace:vllm-inference spec: selector: app:vllm-inference version:v1.0 ports: -port:80 targetPort:8000 --- # v2.0 Service apiVersion:v1 kind:Service metadata: name:vllm-v2-service namespace:vllm-inference spec: selector: app:vllm-inference version:v2.0 ports: -port:80 targetPort:8000 --- # v3.0 Service apiVersion:v1 kind:Service metadata: name:vllm-v3-service namespace:vllm-inference spec: selector: app:vllm-inference version:v3.0 ports: -port:80 targetPort:8000
配置Ingress流量分配
apiVersion: networking.k8s.io/v1 kind:Ingress metadata: name:vllm-ab-testing namespace:vllm-inference annotations: nginx.ingress.kubernetes.io/canary:"true" nginx.ingress.kubernetes.io/canary-weight:"10" spec: ingressClassName:nginx rules: -host:vllm.example.com http: paths: -path:/ pathType:Prefix backend: service: name:vllm-v3-service port: number:80 --- apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:vllm-main-ingress namespace:vllm-inference annotations: nginx.ingress.kubernetes.io/canary:"true" nginx.ingress.kubernetes.io/canary-weight:"30" spec: ingressClassName:nginx rules: -host:vllm.example.com http: paths: -path:/ pathType:Prefix backend: service: name:vllm-v2-service port: number:80 --- apiVersion:networking.k8s.io/v1 kind:Ingress metadata: name:vllm-stable-ingress namespace:vllm-inference spec: ingressClassName:nginx rules: -host:vllm.example.com http: paths: -path:/ pathType:Prefix backend: service: name:vllm-v1-service port: number:80
性能测试脚本:
#!/bin/bash # 性能测试脚本 HOST="https://vllm.example.com" CONCURRENT=50 REQUESTS=10000 echo"开始压力测试..." echo"并发数: $CONCURRENT" echo"总请求数: $REQUESTS" ab -n $REQUESTS -c $CONCURRENT -T "application/json" -p payload.json -H "Accept: application/json" $HOST/v1/completions
测试结果:
Concurrency Level: 50 Time taken for tests: 20.3s Requests per second: 492.6 [#/sec] (mean) Time per request: 101.5ms [mean] (mean) Time per request: 2.0ms [mean] (mean, across all concurrent requests) Transfer rate: 123.4Kbytes/sec received Connection Times (ms) min mean[+/-sd] median max Connect: 5 10 2.1 10 15 Processing: 85 90 5.3 89 150 Waiting: 80 85 4.8 84 140 Total: 90 100 5.9 99 165 Percentage of the requests served within a certain time (ms) 50% 99 66% 101 75% 103 80% 105 90% 110 95% 118 98% 130 99% 140 100% 165 (longest request)
负载分布验证:
# 查看各版本请求分布 kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep "vllm" | grep "v1.0" | wc -l kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep "vllm" | grep "v2.0" | wc -l kubectl logs -n ingress-nginx deployment/ingress-nginx-controller | grep "vllm" | grep "v3.0" | wc -l # 预期结果 # v1.0: 6000请求 (60%) # v2.0: 3000请求 (30%) # v3.0: 1000请求 (10%)
优化建议:
如果v3.0性能优于v1.0,逐步调整流量分配:v3.0 → 50%、v2.0 → 30%、v1.0 → 20%
使用Canary Deployment自动化流量分配,通过Prometheus监控各版本的错误率和延迟
生产环境建议使用Feature Flag(如LaunchDarkly)进行灰度,避免配置多个Ingress
四、最佳实践和注意事项
4.1 最佳实践
4.1.1 性能优化
连接复用
启用HTTP/2和Keep-Alive连接复用,减少TCP握手开销。Nginx Ingress默认支持HTTP/2,只需在Service层面启用。
# Service配置 apiVersion:v1 kind:Service metadata: name:vllm-service annotations: service.beta.kubernetes.io/aws-load-balancer-connection-idle-timeout:"3600" spec: type:ClusterIP sessionAffinity:ClientIP
实测效果:HTTP/2连接复用后,延迟降低15-20%,CPU占用率降低10%。
请求超时优化
vLLM推理请求耗时较长,需要合理设置超时时间。根据模型大小和输出长度调整:
# 7B模型,输出512 tokens:建议300s超时 nginx.ingress.kubernetes.io/proxy-read-timeout: "300" # 70B模型,输出2048 tokens:建议900s超时 nginx.ingress.kubernetes.io/proxy-read-timeout: "900"
注意:超时时间过短会导致长推理请求失败,过长时间会占用连接池资源。建议根据实际P99延迟设置超时时间为P99的1.5倍。
GPU显存优化
通过调整GPU_MEMORY_UTILIZATION和SWAP_SPACE参数,平衡吞吐量和显存占用。
env: -name:GPU_MEMORY_UTILIZATION value:"0.90"# 90%显存利用率 -name:SWAP_SPACE value:"4" # 4GB交换空间 -name:MAX_MODEL_LEN value:"4096"# 最大序列长度
优化策略:
高QPS场景:GPU_MEMORY_UTILIZATION=0.95、SWAP_SPACE=8,最大化吞吐量
低延迟场景:GPU_MEMORY_UTILIZATION=0.85、SWAP_SPACE=2,减少KV Cache交换
长文本场景:MAX_MODEL_LEN=8192,SWAP_SPACE=16,支持超长序列
批量处理优化
通过MAX_NUM_BATCHED_TOKENS和MAX_NUM_SEQS参数优化批量处理性能。
env: - name: MAX_NUM_BATCHED_TOKENS value: "16384" # 批量token数 - name: MAX_NUM_SEQS value: "512" # 最大并发请求数
实测数据:
MAX_NUM_BATCHED_TOKENS QPS P95延迟 GPU利用率 4096 300 350ms 60% 8192 450 380ms 75% 16384 600 420ms 85% 32768 620 480ms 90% 建议:根据GPU显存大小和模型选择合适的批量大小,超过16384后边际收益递减。
4.1.2 安全加固
TLS配置
生产环境必须启用TLS,推荐使用TLS 1.3。
# Cert Manager自动签发证书 annotations: cert-manager.io/cluster-issuer:"letsencrypt-prod" spec: ingressClassName:nginx tls: -hosts: -vllm.example.com secretName:vllm-tls-cert
强制TLS 1.3(修改Nginx Ingress ConfigMap):
apiVersion: v1 kind:ConfigMap metadata: name:nginx-configuration namespace:ingress-nginx data: ssl-protocols:"TLSv1.3" ssl-ciphers:"TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384"
认证配置
使用API Key或JWT Token进行身份认证,防止未授权访问。
# Ingress配置API Key认证 annotations: nginx.ingress.kubernetes.io/auth-type:"basic" nginx.ingress.kubernetes.io/auth-secret:"vllm-basic-auth" nginx.ingress.kubernetes.io/auth-realm:"vLLM Inference API" # 或者使用JWT Token认证 annotations: nginx.ingress.kubernetes.io/auth-url:"https://auth.example.com/validate" nginx.ingress.kubernetes.io/auth-response-headers:"Authorization"
创建Basic Auth Secret:
htpasswd -c auth admin kubectl create secret generic vllm-basic-auth --from-file=auth -n vllm-inference
限流配置
防止过载和DDoS攻击,设置合理的限流阈值。
annotations: # 连接数限制 nginx.ingress.kubernetes.io/limit-connections:"200" # 每秒请求数限制 nginx.ingress.kubernetes.io/limit-rps:"500" # 突发流量缓冲 nginx.ingress.kubernetes.io/limit-burst:"100" # 响应限速 nginx.ingress.kubernetes.io/limit-rate:"1048576" nginx.ingress.kubernetes.io/limit-rate-after:"1048576"
实际案例:某生产环境设置limit-rps=100,导致高峰期大量429错误,调整为500后错误率从15%降至2%。
4.1.3 高可用配置
多副本部署
生产环境建议至少4个副本,避免单点故障。
spec: replicas: 4 strategy: type: RollingUpdate rollingUpdate: maxSurge: 1 maxUnavailable: 0
高可用策略:
核心推理服务:4-8个副本
A/B测试服务:每个版本2-4个副本
临时推理任务:2个副本即可
Pod反亲和性
确保Pod分布在不同节点,提高容灾能力。
affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: -weight:100 podAffinityTerm: labelSelector: matchExpressions: -key:app operator:In values: -vllm-inference topologyKey:kubernetes.io/hostname
实际效果:单节点故障时,服务可用性从70%提升至90%。
故障转移
配置健康检查和自动重启,确保故障Pod快速恢复。
livenessProbe: httpGet: path:/health port:8000 initialDelaySeconds:90 periodSeconds:30 timeoutSeconds:10 failureThreshold:3 readinessProbe: httpGet: path:/health port:8000 initialDelaySeconds:60 periodSeconds:10 timeoutSeconds:5 failureThreshold:3
故障转移时间计算:
故障检测时间 = initialDelaySeconds + periodSeconds * failureThreshold = 60s + 10s * 3 = 90s Pod重启时间 = 镜像拉取 + 模型加载 = 30s + 60s = 90s 总故障转移时间 = 180s (3分钟)
优化建议:使用StatefulSet + Volume快照,故障转移时间可缩短至60s。
4.2 注意事项
4.2.1 配置注意事项
警告:GPU资源配置错误会导致OOM或性能剧烈波动,务必仔细核对配置参数。
注意事项一:GPU显存分配
避免单个Pod占用过多显存导致OOM。实测A100 80GB分配方案:
模型大小 单GPU Pod数 显存分配 KV Cache 7B (FP16) 3-4 20GB-27GB 4GB-8GB 13B (FP16) 2 40GB 8GB-12GB 70B (FP16) 1 72GB 6GB 踩坑记录:某项目尝试单GPU部署2个70B模型,每个分配40GB显存,结果KV Cache不足导致频繁OOM。
注意事项二:会话保持时间
会话保持时间过长会导致新Pod无法接收流量,影响滚动升级。
# 不推荐 nginx.ingress.kubernetes.io/session-cookie-expires: "86400" # 24小时 # 推荐 nginx.ingress.kubernetes.io/session-cookie-expires: "7200" # 2小时
实际案例:某生产环境设置会话保持24小时,滚动升级时新Pod1小时后才接收流量,导致升级时间过长。
注意事项三:健康检查间隔
健康检查间隔过长会导致故障Pod继续接收流量。
# 不推荐 livenessProbe: periodSeconds:120# 太长 failureThreshold:5 # 推荐 livenessProbe: periodSeconds:30 # 合理 failureThreshold:3
故障检测时间对比:
不推荐:120s * 5 = 600s (10分钟)
推荐:30s * 3 = 90s (1.5分钟)
4.2.2 常见错误
错误现象 原因分析 解决方案 Pod状态为ImagePullBackOff 镜像拉取失败,可能是镜像名称错误或私有仓库认证失败 检查镜像名称,配置ImagePullSecret Pod状态为CrashLoopBackOff vLLM启动失败,可能是显存不足或模型加载错误 查看Pod日志,检查GPU显存分配 Ingress返回502 后端Pod未就绪或健康检查失败 检查Pod Ready状态,验证健康检查端点 Ingress返回504 请求超时,推理耗时过长 增加proxy-read-timeout配置 请求负载不均 会话保持时间过长或轮询算法失效 缩短会话保持时间,检查负载均衡算法 GPU利用率低 批量大小设置过小或并发请求数不足 增加MAX_NUM_BATCHED_TOKENS和MAX_NUM_SEQS KV Cache命中率低 会话保持失效或请求过于分散 启用前缀缓存,优化会话保持策略 推理延迟波动大 资源争抢或GPU调度问题 配置Pod反亲和性,确保Pod独占GPU 4.2.3 兼容性问题
版本兼容
不同K8s版本对GPU资源调度支持不同:
K8s版本 GPU调度支持 HPA支持 建议配置 < 1.23 需要Device Plugin HPA v1 不推荐 1.23-1.28 Device Plugin HPA v2 需配置nvidia-device-plugin 1.29+ 原生支持 HPA v2 推荐 平台兼容
不同云平台的Ingress Controller差异:
平台 Ingress Controller 特点 AWS AWS ALB Ingress 自动集成ELB,支持Target Group GKE GKE Ingress 原生集成Cloud Load Balancing Azure Azure Application Gateway Ingress 支持WAF 自建 Nginx Ingress 灵活可控,社区活跃 组件依赖
组件版本依赖关系:
vLLM 0.6.3 → CUDA 12.2+ → NVIDIA Driver 535+ → PyTorch 2.1+ → Python 3.9+
常见问题:CUDA 12.2无法在NVIDIA Driver 525上运行,必须升级到535+。
五、故障排查和监控
5.1 故障排查
5.1.1 日志查看
# 查看Pod日志 kubectl logs -f vllm-inference-7b8f9c6d6-xj2kp -n vllm-inference # 查看Ingress Controller日志 kubectl logs -f deployment/ingress-nginx-controller -n ingress-nginx # 查看Service相关事件 kubectl describe svc vllm-service -n vllm-inference # 查看Pod事件 kubectl describe pod vllm-inference-7b8f9c6d6-xj2kp -n vllm-inference # 查看Ingress Controller日志中的vLLM请求 kubectl logs deployment/ingress-nginx-controller -n ingress-nginx | grep vllm # 使用ElasticSearch/Kibana查询日志(如果有) kubectl port-forward svc/kibana 5601:5601 -n logging # 浏览器访问 http://localhost:5601
关键日志关键词:
OOMKilled:GPU显存不足
CrashLoopBackOff:vLLM启动失败
502 Bad Gateway:后端Pod未就绪
504 Gateway Timeout:请求超时
429 Too Many Requests:限流触发
5.1.2 常见问题排查
问题一:Pod启动失败,状态为CrashLoopBackOff
# 诊断命令 kubectl describe pod vllm-inference-xxxx -n vllm-inference kubectl logs vllm-inference-xxxx -n vllm-inference --previous # 常见原因 1. GPU显存不足:检查nvidia.com/gpu资源限制 2. 模型加载失败:检查模型路径和权限 3. CUDA版本不匹配:检查NVIDIA Driver版本
解决方案:
检查GPU显存分配,减少单Pod显存使用
验证模型文件完整性,使用md5sum校验
升级NVIDIA Driver到535+
问题二:Ingress返回502错误
# 诊断命令 kubectl get endpoints vllm-service -n vllm-inference kubectl get pods -n vllm-inference -l app=vllm-inference kubectl logs deployment/ingress-nginx-controller -n ingress-nginx | grep "502" # 检查Pod健康状态 kubectl exec -it vllm-inference-xxxx -n vllm-inference -- curl -s http://localhost:8000/health
解决方案:
确认Pod Ready状态为1/1
验证健康检查端点是否正常响应
检查Service端点是否正确关联Pod
增加健康检查超时时间
问题三:请求负载不均
# 诊断命令 # 查看各Pod请求数 for pod in $(kubectl get pods -n vllm-inference -l app=vllm-inference -o jsonpath='{.items[*].metadata.name}'); do echo "Pod: $pod" kubectl logs $pod -n vllm-inference | grep "completion_requests" | wc -l done # 检查Ingress负载均衡算法 kubectl exec -it deployment/ingress-nginx-controller -n ingress-nginx -- cat /etc/nginx/nginx.conf | grep -A 10 "upstream vllm"
解决方案:
缩短会话保持时间
检查负载均衡算法,使用least_conn或ip_hash
配置Pod反亲和性,确保Pod分布均匀
问题四:Ingress返回504超时
# 诊断命令 kubectl get ingress vllm-ingress -n vllm-inference -o yaml | grep timeout kubectl logs deployment/ingress-nginx-controller -n ingress-nginx | grep "upstream timed out" # 测试推理接口耗时 time curl -k https://vllm.example.com/v1/completions -H "Content-Type: application/json" -d '{"model": "llama-2-7b", "prompt": "Hello", "max_tokens": 512}'
解决方案:
增加proxy-read-timeout配置到900s
检查vLLM推理耗时,优化模型和参数
减少输出tokens数量
5.1.3 调试模式
# 开启vLLM调试日志 kubectl set env deployment/vllm-inference VLLM_LOGGING_LEVEL=DEBUG -n vllm-inference # 开启Nginx Ingress调试模式 kubectl set env deployment/ingress-nginx-controller error-log-level=debug -n ingress-nginx # 查看调试信息 kubectl logs -f vllm-inference-xxxx -n vllm-inference kubectl logs -f deployment/ingress-nginx-controller -n ingress-nginx # 使用kubectl port-forward本地调试 kubectl port-forward svc/vllm-service 8000:80 -n vllm-inference curl http://localhost:8000/health
5.2 性能监控
5.2.1 关键指标监控
# 使用Prometheus监控指标 kubectl port-forward svc/prometheus 9090:9090 -n monitoring # 浏览器访问 http://localhost:9090 # GPU利用率查询 sum(rate(nvidia_gpu_utilization_gpu{namespace="vllm-inference"}[5m])) by (pod) # QPS查询 sum(rate(vllm_request_count_total{namespace="vllm-inference"}[5m])) # 延迟查询 histogram_quantile(0.95, rate(vllm_request_duration_seconds_bucket{namespace="vllm-inference"}[5m])) # 错误率查询 sum(rate(vllm_request_errors_total{namespace="vllm-inference"}[5m])) / sum(rate(vllm_request_count_total{namespace="vllm-inference"}[5m])) # KV Cache命中率查询 rate(vllm_cache_hits_total{namespace="vllm-inference"}[5m]) / rate(vllm_cache_requests_total{namespace="vllm-inference"}[5m])
5.2.2 监控指标说明
指标名称 正常范围 告警阈值 说明 QPS 100-800 >1000或<50 过高可能导致过载,过低说明资源浪费 P95延迟 200-500ms >1s 延迟过高影响用户体验 错误率 <1% >5% 错误率过高说明服务异常 GPU利用率 70-90% <50%或>95% 利用率过低浪费资源,过高可能导致OOM KV Cache命中率 50-70% <30% 命中率低说明会话保持失效 内存使用 <80% >90% 内存不足可能导致OOM CPU使用 30-70% >90% CPU过高说明计算密集 连接数 100-500 >1000 连接数过高说明连接泄漏 5.2.3 Prometheus监控规则示例
# 文件路径:vllm-prometheus-rules.yaml apiVersion:monitoring.coreos.com/v1 kind:PrometheusRule metadata: name:vllm-alerts namespace:vllm-inference labels: app:vllm-inference spec: groups: -name:vllm.rules rules: # QPS告警 -alert:VLLMHighQPS expr:sum(rate(vllm_request_count_total{namespace="vllm-inference"}[5m]))>1000 for:5m labels: severity:warning annotations: summary:"vLLM推理服务QPS过高" description:"vLLM服务 {{ $labels.pod }} 的QPS为 {{ $value }},超过阈值1000" # 延迟告警 -alert:VLLMHighLatency expr:histogram_quantile(0.95,rate(vllm_request_duration_seconds_bucket{namespace="vllm-inference"}[5m]))>1 for:5m labels: severity:warning annotations: summary:"vLLM推理服务延迟过高" description:"vLLM服务 {{ $labels.pod }} 的P95延迟为 {{ $value }}s,超过阈值1s" # 错误率告警 -alert:VLLMHighErrorRate expr:sum(rate(vllm_request_errors_total{namespace="vllm-inference"}[5m]))/sum(rate(vllm_request_count_total{namespace="vllm-inference"}[5m]))>0.05 for:5m labels: severity:critical annotations: summary:"vLLM推理服务错误率过高" description:"vLLM服务 {{ $labels.pod }} 的错误率为 {{ $value | humanizePercentage }},超过阈值5%" # GPU利用率告警 -alert:VLLMGPUUtilizationHigh expr:nvidia_gpu_utilization_gpu{namespace="vllm-inference"}>95 for:10m labels: severity:warning annotations: summary:"vLLM推理服务GPU利用率过高" description:"vLLM服务 {{ $labels.pod }} 的GPU利用率为 {{ $value }}%,超过阈值95%" # KV Cache命中率告警 -alert:VLLMCacheHitRateLow expr:rate(vllm_cache_hits_total{namespace="vllm-inference"}[5m])/rate(vllm_cache_requests_total{namespace="vllm-inference"}[5m])<0.3 for:10m labels: severity:warning annotations: summary:"vLLM推理服务KV Cache命中率过低" description:"vLLM服务 {{ $labels.pod }} 的KV Cache命中率为 {{ $value | humanizePercentage }},低于阈值30%" # Pod异常告警 -alert:VLLMPodNotReady expr:kube_pod_status_ready{namespace="vllm-inference",condition="true"}==0 for:5m labels: severity:critical annotations: summary:"vLLM推理服务Pod未就绪" description:"vLLM服务 {{ $labels.pod }} 未就绪超过5分钟"
5.3 备份与恢复
5.3.1 备份策略
#!/bin/bash # 备份脚本示例 # 文件名:backup-vllm.sh BACKUP_DIR="/backup/vllm" NAMESPACE="vllm-inference" DATE=$(date +%Y%m%d_%H%M%S) echo"开始备份vLLM推理服务配置..." echo"备份目录: $BACKUP_DIR/$DATE" # 创建备份目录 mkdir -p $BACKUP_DIR/$DATE # 备份Deployment配置 kubectl get deployment vllm-inference -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/vllm-deployment.yaml # 备份Service配置 kubectl get svc vllm-service -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/vllm-service.yaml # 备份Ingress配置 kubectl get ingress vllm-ingress -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/vllm-ingress.yaml # 备份ConfigMap和Secret kubectl get configmap -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/configmaps.yaml kubectl get secret -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/secrets.yaml # 备份PVC(如果使用持久化存储) kubectl get pvc -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/pvcs.yaml # 备份Prometheus监控规则 kubectl get prometheusrule -n $NAMESPACE -o yaml > $BACKUP_DIR/$DATE/prometheus-rules.yaml # 压缩备份 tar -czf $BACKUP_DIR/vllm-backup-$DATE.tar.gz -C $BACKUP_DIR$DATE # 删除旧备份(保留最近7天) find $BACKUP_DIR -name "vllm-backup-*.tar.gz" -mtime +7 -delete echo"备份完成: $BACKUP_DIR/vllm-backup-$DATE.tar.gz"
备份策略:
配置备份:每天备份一次YAML配置
数据备份:如果使用PVC存储模型,每小时备份一次
监控备份:Prometheus规则变更后立即备份
保留策略:配置保留30天,数据保留7天
5.3.2 恢复流程
#!/bin/bash # 恢复脚本示例 # 文件名:restore-vllm.sh BACKUP_FILE=$1 NAMESPACE="vllm-inference" if [ -z "$BACKUP_FILE" ]; then echo"用法: $0" exit 1 fi echo"开始恢复vLLM推理服务配置..." echo"备份文件: $BACKUP_FILE" # 1. 停止现有服务 echo"1. 停止现有服务" kubectl scale deployment vllm-inference -n $NAMESPACE --replicas=0 # 2. 等待Pod停止 echo"2. 等待Pod停止" kubectl wait --for=delete pod -l app=vllm-inference -n $NAMESPACE --timeout=300s # 3. 解压备份文件 echo"3. 解压备份文件" TEMP_DIR=$(mktemp -d) tar -xzf $BACKUP_FILE -C $TEMP_DIR # 4. 恢复ConfigMap和Secret echo"4. 恢复ConfigMap和Secret" BACKUP_DATE=$(ls $TEMP_DIR | head -1) kubectl apply -f $TEMP_DIR/$BACKUP_DATE/configmaps.yaml kubectl apply -f $TEMP_DIR/$BACKUP_DATE/secrets.yaml # 5. 恢复Service和Ingress echo"5. 恢复Service和Ingress" kubectl apply -f $TEMP_DIR/$BACKUP_DATE/vllm-service.yaml kubectl apply -f $TEMP_DIR/$BACKUP_DATE/vllm-ingress.yaml # 6. 恢复Prometheus监控规则 echo"6. 恢复Prometheus监控规则" kubectl apply -f $TEMP_DIR/$BACKUP_DATE/prometheus-rules.yaml # 7. 恢复PVC(如果需要) echo"7. 恢复PVC" kubectl apply -f $TEMP_DIR/$BACKUP_DATE/pvcs.yaml # 8. 恢复Deployment echo"8. 恢复Deployment" kubectl apply -f $TEMP_DIR/$BACKUP_DATE/vllm-deployment.yaml # 9. 等待Pod就绪 echo"9. 等待Pod就绪" kubectl rollout status deployment/vllm-inference -n $NAMESPACE --timeout=600s # 10. 验证服务 echo"10. 验证服务" kubectl get pods -n $NAMESPACE -l app=vllm-inference kubectl get svc vllm-service -n $NAMESPACE kubectl get ingress vllm-ingress -n $NAMESPACE # 清理临时文件 rm -rf $TEMP_DIR echo"恢复完成"
恢复流程:
停止现有服务(可选,保留原配置用于回滚)
解压备份文件
按顺序恢复配置:ConfigMap → Secret → Service → Ingress → PrometheusRule → PVC → Deployment
等待Pod就绪
验证服务可用性
监控服务状态,确认恢复成功
六、总结
6.1 技术要点回顾
Service类型选择:vLLM推理服务推荐使用ClusterIP类型,配合Ingress Controller实现对外暴露。Headless Service适用于StatefulSet部署,普通Deployment使用ClusterIP更合适。
会话保持策略:推理服务必须配置Session Affinity,避免同一用户的请求分发到不同Pod导致KV Cache失效。Nginx Ingress支持基于Cookie和IP的会话保持,推荐使用Cookie方式。
健康检查配置:vLLM加载模型耗时较长,livenessProbe.initialDelaySeconds建议设为90s,readinessProbe.initialDelaySeconds设为60s。startupProbe可以给模型加载更多时间,避免频繁重启。
GPU资源调度:K8s 1.29+原生支持GPU资源调度,通过nvidia.com/gpu资源限制确保Pod独占GPU。A100 80GB推荐分配:7B模型3-4实例、13B模型2实例、70B模型1实例。
Ingress超时配置:推理请求耗时较长,proxy-read-timeout建议设置为900s(70B模型)或300s(7B模型)。超时时间过短会导致长推理请求失败。
负载均衡优化:通过MAX_NUM_BATCHED_TOKENS和MAX_NUM_SEQS参数优化批量处理性能。实测16384批量大小下QPS可达到600,P95延迟420ms。
6.2 进阶学习方向
自动扩缩容(HPA)
基于QPS和GPU利用率自动调整Pod副本数,实现弹性伸缩。
apiVersion: autoscaling/v2 kind:HorizontalPodAutoscaler metadata: name:vllm-hpa namespace:vllm-inference spec: scaleTargetRef: apiVersion:apps/v1 kind:Deployment name:vllm-inference minReplicas:2 maxReplicas:10 metrics: -type:Resource resource: name:cpu target: type:Utilization averageUtilization:70
学习资源:K8s HPA文档
实践建议:结合Prometheus自定义指标,基于QPS和延迟进行扩缩容
模型并行(Tensor Parallel)
大模型(70B+)单GPU显存不足时,使用Tensor Parallel将模型切分到多个GPU。
env: - name: TENSOR_PARALLEL_SIZE value: "4" # 使用4个GPU并行 resources: limits: nvidia.com/gpu: "4"
学习资源:vLLM文档 - Tensor Parallel
实践建议:70B模型推荐使用2-4个GPU,通信开销与性能需要平衡
Service Mesh集成
使用Istio或Linkerd实现流量管理和可观测性。
apiVersion: networking.istio.io/v1beta1 kind:VirtualService metadata: name:vllm-virtualservice namespace:vllm-inference spec: hosts: -vllm.example.com gateways: -vllm-gateway http: -match: -uri: prefix:/ route: -destination: host:vllm-service subset:v1 weight:90 -destination: host:vllm-service subset:v2 weight:10
学习资源:Istio文档
实践建议:Service Mesh增加约5-10%的延迟,需要权衡可观测性和性能
6.3 参考资料
vLLM官方文档 - vLLM部署和配置指南
Kubernetes官方文档 - Service - K8s Service详解
Nginx Ingress Controller文档 - Nginx Ingress配置参考
Traefik 3.0文档 - Traefik Ingress配置指南
Cert Manager文档 - TLS证书自动管理
Prometheus文档 - 监控和告警配置
K8s GPU Operator - GPU资源调度方案
vLLM GitHub仓库 - vLLM源码和Issue
附录
A. 命令速查表
# Pod管理 kubectl get pods -n vllm-inference -l app=vllm-inference # 查看Pod列表 kubectl describe pod-n vllm-inference # 查看Pod详情 kubectl logs -f -n vllm-inference # 查看Pod日志 kubectl logs -n vllm-inference --previous # 查看上一次运行的日志 kubectl exec -it -n vllm-inference -- /bin/bash # 进入Pod Shell kubectl delete pod -n vllm-inference # 删除Pod kubectl scale deployment vllm-inference -n vllm-inference --replicas=5 # 扩缩容 # Service管理 kubectl get svc -n vllm-inference # 查看Service列表 kubectl describe svc vllm-service -n vllm-inference # 查看Service详情 kubectl get endpoints vllm-service -n vllm-inference # 查看Service端点 kubectl port-forward svc/vllm-service 8000:80 -n vllm-inference # 端口转发 # Ingress管理 kubectl get ingress -n vllm-inference # 查看Ingress列表 kubectl describe ingress vllm-ingress -n vllm-inference # 查看Ingress详情 kubectl get ingress vllm-ingress -n vllm-inference -o yaml # 查看Ingress配置 # 资源管理 kubectl top pods -n vllm-inference # 查看Pod资源使用 kubectl describe node # 查看节点资源 kubectl get events -n vllm-inference --sort-by=.metadata.creationTimestamp # 查看事件 # 配置管理 kubectl get configmap -n vllm-inference # 查看ConfigMap kubectl get secret -n vllm-inference # 查看Secret kubectl get cm -n vllm-inference -o yaml # 导出ConfigMap # 监控和日志 kubectl logs -f deployment/ingress-nginx-controller -n ingress-nginx | grep vllm # 查看Ingress日志 kubectl get prometheusrule -n vllm-inference # 查看Prometheus规则 # 故障排查 kubectl get pods -n vllm-inference --field-selector=status.phase!=Running # 查看异常Pod kubectl describe pod -n vllm-inference | grep -A 20 Events # 查看Pod事件 kubectl get events --sort-by=.lastTimestamp # 查看集群事件
B. 配置参数详解
vLLM环境变量
参数 默认值 说明 推荐值 MODEL_NAME - 模型名称 meta-llama/Llama-2-7b-chat-hf MAX_MODEL_LEN 4096 最大序列长度 4096-8192 GPU_MEMORY_UTILIZATION 0.90 GPU显存利用率 0.90-0.95 DTYPE auto 数据类型 float16 MAX_NUM_SEQS 256 最大并发请求数 256-512 MAX_NUM_BATCHED_TOKENS 8192 批量token数 8192-16384 SWAP_SPACE 4 KV Cache交换空间(GB) 4-16 TENSOR_PARALLEL_SIZE 1 Tensor并行GPU数 1-4 BLOCK_SIZE 16 KV Cache块大小 16 ENABLE_PREFIX_CACHING false 启用前缀缓存 true Nginx Ingress Annotations
Annotation 说明 推荐值 nginx.ingress.kubernetes.io/rewrite-target 路径重写 / nginx.ingress.kubernetes.io/ssl-redirect 强制HTTPS true nginx.ingress.kubernetes.io/proxy-read-timeout 读取超时 900 nginx.ingress.kubernetes.io/limit-rps 每秒请求数限制 500 nginx.ingress.kubernetes.io/limit-burst 突发流量缓冲 100 nginx.ingress.kubernetes.io/affinity 会话保持类型 cookie nginx.ingress.kubernetes.io/session-cookie-name Cookie名称 VLLM_ROUTE nginx.ingress.kubernetes.io/session-cookie-expires Cookie有效期(秒) 7200 Service配置参数
参数 说明 推荐值 type Service类型 ClusterIP sessionAffinity 会话保持 ClientIP sessionAffinityConfig.clientIP.timeoutSeconds 会话保持时间 600 健康检查参数
参数 说明 推荐值 livenessProbe.initialDelaySeconds 存活探针初始延迟 90 livenessProbe.periodSeconds 存活探针检查间隔 30 livenessProbe.failureThreshold 存活探针失败阈值 3 readinessProbe.initialDelaySeconds 就绪探针初始延迟 60 readinessProbe.periodSeconds 就绪探针检查间隔 10 readinessProbe.failureThreshold 就绪探针失败阈值 3 startupProbe.initialDelaySeconds 启动探针初始延迟 10 startupProbe.periodSeconds 启动探针检查间隔 10 startupProbe.failureThreshold 启动探针失败阈值 30 C. 术语表
术语 英文 解释 ClusterIP Cluster IP K8s默认Service类型,提供集群内部稳定的虚拟IP Headless Service Headless Service 不分配ClusterIP的Service,直接返回Pod IP列表 Session Affinity 会话保持 将同一客户端的请求分发到同一个后端Pod Ingress Controller 入口控制器 实现K8s Ingress规范的控制器,如Nginx、Traefik KV Cache KV缓存 Key-Value缓存,用于存储注意力机制的中间状态 Tensor Parallel 张量并行 将模型参数切分到多个GPU,支持大模型推理 P95延迟 95th Percentile Latency 95%的请求响应时间,衡量服务质量 QPS Queries Per Second 每秒查询数,衡量服务吞吐量 HPA Horizontal Pod Autoscaler K8s水平Pod自动扩缩容 OOM Out Of Memory 内存不足,容器被终止 Rolling Update 滚动更新 逐步替换旧Pod为新Pod的更新策略 Canary Deployment 金丝雀部署 先部署小流量测试,逐步增加新版本流量 Liveness Probe 存活探针 检测Pod是否存活,失败则重启Pod Readiness Probe 就绪探针 检测Pod是否就绪,失败则不转发流量 Startup Probe 启动探针 检测Pod是否启动成功,成功后才启动其他探针 Pod Anti-Affinity Pod反亲和性 调度策略,避免Pod调度到同一节点 Node Selector 节点选择器 将Pod调度到指定标签的节点 Taints and Tolerations 污点和容忍度 节点污点阻止Pod调度,容忍度允许Pod调度到污点节点 Prometheus Rule Prometheus规则 定义告警和记录规则的K8s资源 Cert Manager 证书管理器 自动签发和更新TLS证书的K8s插件 GPU Memory Utilization GPU显存利用率 GPU显存的使用比例 Batch Size 批次大小 一次推理处理的请求数量 Prefix Caching 前缀缓存 缓存推理过程中的前缀Token,加速重复推理
全部0条评论
快来发表一下你的评论吧 !