ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

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

2026/9/5 19:57:47 拓冰建站 浏览量
使用 Helm 在 Kubernetes 上部署 vLLM 推理服务:安装步骤、values 配置详解与模型自动下载原理 使用 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 目录结构 可以看到这个 chartChart.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存放模型权重的持久化存储ReadWriteOncetemplates/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 写入 PVCDeployment 主容器把 PVC 挂载到/data容器内执行vllm serve /data/启动 OpenAI 兼容服务Service 将流量导入 Pod。前置条件在开始之前确保你具备以下条件引自 Helm 文档一个可用的 Kubernetes 集群NVIDIA Kubernetes Device Plugink8s-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 \ --namespacens-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 --namespacens-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 --namespacens-vllm文档特别强调该命令会删除 chart 关联的所有 Kubernetes 组件包括持久卷PVC并删除 release。也就是说test-vllm-storage-claim这个 PVC 会被一并移除模型权重不会保留重新部署时需要再次下载。主容器与 Deployment源码级细节渲染逻辑集中在 templates/deployment.yaml 与 templates/_helpers.tpl 中几个关键实现细节镜像与启动命令。主容器镜像为{{ .Values.image.repository }}:{{ .Values.image.tag }}默认vllm/vllm-openai:latest。image.repository与image.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。实际部署时替换为你的模型路径与参数即可。模型存储挂载。主容器把{{ .Release.Name }}-storage卷指向 PVC{{ .Release.Name }}-storage-claim挂载到/data与vllm serve /data/形成闭环。GPU 调度。当resources.requests与resources.limits中nvidia.com/gpu均大于 0 时模板会自动追加runtimeClassName: nvidia并生成基于节点标签nvidia.com/gpu.product的nodeAffinity候选值取自gpuModels列表默认占位符TYPE_GPU_USED必须替换成实际卡型如 A10G/H100 对应的 product 标签值。这也解释了前置条件中要求安装 NVIDIA Device Plugin——没有插件就没有nvidia.com/gpu资源可请求。副本数与更新策略。replicas来自replicaCount默认 1deploymentStrategy未配置时helpers 中的chart.strategy默认使用rollingUpdate: maxSurge 100% / maxUnavailable 0的零中断滚动更新且 Deployment 的progressDeadlineSeconds为 1200 秒为 vLLM 这类大模型容器拉镜像、加载权重的慢启动留出余量。环境变量注入。若配置了configs/secrets/externalConfigs模板通过envFrom引用{{ .Release.Name }}-configsConfigMap 与{{ .Release.Name }}-secretsSecret。这意味着所有 S3 凭据最终都以环境变量形式进入容器见下一节也可以借此注入VLLM_*系列环境变量给 vLLM 主进程。模型自动下载机制Job 等待 init 容器这是该 chart 默认开启extraInit.modelDownload.enabled: true的核心机制由两个协作者构成下载 Jobtemplates/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_URL、S3_BUCKET_NAME、AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY四个变量分别通过secretKeyRef从{{ .Release.Name }}-secrets中读取s3endpoint、s3bucketname、s3accesskeyid、s3accesskey四个键——这正是安装命令里那四个--set secrets.*的落点S3_PATH则直接取自extraInit.s3modelpath。此外若extraInit.awsEc2MetadataDisabled有定义默认true还会注入AWS_EC2_METADATA_DISABLED避免在 EKS 之外的云环境如自建集群、GCP/Azure上 aws-cli 反复查询 EC2 元数据服务导致启动变慢。注意一旦显式配置了waitContainer.env或downloadJob.env模板会整体替换默认的 S3 变量组适合改用 Hugging Face 等其它下载方式。PVC、Service、HPA 与 PDBPVCtemplates/pvc.yaml只要extraInit有值就渲染容量取自extraInit.pvcStorage默认1Gi只够 opt-125m 演示模型部署 7B 级以上模型务必调大如10Gi访问模式固定为ReadWriteOnce。Servicetemplates/service.yaml固定ClusterIP类型servicePort默认 80映射到容器端口名container-port即containerPort默认 8000与--port 8000对应。serviceName为空时默认命名{{ .Release.Name }}-service。HPAtemplates/hpa.yamlautoscaling.enabled: true时渲染autoscaling/v2HPA支持 CPUtargetCPUUtilizationPercentage默认 80与内存targetMemoryUtilizationPercentagevalues 中默认注释两个 Resource 指标副本数在minReplicas默认 1到maxReplicas默认 100之间伸缩。PDBtemplates/poddisruptionbudget.yamlmaxUnavailable默认 1保障节点维护等自愿中断期间的服务可用性。ConfigMap / Secretsconfigs默认{}渲染为{{ .Release.Name }}-configssecrets渲染为 base64 编码的 Opaque Secret。自定义资源customObjects列表中的每一项都会以 Helm 模板语法渲染成独立 K8s 对象方便追加 Ingress、InferenceService 等任意资源。values 参数完整说明以下表格完整收录 Helm 文档 中values.yaml的可配置参数KeyTypeDefaultDescriptionautoscalingobject{enabled:false,maxReplicas:100,minReplicas:1,targetCPUUtilizationPercentage:80}Autoscaling configurationautoscaling.enabledboolfalseEnable autoscalingautoscaling.maxReplicasint100Maximum replicasautoscaling.minReplicasint1Minimum replicasautoscaling.targetCPUUtilizationPercentageint80Target CPU utilization for autoscalingconfigsobject{}ConfigmapcontainerPortint8000Container portcustomObjectslist[]Custom Objects configurationdeploymentStrategyobject{}Deployment strategy configurationexternalConfigslist[]External configurationextraContainerslist[]Additional containers configurationextraInitobject{modelDownload:{enabled:true},initContainers:[],pvcStorage:1Gi}Additional configuration for init containersextraInit.modelDownloadobject{enabled:true}Model download functionality configurationextraInit.modelDownload.enabledbooltrueEnable automatic model download job and wait containerextraInit.modelDownload.imageobject{repository:amazon/aws-cli,tag:2.6.4,pullPolicy:IfNotPresent}Image for model download operationsextraInit.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.pvcStoragestring1GiStorage size for the PVCextraInit.s3modelpathstringrelative_s3_model_path/opt-125m(Optional) Path of the model on S3extraInit.awsEc2MetadataDisabledbooltrue(Optional) Disable AWS EC2 metadata serviceextraPortslist[]Additional ports configurationgpuModelslist[TYPE_GPU_USED]Type of gpu usedimageobject{command:[vllm,serve,/data/,--served-model-name,opt-125m,--host,0.0.0.0,--port,8000],repository:vllm/vllm-openai,tag:latest}Image configurationimage.commandlist[vllm,serve,/data/,--served-model-name,opt-125m,--host,0.0.0.0,--port,8000]Container launch commandimage.repositorystringvllm/vllm-openaiImage repositoryimage.tagstringlatestImage taglivenessProbeobject{failureThreshold:3,httpGet:{path:/health,port:8000},initialDelaySeconds:15,periodSeconds:10}Liveness probe configurationlivenessProbe.failureThresholdint3Number of times after which if a probe fails in a row, Kubernetes considers that the overall check has failed: the container is not alivelivenessProbe.httpGetobject{path:/health,port:8000}Configuration of the kubelet http request on the serverlivenessProbe.httpGet.pathstring/healthPath to access on the HTTP serverlivenessProbe.httpGet.portint8000Name or number of the port to access on the container, on which the server is listeninglivenessProbe.initialDelaySecondsint15Number of seconds after the container has started before liveness probe is initiatedlivenessProbe.periodSecondsint10How often (in seconds) to perform the liveness probemaxUnavailablePodDisruptionBudgetstringDisruption Budget ConfigurationreadinessProbeobject{failureThreshold:3,httpGet:{path:/health,port:8000},initialDelaySeconds:5,periodSeconds:5}Readiness probe configurationreadinessProbe.failureThresholdint3Number of times after which if a probe fails in a row, Kubernetes considers that the overall check has failed: the container is not readyreadinessProbe.httpGetobject{path:/health,port:8000}Configuration of the kubelet http request on the serverreadinessProbe.httpGet.pathstring/healthPath to access on the HTTP serverreadinessProbe.httpGet.portint8000Name or number of the port to access on the container, on which the server is listeningreadinessProbe.initialDelaySecondsint5Number of seconds after the container has started before readiness probe is initiatedreadinessProbe.periodSecondsint5How often (in seconds) to perform the readiness probereplicaCountint1Number of replicasresourcesobject{limits:{cpu:4,memory:16Gi,nvidia.com/gpu:1},requests:{cpu:4,memory:16Gi,nvidia.com/gpu:1}}Resource configurationresources.limits.nvidia.com/gpuint1Number of GPUs usedresources.limits.cpuint4Number of CPUsresources.limits.memorystring16GiCPU memory configurationresources.requests.nvidia.com/gpuint1Number of GPUs usedresources.requests.cpuint4Number of CPUsresources.requests.memorystring16GiCPU memory configurationsecretsobject{}Secrets configurationserviceNamestringService nameservicePortint80Service portlabels.environmentstringtestEnvironment name结合仓库源码补充几点文档表格之外的实现事实两个探针readinessProbe/livenessProbe整体通过 helpers 中的chart.probes以toYaml透传因此可以按 K8s 标准探针语法追加timeoutSeconds、successThreshold等字段探针对应的是 vLLM OpenAI 兼容服务的/health端点。resources.requests.memory、cpu与limits对应字段在 helpers 的chart.resources中均为required缺失会导致渲染直接报错。从 deployment.yaml 的结构看chart 还支持nodeSelector、tolerations与image.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.enabled或initContainers任一有值就会渲染 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),仅供参考