🎉 基于 Docker + Kubernetes + Helm 的 vLLM 推理服务部署与灰度发布(Canary)实战

从零开始,使用现代云原生技术栈完成 AI 推理服务的 容器化 → 声明式部署 → 自动扩缩 → Istio 灰度发布 的全流程。


✅ 一、整体目标以及技术栈总览

序号目标
1将 vLLM 模型推理服务容器化
2使用 Helm Chart 封装部署
3配置 HPA 自动扩缩容
4实现 Istio 流量治理与 10% 流量灰度发布(Canary)
5验证流量按权重分发
技术安装方式作用
Dockersudo yum install docker 或 brew install docker构建 & 运行容器,将 vLLM 服务打包成镜像
Minikubecurl -LO https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64本地单节点 Kubernetes 集群,用于开发测试
kubectlcurl -LO "https://dl.k8s.io/release/$(curl -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl"K8s 命令行工具,管理所有资源
Helm`curl https://raw.githubusercontent.com/helm/helm/main/scripts/get-helm-3bash`
Istioistioctl install --set profile=demo -y服务网格,流量治理、灰度发布、可观测性
vLLMpip install vllm + 自定义 Flask高性能大模型推理引擎,暴露 /v1/completions

🚀 二、完整操作流程(Step by Step)

🔹 第一步:构建 Docker 镜像(本地)

1. 编写 Dockerfile
# Dockerfile.vllm
FROM nvcr.io/nvidia/pytorch:23.10-py3  # 官方 NVIDIA 镜像,支持 GPU

# 安装 vLLM
RUN pip install vllm==0.4.0  # 建议固定版本

# 暴露端口
EXPOSE 8000

# 启动命令(根据你的模型调整)
CMD ["python", "-m", "vllm.entrypoints.openai.api_server", \
     "--host", "0.0.0.0", \
     "--port", "8000", \
     "--model", "meta-llama/Llama-3-8b-instruct" ]
2. 构建 & 推送
docker build -f Dockerfile.vllm -t your-registry/vllm:latest .
docker tag mock-vllm:latest your-registry/mock-vllm:v0.1-mock
docker push your-registry/mock-vllm:v0.1-mock

💡 学到:如何为大模型推理服务定制轻量级镜像


🔹 第二步:编写 Helm Chart 结构

helm create vllm-chart
目录结构
vllm-chart/
├── charts/
├── templates/
│   ├── deployment-v1.yaml
│   ├── deployment-v2.yaml
│   ├── service.yaml
│   ├── hpa.yaml
│   ├── destinationrule.yaml
│   ├── virtualservice.yaml
│   └── gateway.yaml
├── values.yaml
└── Chart.yaml

💡 学到:Helm 是声明式部署的利器,适合管理复杂应用


🔹 第三步:定义资源对象

1. Deployment(v1 & v2)
  • v1:稳定版本,version: v1
  • v2:新版本,version: v2
2. Service(必须命名端口为 http)
selector:
  app: vllm
ports:
  - port: 80
    targetPort: 8000
    name: http   # 必须命名 http 才能被 Istio 路由
3. HPA(自动扩缩容)

helm的values.yaml需要配置一下内容

autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 10
  targetCPUUtilizationPercentage: 50  # CPU >50% 就扩容
  targetMemoryUtilizationPercentage: 80

image:
  repository: your-registry/mock-vllm        # ← 改成你的镜像名
  tag: v0.1-mock                  # ← 镜像标签
  pullPolicy: IfNotPresent     # ← 本地镜像用这个

💡 学到:HPA 可根据 CPU/内存/自定义指标自动伸缩 Pod 数量


🔹 第四步:使用 Istio 实现灰度发布

1. DestinationRule:定义 subset
# destination-rule.yaml
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: vllm-destination-rule
spec:
  host: vllm-service
  subsets:
  - name: v1
    labels:
      version: v1
  - name: v2
    labels:
      version: v2
2. VirtualService:90/10 流量切分
# virtual-service-canary.yaml
apiVersion: networking.istio.io/v1
kind: VirtualService
metadata:
  name: vllm-virtual-service
spec:
  hosts:
  - vllm-service
  gateways:
  - vllm-gateway
  http:
  - route:
    - destination:
        host: vllm-service
        subset: v1
      weight: 90
    - destination:
        host: vllm-service
        subset: v2
      weight: 10
3. Gateway:入口网关(关键!)
apiVersion: networking.istio.io/v1
kind: Gateway
metadata:
  name: vllm-gateway
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 80
      name: http
      protocol: HTTP
    hosts:
    - vllm-service.default.svc.cluster.local   # 必须是 FQDN!

⚠️ 重点:

  • short names(如 vllm-service)会被 Istio 拒绝
  • 必须使用 FQDN:<svc>.<ns>.svc.cluster.local
  • name: http 是 Istio 路由的前提

🔹 第五步:部署并验证

