引言:从“跑起来”到“跑得好”
大模型从研究走向生产,最典型的分水岭在于:一台机器能跑通模型,不等于一套系统能跑好服务。当模型参数突破百亿乃至千亿级,单机显存的物理天花板便成为第一道障碍——即便是A100/H100这样的旗舰GPU,也无法独自承载Qwen3-235B这类千亿参数模型的全量加载与推理。

于是,分布式并行(张量并行TP、流水线并行PP)成为标配,单次推理任务可能横跨多张GPU甚至多台物理节点。然而,习惯于处理无状态微服务的Kubernetes原生工作负载抽象(Deployment/Service),面对这种“有状态、重通信、强拓扑依赖”的分布式推理任务,显得力不从心。

本文围绕“Kubernetes + vLLM弹性推理架构设计”这一主题,从分布式推理的云原生痛点、vLLM核心机制、Kubernetes部署实践、弹性伸缩与智能路由四个维度展开,提供一份可落地的生产级架构方案与完整代码示例。

一、分布式大模型推理的云原生挑战
将大模型推理部署在Kubernetes上,面临的远不止“把Pod跑起来”这么简单。核心痛点集中在以下三方面:

1.1 多维度拓扑约束缺失
TP并行需要高频的all-reduce通信,对网络延迟极度敏感。Kubernetes原生调度器极易将同一并行组的Pod打散到不同物理节点甚至跨越骨干网,高昂的跨交换机通信延迟会直接吞噬模型并行带来的性能红利,拖垮吞吐量等核心SLA指标。

1.2 PD分离架构下的编排断裂
为优化长上下文处理,业界普遍采用Prefill(计算密集型)与Decode(访存密集型)分离的架构。但由于Kubernetes缺乏多角色原子化编排能力,这两种负载特性截然不同的角色难以实现独立的精细化弹性扩缩。单一角色的配比失衡,极易导致整体链路拥塞或服务中断。

1.3 流量网关的“状态盲区”
提升长文本推理效率的核心在于复用KV Cache。然而,Kubernetes原生的Ingress或Service均为无状态设计,无法感知各个Decode实例GPU显存中的Cache分布状况。采用轮询等传统策略盲目分发请求,会导致Cache命中率骤降,引发大量重复计算和资源浪费。

二、vLLM:破解GPU内存与调度效率困局
理解vLLM的核心机制,是设计云原生架构的前提。

2.1 PagedAttention:将“浪费”从80%降至4%
传统推理系统为每个请求预分配连续的KV Cache内存块,实际利用率往往只有20%~40%,其余全部浪费在碎片化和过度预留上。vLLM提出的PagedAttention机制,仿照操作系统虚拟内存管理,将KV Cache划分为固定大小的“页”,按需分配并通过页表映射。实验数据显示,这一设计将内存浪费从60%~80%压低至约4%。

直接结果:同一张GPU上能容纳更大的批次、支撑更高的吞吐量。

2.2 Continuous Batching:一个Pod就是一台高并发服务器
vLLM在Token级别进行连续批处理,而非等待固定批次全部完成。这意味着一个长序列生成不会阻塞其他短请求。调度后果是:单个推理副本(Replica)的承载能力远超“一请求一Worker”的模型,Pod真正饱和的信号是它自己的请求队列开始积压,而非单纯的请求总数。

2.3 Prefix Caching:共享前缀一次计算、重复复用
在V1引擎中默认开启的前缀缓存机制,会将公共提示词(如系统指令)的KV块在请求间共享。但需要注意:这个缓存存在于单个Pod的GPU内存中。如果通过普通Service做轮询负载均衡,共享同一前缀的请求会被打散到不同Pod,每个Pod都要重新计算,前缀缓存的收益便归零。这引出了前缀感知路由的必要性。

三、Kubernetes + vLLM:从零搭建生产级推理服务
以下基于GKE集群(Kubernetes 1.35,NVIDIA L4 24GB GPU节点)的完整实操过程,也适用于自建集群。

3.1 前置条件:让GPU成为可调度资源
在部署任何vLLM Pod之前,必须确认GPU资源可被Kubernetes识别:

bash
kubectl get nodes -o custom-columns=NAME:.metadata.name,GPU:.status.allocatable.nvidia.com/gpu

GPU节点应显示 1 或更大数值,而非

如果该列为空,问题出在NVIDIA设备插件或驱动层。在托管集群(GKE/EKS)中,通常随GPU节点池自动安装;自建集群需部署NVIDIA GPU Operator。

测试GPU可访问性(在EKS环境验证通过):

yaml
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: gpu-nvidia-smi-test
spec:
restartPolicy: OnFailure
tolerations:

  • key: “nvidia.com/gpu”
    operator: “Exists”
    effect: “NoSchedule”
    nodeSelector:
    role: gpu-worker # 根据实际节点池标签调整
    containers:
  • name: cuda-container
    image: nvidia/cuda:12.9.1-base-ubuntu20.04
    command: [“nvidia-smi”]
    resources:
    limits:
    nvidia.com/gpu: 1
    EOF
    查看日志确认GPU信息正确输出后,即可进入部署环节。

