使用 Helm 在 Kubernetes 上部署 vLLM 推理服务:安装步骤、values 配置详解与模型自动下载原理
2026/9/5 19:57:38 网站建设 项目流程

使用 Helm 在 Kubernetes 上部署 vLLM 推理服务:安装步骤、values 配置详解与模型自动下载原理

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

本篇基于 vLLM 仓库中的 Helm 部署文档 与官方示例 chart examples/deployment/chart-helm,完整讲解如何用 Helm 在 Kubernetes 上部署 vLLM 推理服务:包括前置条件、安装与卸载命令、全部 values 参数、部署架构,以及结合 chart 模板源码剖析"模型自动下载 + init 容器等待"这套默认机制的底层实现。读完后,你可以直接复制命令在自己集群中部署 vLLM,并理解每个 K8s 资源对象是由哪个模板、依据哪些参数渲染出来的。

部署架构概览

Helm 是 Kubernetes 的包管理器。借助它,vLLM 可以把整套 K8s 资源(Deployment、Service、PVC、Job、HPA 等)打包为一个 chart,以不同配置下发到多个 namespace。

从 chart 目录结构 可以看到,这个 chart(Chart.yaml 中声明name: chart-vllmtype: application)由一组 Go Template 模板渲染而成:

模板文件渲染出的 K8s 资源作用
templates/deployment.yamlDeployment运行vllm serve主容器,含 init 容器、健康探针、GPU 亲和性
templates/job.yamlJob用 aws-cli 把模型权重从 S3 同步到 PVC(默认启用)
templates/pvc.yamlPersistentVolumeClaim存放模型权重的持久化存储(ReadWriteOnce
templates/service.yamlServiceClusterIP类型,对外暴露推理端口
templates/hpa.yamlHorizontalPodAutoscaler按 CPU/内存利用率自动扩缩容(默认关闭)
templates/poddisruptionbudget.yamlPodDisruptionBudget自愿中断时限制不可用副本数
templates/configmap.yaml / templates/secrets.yamlConfigMap / Secret通过envFrom注入环境变量与 S3 凭据
templates/custom-objects.yaml任意自定义对象以 Helm 模板语法渲染任意 K8s 资源

整体数据流是:Job 先把模型权重从 S3 写入 PVC,Deployment 主容器把 PVC 挂载到/data,容器内执行vllm serve /data/启动 OpenAI 兼容服务,Service 将流量导入 Pod。

前置条件

在开始之前,确保你具备以下条件(引自 Helm 文档):

  • 一个可用的 Kubernetes 集群;
  • NVIDIA Kubernetes Device Plugin(k8s-device-plugin),用于向 K8s 注册 GPU 资源;
  • 集群中有可用的 GPU 资源;
  • (可选)存放模型权重的 S3 桶或其他存储 —— 仅在使用"自动模型下载"时需要。

S3 凭据会在安装时以--set secrets.*的方式传入,最终由 templates/secrets.yaml 渲染为一个OpaqueSecret(值经b64enc编码),命名规则为{{ .Release.Name }}-secrets

安装与卸载 Chart

文档以 examples/deployment/chart-helm 目录中的 chart 为例。helm upgrade --install命令在 chart 所在目录(即examples/deployment/chart-helm)下执行,安装一个 release 名为test-vllm的部署:

helm upgrade --install --create-namespace \ --namespace=ns-vllm test-vllm . \ -f values.yaml \ --set secrets.s3endpoint=$ACCESS_POINT \ --set secrets.s3bucketname=$BUCKET \ --set secrets.s3accesskeyid=$ACCESS_KEY \ --set secrets.s3accesskey=$SECRET_KEY

要点说明:

  • --create-namespace --namespace=ns-vllm:自动创建并使用独立 namespace,便于把同一 chart 部署到多个 namespace 做不同配置;
  • -f values.yaml:使用 chart 自带 values.yaml 作为基线值,也可以用自定义文件覆盖;
  • 四个--set secrets.*覆盖 S3 凭据,供默认启用的模型下载 Job 使用;values.yaml中的secrets默认为空对象{},即 S3 地址/桶名/密钥必须显式提供,否则wait-download-model与下载 Job 无法工作。

卸载命令:

helm uninstall test-vllm --namespace=ns-vllm

文档特别强调:该命令会删除 chart 关联的所有 Kubernetes 组件,包括持久卷(PVC),并删除 release。也就是说test-vllm-storage-claim这个 PVC 会被一并移除,模型权重不会保留,重新部署时需要再次下载。

主容器与 Deployment:源码级细节

渲染逻辑集中在 templates/deployment.yaml 与 templates/_helpers.tpl 中,几个关键实现细节:

  1. 镜像与启动命令。主容器镜像为{{ .Values.image.repository }}:{{ .Values.image.tag }},默认vllm/vllm-openai:latestimage.repositoryimage.tag使用required强制校验,未定义会渲染失败。仓库 values.yaml 中默认的启动命令为:

    command: ["vllm", "serve", "/data/", "--served-model-name", "opt-125m", "--enforce-eager", "--dtype", "bfloat16", "--block-size", "16", "--host", "0.0.0.0", "--port", "8000"]

    即从 PVC 挂载目录/data/加载模型、以 125M 参数的小模型opt-125m为例做演示,并显式指定--enforce-eager(禁用 CUDA Graph 以便在资源受限环境启动)、bfloat16精度与 16 的 block size。实际部署时替换为你的模型路径与参数即可。

  2. 模型存储挂载。主容器把{{ .Release.Name }}-storage卷(指向 PVC{{ .Release.Name }}-storage-claim)挂载到/data,与vllm serve /data/形成闭环。

  3. GPU 调度。当resources.requestsresources.limitsnvidia.com/gpu均大于 0 时,模板会自动追加runtimeClassName: nvidia,并生成基于节点标签nvidia.com/gpu.productnodeAffinity,候选值取自gpuModels列表(默认占位符TYPE_GPU_USED,必须替换成实际卡型,如 A10G/H100 对应的 product 标签值)。这也解释了前置条件中要求安装 NVIDIA Device Plugin——没有插件就没有nvidia.com/gpu资源可请求。

  4. 副本数与更新策略replicas来自replicaCount(默认 1);deploymentStrategy未配置时,helpers 中的chart.strategy默认使用rollingUpdate: maxSurge 100% / maxUnavailable 0的零中断滚动更新,且 Deployment 的progressDeadlineSeconds为 1200 秒,为 vLLM 这类大模型容器拉镜像、加载权重的慢启动留出余量。

  5. 环境变量注入。若配置了configs/secrets/externalConfigs,模板通过envFrom引用{{ .Release.Name }}-configsConfigMap 与{{ .Release.Name }}-secretsSecret。这意味着所有 S3 凭据最终都以环境变量形式进入容器(见下一节),也可以借此注入VLLM_*系列环境变量给 vLLM 主进程。

模型自动下载机制:Job + 等待 init 容器

这是该 chart 默认开启(extraInit.modelDownload.enabled: true)的核心机制,由两个协作者构成:

下载 Job(templates/job.yaml):当modelDownload.enabled为真时渲染出名为{{ .Release.Name }}-init-vllm的 Job,其容器job-download-model使用 aws-cli 镜像(默认amazon/aws-cli:2.6.4)执行:

aws --endpoint-url $S3_ENDPOINT_URL s3 sync s3://$S3_BUCKET_NAME/$S3_PATH /data

把桶内s3modelpath指定的模型目录同步到 PVC 的/data。Job 的restartPolicy: OnFailure,完成后 100 秒内自动清理(ttlSecondsAfterFinished: 100),资源请求/上限仅为 200m/500m CPU、1Gi/2Gi 内存——下载任务本身很轻。

等待 init 容器(templates/deployment.yaml 第 75–98 行附近):Deployment 的wait-download-modelinit 容器在主容器之前运行,通过轮询"干跑"同步结果来阻塞,直到模型文件就绪:

while aws --endpoint-url $S3_ENDPOINT_URL s3 sync --dryrun s3://$S3_BUCKET_NAME/$S3_PATH /data | grep -q download; do sleep 10; done

即:只要--dryrun输出中还有download条目(说明/data里还缺文件),就每 10 秒重试一次。这样主容器启动时模型必然已就位,避免了vllm serve因权重缺失而反复崩溃。

凭据如何流转。init 容器与 Job 的环境变量由 helpers 中的chart.extraInitEnv统一生成:S3_ENDPOINT_URLS3_BUCKET_NAMEAWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEY四个变量分别通过secretKeyRef{{ .Release.Name }}-secrets中读取s3endpoints3bucketnames3accesskeyids3accesskey四个键——这正是安装命令里那四个--set secrets.*的落点;S3_PATH则直接取自extraInit.s3modelpath。此外,若extraInit.awsEc2MetadataDisabled有定义(默认true),还会注入AWS_EC2_METADATA_DISABLED,避免在 EKS 之外的云环境(如自建集群、GCP/Azure)上 aws-cli 反复查询 EC2 元数据服务导致启动变慢。注意:一旦显式配置了waitContainer.envdownloadJob.env,模板会整体替换默认的 S3 变量组,适合改用 Hugging Face 等其它下载方式。

PVC、Service、HPA 与 PDB

  • PVC(templates/pvc.yaml):只要extraInit有值就渲染,容量取自extraInit.pvcStorage(默认"1Gi",只够 opt-125m 演示模型;部署 7B 级以上模型务必调大,如10Gi),访问模式固定为ReadWriteOnce
  • Service(templates/service.yaml):固定ClusterIP类型,servicePort(默认 80)映射到容器端口名container-port(即containerPort,默认 8000,与--port 8000对应)。serviceName为空时默认命名{{ .Release.Name }}-service
  • HPA(templates/hpa.yaml):autoscaling.enabled: true时渲染autoscaling/v2HPA,支持 CPU(targetCPUUtilizationPercentage,默认 80)与内存(targetMemoryUtilizationPercentage,values 中默认注释)两个 Resource 指标,副本数在minReplicas(默认 1)到maxReplicas(默认 100)之间伸缩。
  • PDB(templates/poddisruptionbudget.yaml):maxUnavailable默认 1,保障节点维护等自愿中断期间的服务可用性。
  • ConfigMap / Secretsconfigs(默认{})渲染为{{ .Release.Name }}-configssecrets渲染为 base64 编码的 Opaque Secret。
  • 自定义资源customObjects列表中的每一项都会以 Helm 模板语法渲染成独立 K8s 对象,方便追加 Ingress、InferenceService 等任意资源。

values 参数完整说明

以下表格完整收录 Helm 文档 中values.yaml的可配置参数:

KeyTypeDefaultDescription
autoscalingobject{"enabled":false,"maxReplicas":100,"minReplicas":1,"targetCPUUtilizationPercentage":80}Autoscaling configuration
autoscaling.enabledboolfalseEnable autoscaling
autoscaling.maxReplicasint100Maximum replicas
autoscaling.minReplicasint1Minimum replicas
autoscaling.targetCPUUtilizationPercentageint80Target CPU utilization for autoscaling
configsobject{}Configmap
containerPortint8000Container port
customObjectslist[]Custom Objects configuration
deploymentStrategyobject{}Deployment strategy configuration
externalConfigslist[]External configuration
extraContainerslist[]Additional containers configuration
extraInitobject{"modelDownload":{"enabled":true},"initContainers":[],"pvcStorage":"1Gi"}Additional configuration for init containers
extraInit.modelDownloadobject{"enabled":true}Model download functionality configuration
extraInit.modelDownload.enabledbooltrueEnable automatic model download job and wait container
extraInit.modelDownload.imageobject{"repository":"amazon/aws-cli","tag":"2.6.4","pullPolicy":"IfNotPresent"}Image for model download operations
extraInit.modelDownload.waitContainerobject{}Wait container configuration (command, args, env)
extraInit.modelDownload.downloadJobobject{}Download job configuration (command, args, env)
extraInit.initContainerslist[]Custom init containers (appended after model download if enabled)
extraInit.pvcStoragestring"1Gi"Storage size for the PVC
extraInit.s3modelpathstring"relative_s3_model_path/opt-125m"(Optional) Path of the model on S3
extraInit.awsEc2MetadataDisabledbooltrue(Optional) Disable AWS EC2 metadata service
extraPortslist[]Additional ports configuration
gpuModelslist["TYPE_GPU_USED"]Type of gpu used
imageobject{"command":["vllm","serve","/data/","--served-model-name","opt-125m","--host","0.0.0.0","--port","8000"],"repository":"vllm/vllm-openai","tag":"latest"}Image configuration
image.commandlist["vllm","serve","/data/","--served-model-name","opt-125m","--host","0.0.0.0","--port","8000"]Container launch command
image.repositorystring"vllm/vllm-openai"Image repository
image.tagstring"latest"Image tag
livenessProbeobject{"failureThreshold":3,"httpGet":{"path":"/health","port":8000},"initialDelaySeconds":15,"periodSeconds":10}Liveness probe configuration
livenessProbe.failureThresholdint3Number of times after which if a probe fails in a row, Kubernetes considers that the overall check has failed: the container is not alive
livenessProbe.httpGetobject{"path":"/health","port":8000}Configuration of the kubelet http request on the server
livenessProbe.httpGet.pathstring"/health"Path to access on the HTTP server
livenessProbe.httpGet.portint8000Name or number of the port to access on the container, on which the server is listening
livenessProbe.initialDelaySecondsint15Number of seconds after the container has started before liveness probe is initiated
livenessProbe.periodSecondsint10How often (in seconds) to perform the liveness probe
maxUnavailablePodDisruptionBudgetstring""Disruption Budget Configuration
readinessProbeobject{"failureThreshold":3,"httpGet":{"path":"/health","port":8000},"initialDelaySeconds":5,"periodSeconds":5}Readiness probe configuration
readinessProbe.failureThresholdint3Number of times after which if a probe fails in a row, Kubernetes considers that the overall check has failed: the container is not ready
readinessProbe.httpGetobject{"path":"/health","port":8000}Configuration of the kubelet http request on the server
readinessProbe.httpGet.pathstring"/health"Path to access on the HTTP server
readinessProbe.httpGet.portint8000Name or number of the port to access on the container, on which the server is listening
readinessProbe.initialDelaySecondsint5Number of seconds after the container has started before readiness probe is initiated
readinessProbe.periodSecondsint5How often (in seconds) to perform the readiness probe
replicaCountint1Number of replicas
resourcesobject{"limits":{"cpu":4,"memory":"16Gi","nvidia.com/gpu":1},"requests":{"cpu":4,"memory":"16Gi","nvidia.com/gpu":1}}Resource configuration
resources.limits."nvidia.com/gpu"int1Number of GPUs used
resources.limits.cpuint4Number of CPUs
resources.limits.memorystring"16Gi"CPU memory configuration
resources.requests."nvidia.com/gpu"int1Number of GPUs used
resources.requests.cpuint4Number of CPUs
resources.requests.memorystring"16Gi"CPU memory configuration
secretsobject{}Secrets configuration
serviceNamestring""Service name
servicePortint80Service port
labels.environmentstringtestEnvironment name

结合仓库源码补充几点文档表格之外的实现事实:

  • 两个探针(readinessProbe/livenessProbe)整体通过 helpers 中的chart.probestoYaml透传,因此可以按 K8s 标准探针语法追加timeoutSecondssuccessThreshold等字段;探针对应的是 vLLM OpenAI 兼容服务的/health端点。
  • resources.requests.memorycpulimits对应字段在 helpers 的chart.resources中均为required,缺失会导致渲染直接报错。
  • 从 deployment.yaml 的结构看,chart 还支持nodeSelectortolerationsimage.securityContext/image.runAsUser等透传字段(image未显式给出 securityContext 时,默认runAsNonRoot: false),便于把 vLLM 钉到带 GPU 污点容忍的专用节点池。
  • chart 附带 values.schema.json 用于helm侧的值校验,tests/目录下的 deployment_test.yaml、job_test.yaml 等基于 chart-testing 的测试文件验证了 Deployment/Job/PVC 等模板的输出契约,可参考其断言来确认自己 values 的渲染结果是否符合预期。

配置示例

示例一:S3 模型下载(默认方式)

将模型存放在 S3 并调整存储配额:

extraInit: modelDownload: enabled: true pvcStorage: "10Gi" s3modelpath: "models/llama-7b"

安装命令中通过--set secrets.s3endpoint / s3bucketname / s3accesskeyid / s3accesskey提供凭据后,models/llama-7b目录会在 Pod 启动前同步进/data。记得把image.command里的--served-model-name与模型路径改成你的真实模型,并把gpuModels换成节点上nvidia.com/gpu.product标签的实际取值。

示例二:仅使用自定义 Init 容器(如 llm-d 场景)

当不需要 chart 内置的 S3 下载、而要注入自定义 sidecar/init 容器时:

extraInit: modelDownload: enabled: false initContainers: - name: llm-d-routing-proxy image: ghcr.io/llm-d/llm-d-routing-sidecar:v0.2.0 imagePullPolicy: IfNotPresent ports: - containerPort: 8080 name: proxy securityContext: runAsUser: 1000 restartPolicy: Always pvcStorage: "10Gi"

从 deployment.yaml 的条件{{- if and .Values.extraInit (or .Values.extraInit.modelDownload.enabled .Values.extraInit.initContainers) }}看,只要modelDownload.enabledinitContainers任一有值就会渲染 init 容器段;自定义 init 容器追加在wait-download-model之后,PVC 依然会创建并挂载,模型可以通过其它方式(镜像自带、节点预置、对象存储挂载卷等)提前写入。

小结

vLLM 仓库自带的 Helm chart 覆盖了 LLM 服务在 K8s 上落地的完整链路:PVC 承载模型权重、aws-cli Job 拉取权重、init 容器轮询等待、GPU 节点亲和调度、健康探针、滚动更新策略与 HPA/PDB。所有可调项都收敛在 values.yaml 中,配合--set secrets.*注入凭据即可用一条helm upgrade --install完成部署;需要深度定制时,直接阅读 templates 下的对应模板文件就能定位渲染逻辑。

【免费下载链接】vllmA high-throughput and memory-efficient inference and serving engine for LLMs项目地址: https://gitcode.com/GitHub_Trending/vl/vllm

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询