1. 一键安装
helm install vllm-release ./vllm-chart
2. 获取网关地址
export GATEWAY_URL=$(minikube ip):$(kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
3. 发送测试请求(带 Host 头)
for i in {1..20}; do
  curl -s -X POST "http://$GATEWAY_URL/v1/completions" \
    -H "Host: vllm-service.default.svc.cluster.local" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "hello", "max_tokens": 1}' -w "\n"
done

🔹 第六步:观察结果

查看网关日志
kubectl logs -n istio-system -l app=istio-ingressgateway -c istio-proxy --tail=20
✅ 成功看到:
  • 200 响应
  • outbound 80 v1 ... 和 outbound 80 v2 ...
  • v1 接收 ~90%,v2 接收 ~10%

📚 三、核心知识点总结

技术学到的关键点
Docker如何为 Python AI 服务构建高效镜像,注意基础镜像选择与依赖管理
KubernetesPod、Service、Deployment、HPA 的协同工作机制
Helm使用模板化方式管理复杂应用部署,提升可复用性
Istio流量路由、subset、gateway、virtualservice 协同机制
灰度发布通过 weight 实现 Canary 发布,降低上线风险
FQDNIstio 安全策略要求必须使用全限定域名,否则报 short names not allowed
Service 端口命名必须为 name: http,否则 Istio 不做 HTTP 路由

📸 四、推荐截图命令

目的命令截图说明
查看所有资源状态kubectl get all -l app=vllm展示 v1 和 v2 的 Pod 正常运行在这里插入图片描述
查看 HPA 状态kubectl get hpa展示 CPU 使用率和副本数变化在这里插入图片描述
查看 Service & Endpointkubectl get svc vllm-service -o wide
kubectl get endpoints vllm-service
确认服务发现正常在这里插入图片描述
查看 Istio 资源kubectl get gateway,virtualservice,destinationrule -o wide确认 hosts 和 weights 正确在这里插入图片描述
查看网关日志kubectl logs -n istio-system -l app=istio-ingressgateway -c istio-proxy --tail=20v1 10.244.0.27/v2 10.244.0.25在这里插入图片描述

🛣️ 五、完整请求路径(从外部到 Pod)

[你的终端]
curl -H "Host: vllm-service.default.svc.cluster.local" \
     http://192.168.49.2:31502/v1/completions
↓
Minikube NodePort (31502 → 80)
↓
Istio Ingress Gateway (istio-ingressgateway Pod)
↓
Gateway 允许该 Host
↓
VirtualService 按权重路由:
  90% → subset: v1
  10% → subset: v2
↓
DestinationRule 找到对应标签的 Pod
↓
Service (vllm-service) 做负载均衡
↓
Pod v1 或 v2 (Flask+vLLM)
↓
返回推理结果

🔍 关键点

  • Host 头必须是 FQDN
  • Gateway 放行该 Host
  • VirtualService 定义权重
  • DestinationRule 定义 subset
  • Service 负责 Pod 负载均衡

🖼️ 六、系统架构图(文字版)

+---------------------------+
|      你的终端             |
|  curl -H "Host: ..."      |
+-----------+---------------+
            |
            | HTTP
            v
+-----------+---------------+
|   Minikube NodePort       |
|   31502 → 80 (Gateway)    |
+-----------+---------------+
            |
            v
+-----------+---------------+
| Istio Ingress Gateway     |
|  (istio-proxy sidecar)    |
+-----------+---------------+
            |
            | 路由决策
            v
+-----------+---------------+     +----------------------+
|      VirtualService       |---->| DestinationRule      |
|  hosts: vllm-service      |     |  subsets: v1, v2     |
|  weight: 90/10            |     +----------------------+
+-----------+---------------+
            |
            v
+-----------+---------------+
|   Service: vllm-service   |
|   selector: app=vllm      |
+-----------+---------------+
            |
    +-------+-------+
    |               |
    v               v
+---+-----+   +-----+---+
| Pod v1  |   | Pod v2  |
| vllm:v1 |   | vllm:v2 |
+---------+   +---------+

🎯 七、经验教训 & 最佳实践

  1. Istio 的 Host 必须是 FQDN,否则 admission webhook denied
  2. Service 端口必须命名为 http,否则不走 HTTP 路由
  3. Gateway 必须放行 VirtualService 的 hosts
  4. VirtualService 的 gateways: 必须引用存在的 Gateway
  5. 测试时 Host 头必须匹配 Gateway 的 hosts
  6. 使用 Helm 可大幅减少 YAML 管理成本


🌟 总结一句话

使用现代云原生技术栈(Docker+K8s+Helm+Istio)部署、扩缩、灰度发布一个 AI 推理服务的全流程,具备生产级交付能力!


🌐 终极总结:云原生 AI 推理服务技术栈与请求路径全解析

一份涵盖 技术栈 → 安装方式 → 组件作用 → 请求路径 → 架构图 的终极速查表,用于写文档、做汇报、画架构图。


更多推荐