3、环境搭建:在 K8s 集群中部署 vLLM 推理服务(Docker 镜像 + YAML 配置)

好,咱们直接进入正题。上一章我们把 K8s 集群搭起来了,现在要让它真正跑起来——把 vLLM 推理服务部署上去。说白了,就是两步:先搞定 Docker 镜像,再写好 YAML 配置。我刚开始接触这套流程时,总觉得 YAML 写起来像玄学,后来踩了几个坑才摸清门道。

3.1 构建 vLLM 推理镜像

我个人习惯,先把镜像构建流程跑通。vLLM 官方提供了 Dockerfile,但直接拿来用可能会遇到 CUDA 版本不匹配的问题。我在项目中遇到过,镜像拉下来后,GPU 驱动版本对不上,推理速度直接掉到三分之一。

这里我建议你基于官方镜像二次构建。先拉取基础镜像:

docker pull vllm/vllm-openai:latest

然后写一个简单的 Dockerfile,把模型文件打包进去。为什么要打包?你想想看,每次启动都从 HuggingFace 下载模型,网络波动一下就得重来,生产环境根本扛不住。

FROM vllm/vllm-openai:latest

# 把本地下载好的模型拷贝进去
COPY ./models/Qwen2-7B-Instruct /models/Qwen2-7B-Instruct

# 设置默认启动参数
ENTRYPOINT ["python3", "-m", "vllm.entrypoints.openai.api_server"]
CMD ["--model", "/models/Qwen2-7B-Instruct", "--port", "8000"]

构建镜像时注意标签规范。我习惯用 项目名-模型名:日期 的格式,方便回滚。

docker build -t my-inference/qwen2-7b:20240501 .
小提示: 如果你用的是私有仓库,记得先 docker login。我见过有人镜像构建好了,推不上去,排查半天发现是没登录。

3.2 推送镜像到仓库

镜像构建好之后,得推送到 K8s 节点能拉取到的仓库。我一般用 Harbor 或者阿里云镜像仓库。命令很简单:

docker tag my-inference/qwen2-7b:20240501 registry.example.com/my-inference/qwen2-7b:20240501
docker push registry.example.com/my-inference/qwen2-7b:20240501

嗯,这里要注意一点:镜像大小。vLLM 镜像加上模型,动不动就 10GB+。推送前最好确认下网络带宽,我曾经在办公室网络推了半小时没推完,最后改用内网仓库才搞定。

3.3 编写 Deployment YAML

镜像准备好了,接下来就是 K8s 的核心——YAML 配置。我把它分成三块:Deployment、Service、ConfigMap。先看 Deployment:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-inference
  namespace: ai-infra
spec:
  replicas: 2
  selector:
    matchLabels:
      app: vllm-inference
  template:
    metadata:
      labels:
        app: vllm-inference
    spec:
      containers:
      - name: vllm
        image: registry.example.com/my-inference/qwen2-7b:20240501
        ports:
        - containerPort: 8000
        resources:
          requests:
            nvidia.com/gpu: 1
            memory: "32Gi"
            cpu: "8"
          limits:
            nvidia.com/gpu: 1
            memory: "64Gi"
            cpu: "16"
        env:
        - name: CUDA_VISIBLE_DEVICES
          value: "0"
        volumeMounts:
        - name: model-cache
          mountPath: /root/.cache/huggingface
      volumes:
      - name: model-cache
        hostPath:
          path: /data/model-cache
          type: DirectoryOrCreate
关键点解析:
  • nvidia.com/gpu: 1 表示每个 Pod 申请 1 张 GPU。别贪多,一张卡跑一个模型实例最稳。
  • 内存申请 32Gi,限制 64Gi。vLLM 推理时,显存不够会 spill 到内存,留点余量。
  • hostPath 挂载模型缓存,避免每次重启都重新下载。

3.4 编写 Service 和 ConfigMap

Deployment 只管跑 Pod,要让外部能访问,还得配 Service。我习惯用 ClusterIP 类型,内部服务间调用足够了。

apiVersion: v1
kind: Service
metadata:
  name: vllm-service
  namespace: ai-infra
spec:
  selector:
    app: vllm-inference
  ports:
  - protocol: TCP
    port: 8000
    targetPort: 8000
  type: ClusterIP

ConfigMap 用来管理推理参数。为什么要单独拎出来?你想想看,每次调参都要改 YAML 重新部署,多麻烦。把参数抽出来,改 ConfigMap 后重启 Pod 就行。

apiVersion: v1
kind: ConfigMap
metadata:
  name: vllm-config
  namespace: ai-infra
data:
  max-model-len: "4096"
  gpu-memory-utilization: "0.9"
  tensor-parallel-size: "1"
避坑指南: 我曾经把 gpu-memory-utilization 设成 0.95,结果模型加载时直接 OOM。建议从 0.8 开始调,稳定后再往上加。

3.5 部署与验证

配置写好了,执行部署命令:

kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f configmap.yaml

查看 Pod 状态:

kubectl get pods -n ai-infra -w

等 Pod 变成 Running 状态后,测试一下推理接口:

# 先端口转发到本地
kubectl port-forward -n ai-infra pod/vllm-inference-xxx 8000:8000

# 测试推理
curl http://localhost:8000/v1/completions \
  -H "Content-Type: application/json" \
  -d '{
    "model": "/models/Qwen2-7B-Instruct",
    "prompt": "你好,请介绍一下你自己",
    "max_tokens": 100
  }'

如果返回了正常的 JSON 响应,恭喜你,部署成功了!

3.6 知识体系总览

为了让你对整个流程有个直观认识,我画了张图:

vLLM 推理服务部署流程 ① 构建 Docker 镜像 vllm/vllm-openai:latest ② 推送至镜像仓库 Harbor / 阿里云 ③ 编写 YAML 配置 Deployment + Service ④ kubectl apply 部署到 K8s 集群 ⑤ 验证推理服务 curl 测试接口 ⑥ 持续调优 调整 ConfigMap 参数 核心组件:Docker + K8s Deployment + Service + ConfigMap GPU 资源管理:nvidia.com/gpu 显式声明

这张图把整个部署流程串起来了。从镜像构建到最终调优,每一步都有它的意义。我个人觉得,最容易被忽略的是 ConfigMap 那一步——很多人直接把参数写死在代码里,后面改起来想哭。

我的经验: 部署完成后,建议先跑一个简单的压力测试,看看 GPU 利用率是否达到 80% 以上。如果利用率低,可能是 tensor-parallel-size 没配好,或者模型加载参数有问题。

好了,环境搭建这块就讲到这里。你按照这个流程走一遍,应该能顺利把 vLLM 推理服务跑起来。记住,镜像构建要细心,YAML 配置要规范,验证测试不能省。


专注资料整理