3.2 核心部署清单:Deployment + Service
以下为完整的vLLM部署YAML(以Llama-3.1-8B-Instruct为例),已在AWS EKS + GKE环境中验证。

第一步:创建模型存储PVC(可选,用于缓存模型文件)

yaml
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: model-store
namespace: inference
spec:
accessModes:
- ReadOnlyMany
resources:
requests:
storage: 50Gi
第二步:部署vLLM服务

yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: vllm-llama3-8b
namespace: inference
spec:
replicas: 1 # 起始1副本,后续由KEDA驱动伸缩
selector:
matchLabels:
app: vllm-llama3-8b
template:
metadata:
labels:
app: vllm-llama3-8b
spec:
tolerations:
- key: nvidia.com/gpu
operator: Exists
effect: NoSchedule
nodeSelector:
role: gpu-worker # 与节点池标签匹配
containers:
- name: vllm
# AWS DLC镜像(EKS推荐),也可替换为 vllm/vllm-openai:latest
image: 763104351884.dkr.ecr.us-east-1.amazonaws.com/vllm:0.9-gpu-py312-ec2
args:
- “–model”
- “NousResearch/Meta-Llama-3-8B-Instruct” # 无门槛可用镜像
- “–gpu-memory-utilization”
- “0.90”
- “–max-model-len”
- “8192”
- “–tensor-parallel-size”
- “1” # 单卡推理;多卡改为GPU数
ports:
- containerPort: 8000
env:
- name: MODEL_PATH
value: “/mnt/models/llama-3.1-8b-instruct”
resources:
limits:
nvidia.com/gpu: 1
requests:
memory: “24Gi”
cpu: “4”
ephemeral-storage: “25Gi”
readinessProbe:
httpGet:
path: /health
port: 8000
initialDelaySeconds: 30
periodSeconds: 5
failureThreshold: 60 # 模型加载可能耗时数分钟
volumeMounts:
- name: models
mountPath: /mnt/models
readOnly: true
volumes:
- name: models
persistentVolumeClaim:
claimName: model-store

apiVersion: v1
kind: Service
metadata:
name: vllm-inference-svc
namespace: inference
spec:
type: ClusterIP
ports:
- port: 80
targetPort: 8000
protocol: TCP
selector:
app: vllm-llama3-8b
关键参数解读:

–gpu-memory-utilization=0.90:为模型权重和KV Cache预留90%显存,过高可能导致启动失败

readinessProbe.failureThreshold=60:大模型镜像下载和CUDA图编译可能长达5~10分钟,阈值过小会导致Pod被反复杀死

tolerations与nodeSelector:确保Pod调度到带有GPU的节点,且匹配节点污点

第三步:测试推理服务

bash

端口转发本地测试

export POD_NAME= ( k u b e c t l g e t p o d − l a p p = v l l m − l l a m a 3 − 8 b − o j s o n p a t h = ′ . i t e m s [ 0 ] . m e t a d a t a . n a m e ′ ) k u b e c t l p o r t − f o r w a r d p o d / (kubectl get pod -l app=vllm-llama3-8b -o jsonpath='{.items[0].metadata.name}') kubectl port-forward pod/ (kubectlgetpodlapp=vllmllama38bojsonpath=.items[0].metadata.name)kubectlportforwardpod/POD_NAME 8000:8000

发送推理请求

curl -X POST http://localhost:8000/v1/completions
-H “Content-Type: application/json”
-d ‘{
“model”: “NousResearch/Meta-Llama-3-8B-Instruct”,
“prompt”: “What is cloud native?”,
“max_tokens”: 256
}’
四、弹性伸缩:KEDA + Karpenter双引擎
真正的生产系统,必须能根据流量自动伸缩——既包括Pod副本数(应用层),也包括GPU节点数(基础设施层)。

4.1 基于队列深度的Pod副本伸缩(KEDA)
vLLM暴露了Prometheus指标端点(默认:8000/metrics),其中最关键的两个指标是:

vllm:num_requests_waiting:正在等待排队的请求数(推荐伸缩依据)

vllm:num_requests_running:正在运行的请求数

使用KEDA(Kubernetes Event-driven Autoscaling)基于队列深度伸缩:

yaml
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: vllm-scaler
namespace: inference
spec:
scaleTargetRef:
name: vllm-llama3-8b
pollingInterval: 10
cooldownPeriod: 60
minReplicaCount: 1
maxReplicaCount: 10
triggers:
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
metricName: vllm_requests_waiting
query: |
sum(vllm:num_requests_waiting{namespace=“inference”})
threshold: “5” # 队列深度>5时扩容
当队列深度超过5时自动扩容,队列清空后冷却60秒缩回。

4.2 GPU节点自动伸缩(Karpenter/Cluster Autoscaler)
Pod副本伸缩的前提是集群内有足够的GPU节点资源。Karpenter(AWS)或Cluster Autoscaler(GCP/Azure)负责在现有GPU节点满载时自动加入新节点:

节点池配置L4/A10G等GPU机型(单卡24GB显存)

冷启动时间约6分钟(含节点预配+驱动初始化)

配合Pod的Pending状态触发节点扩容

4.3 PD分离场景下的联动伸缩(Kthena)
对于Prefill-Decode分离架构(如Qwen3-235B双机16卡部署),需要分别监控Prefill和Decode实例的队列长度并独立伸缩。Kthena Autoscaler正为此设计——当Prefill实例请求积压时扩容Prefill,当Decode GPU利用率飙升时扩容Decode,避免单一角色成为瓶颈。

五、智能路由:突破无状态负载均衡的局限
普通Service轮询分发请求,在大模型推理场景中有两个致命缺陷:

前缀缓存失效:共享系统提示词的请求被分散到不同Pod,每个Pod各自计算,缓存复用率为零

KV Cache亲和性缺失:长对话场景下,续写请求应优先路由到存有该会话KV Cache的实例

5.1 Kthena Router:KV Cache感知路由
Kthena Router通过ScorePlugin机制,收集各Decode实例的KV Cache信息,构建“知识图谱”。新请求到达时,Router对所有可用实例评估当前请求的Token序列与各实例Cache中已有Token序列的重叠度(Block Matching),最终选择缓存命中收益最高的实例。

实验数据表明,这种方式可将吞吐量提升2.7倍,首字延迟(TTFT)降低约73.5%,端到端延迟降低超60%。

5.2 生产栈方案:Helm一键部署
对于希望快速上手的团队,vLLM官方生产栈(Production Stack)提供了Helm Chart方案:

bash
helm repo add vllm https://vllm-project.github.io/production-stack/
helm install vllm vllm/vllm --set modelSpec.modelURL=NousResearch/Meta-Llama-3-8B-Instruct
部署后自动包含Router、Grafana面板、LMCache KV缓存卸载等生产级能力。需要更大规模控制的团队可参考字节跳动开源的AIBrix项目,它提供了高密度LoRA管理、分布式KV缓存等企业级特性。

六、生产级架构全景图
综合以上技术栈,一个完整的Kubernetes + vLLM生产级推理架构包含以下层次:

层级 组件 职责
流量入口 Kthena Router / vLLM Router 前缀感知路由、KV Cache亲和调度
工作负载 vLLM Deployment (多副本) 实际推理执行,暴露/metrics端点
应用伸缩 KEDA (基于vllm:num_requests_waiting) Pod副本动态扩缩
节点伸缩 Karpenter / Cluster Autoscaler GPU节点弹性供给
编排增强 Volcano (Gang Scheduling + 拓扑感知) 多Pod原子化拉起、网络拓扑约束
存储加速 EMS / LMCache (可选) 跨节点KV Cache共享,突破单机显存墙
可观测性 Prometheus + Grafana GPU利用率、队列深度、TTFT/P99延迟监控
七、踩坑经验与优化清单
7.1 启动慢导致健康检查失败
现象:Pod反复重启,日志含KeyboardInterrupt: terminated
根因:failureThreshold过小,模型下载+CUDA图编译耗时超限
解决:readinessProbe.failureThreshold设为60或更高;或先下载模型至PVC预置

7.2 --gpu-memory-utilization 过高
现象:Pod启动失败,日志显示OOM
解决:从0.85开始尝试,观察实际KV Cache占用后再逐步上调

7.3 模型权重存储选择
PVC:适合固定模型,多Pod共享

HostPath:适合单机测试,需确保节点本地有模型文件

模型下载:首次启动自动从HuggingFace下载,需外网访问权限

7.4 跨节点通信延迟
使用nodeSelector + podAffinity将同一TP组的Pod调度到同一节点或同一机架

Volcano调度器的HyperNode可将通信依赖强的实例“锁定”在同一ToR交换机内,网络延迟控制在1~2微秒

结语
将大模型推理搬上Kubernetes,远非“写一个Deployment”那么简单。真正的工程挑战在于:让调度器感知拓扑,让路由器感知缓存,让伸缩器感知队列。vLLM通过PagedAttention和Continuous Batching提供了单Pod的高效推理基座;而Kthena、Volcano、KEDA、Karpenter等云原生组件构成的生态,则补齐了大规模生产所需的编排、路由与弹性能力。

2026年的行业共识是:未来大模型服务平台必然建立在成熟云原生技术栈之上。本文所呈现的架构——Kubernetes + vLLM + 智能路由 + 联动伸缩——正是这一趋势的可落地范式。从单卡推理到千卡集群,核心设计原则不变:让基础设施感知模型特性,让模型特性驱动基础设施调度。

更多推荐