4、K8s核心概念回顾:Pod、Deployment、Service、ConfigMap、Secret

说实话,很多朋友一上来就问我:「老师,vLLM 热加载到底怎么搞?」

我通常会反问一句:「K8s 这几个核心概念,你心里有数吗?」

不是我要卖关子。而是我踩过太多坑了——有一次在生产环境里,就因为搞混了 Pod 和 Deployment 的生命周期,导致模型热加载脚本跑了一半,Pod 被重新调度了。嗯,那场面,挺尴尬的。

所以这一章,咱们不急着写 YAML。先把地基打牢。你想想看,K8s 里跑 vLLM,说白了就是管理一堆「装了大模型的容器」。而 Pod、Deployment、Service、ConfigMap、Secret,就是管理这些容器的五把钥匙。

一句话总结:Pod 是跑模型的「小盒子」,Deployment 是管盒子的「自动售货机」,Service 是给盒子发「门牌号」的,ConfigMap 和 Secret 是给盒子塞「说明书」和「密码本」的。

4.1 Pod:最小的调度单元

Pod 是 K8s 里你能直接操作的最小单位。一个 Pod 里可以有一个或多个容器。对于 vLLM 来说,通常一个 Pod 里就放一个推理容器。

我个人习惯把 Pod 想象成一个「微型服务器」。它有自己的 IP、端口、存储卷。但有个特点——Pod 是临时性的。它挂了,K8s 不会自动复活它。

我的经验:在 vLLM 热加载场景下,Pod 的 restartPolicy 一定要设成 OnFailureAlways。我曾经设成 Never,结果模型加载到一半 OOM,Pod 直接死在那了,还得手动删。

一个典型的 vLLM Pod 定义大概长这样:

apiVersion: v1
kind: Pod
metadata:
  name: vllm-gpu-pod
spec:
  containers:
  - name: vllm
    image: vllm/vllm-openai:latest
    args: ["--model", "/models/llama-3-8b"]
    resources:
      limits:
        nvidia.com/gpu: 1
    volumeMounts:
    - name: model-storage
      mountPath: /models
  volumes:
  - name: model-storage
    persistentVolumeClaim:
      claimName: model-pvc

注意看,这里我直接指定了 GPU 资源。没有 GPU,vLLM 跑不起来的,这是硬门槛。

4.2 Deployment:让 Pod 永不掉线

Pod 太脆弱了。你想想看,生产环境里模型推理服务要是因为节点故障挂了,用户那边直接报 503。怎么办?

Deployment 就是干这个的。它负责声明「我要跑几个 Pod 副本」,然后 K8s 的控制器会拼命维持这个数量。

避坑指南:我曾经在 Deployment 里设了 replicas: 1,然后做滚动更新。结果新 Pod 启动失败,旧 Pod 又被缩容了,服务直接中断了 3 分钟。后来我学乖了,热加载场景下一定要用 maxSurge: 1maxUnavailable: 0

Deployment 的核心价值在于:

  • 声明式更新:你只管说「我要用新镜像」,它自动滚动替换
  • 自愈能力:Pod 挂了,它自动再起一个
  • 版本回滚:新模型有问题?kubectl rollout undo 一键回去

对于 vLLM 热加载,Deployment 的 strategy 配置很关键:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: vllm-deployment
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: vllm
  template:
    metadata:
      labels:
        app: vllm
    spec:
      containers:
      - name: vllm
        image: vllm/vllm-openai:latest

这里 maxUnavailable: 0 的意思是:更新过程中,绝对不能有 Pod 不可用。说白了就是「先起新的,再停旧的」。这对推理服务来说太重要了。

4.3 Service:稳定的访问入口

Pod 的 IP 是会变的。Deployment 滚动更新一次,所有 Pod 的 IP 全换了。客户端总不能每次都去查 DNS 吧?

Service 就是解决这个问题的。它提供一个固定的虚拟 IP(ClusterIP),然后通过标签选择器把流量转发到后端的 Pod 上。

我建议:vLLM 推理服务一定要用 ClusterIP 类型的 Service。除非你要对外暴露,才用 NodePortLoadBalancer。内部调用走 ClusterIP,延迟最低。

一个简单的 Service 定义:

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

这里 selector 匹配了 Deployment 里 Pod 的标签 app: vllm。流量进来后,K8s 会自动负载均衡到所有匹配的 Pod 上。

为什么会用到 Service?你想想看,热加载模型时,你可能要同时跑新旧两个版本的 Pod。Service 会自动把流量分到两个版本上,等新版本稳定了,再切走旧版本。这就是蓝绿部署的雏形。

4.4 ConfigMap:配置与模型解耦

vLLM 的启动参数很多:模型路径、tensor-parallel-size、max-model-len、gpu-memory-utilization……这些参数如果硬编码在镜像里,每次改参数都得重新打包镜像。太蠢了。

ConfigMap 就是用来存这些配置的。它本质上是键值对,可以挂载成文件,也可以注入成环境变量。

我的做法:把 vLLM 的启动参数全部放到 ConfigMap 里。这样热加载新模型时,只需要更新 ConfigMap,然后触发 Deployment 滚动更新就行。镜像本身不用动。

示例:

apiVersion: v1
kind: ConfigMap
metadata:
  name: vllm-config
data:
  model: /models/llama-3-8b
  tensor-parallel-size: "2"
  max-model-len: "4096"
  gpu-memory-utilization: "0.9"

然后在 Deployment 里引用:

envFrom:
- configMapRef:
    name: vllm-config

或者挂载成文件:

volumeMounts:
- name: config
  mountPath: /etc/vllm
volumes:
- name: config
  configMap:
    name: vllm-config

注意:ConfigMap 更新后,Pod 里的环境变量不会自动刷新。你需要手动重启 Pod,或者用 Reloader 这类工具自动监听变化。我曾经因为这个坑,调试了整整一个下午。

4.5 Secret:敏感信息的保险箱

模型推理服务有时候需要访问私有仓库、Hugging Face Token、或者数据库密码。这些信息绝对不能明文写在 YAML 里。

Secret 和 ConfigMap 很像,但它的值是 base64 编码的。K8s 会保证 Secret 在 etcd 中是加密存储的(如果开启了加密)。

一个典型的 Secret:

apiVersion: v1
kind: Secret
metadata:
  name: hf-token
type: Opaque
data:
  token: aGZfYmxhaGJsYWhibGFo  # 这是 base64 编码后的假 token

在 Pod 里使用:

env:
- name: HUGGING_FACE_HUB_TOKEN
  valueFrom:
    secretKeyRef:
      name: hf-token
      key: token

我的习惯:永远不要在代码里硬编码 Secret。哪怕只是测试环境。我见过有人把生产环境的数据库密码写在 GitHub 上,那画面……嗯,你懂的。

4.6 知识体系总览

说了这么多,咱们用一张图来串一下这几个概念的关系。我画了一张 SVG,帮你理清思路:

K8s 核心概念关系图(vLLM 视角) ConfigMap 启动参数、模型路径 Secret Token、密码、密钥 Pod vLLM 推理容器 Deployment 管理 Pod 副本数 Service 固定访问入口 注入配置 注入密钥 管理/调度 流量转发 Pod 是核心,Deployment 管生命周期,Service 管网络入口 ConfigMap 和 Secret 为 Pod 提供配置和敏感数据 图例 配置/密钥类资源 核心工作负载 管理控制器 网络抽象层

这张图你看懂了吗?说白了,Pod 是跑 vLLM 的「小盒子」,Deployment 是「管家」,Service 是「门牌号」,ConfigMap 和 Secret 是「说明书和密码本」。五者配合,才能让模型推理服务稳定、安全、可配置。

4.7 小结

这一章我们回顾了 K8s 的五个核心概念。每个概念在 vLLM 热加载场景下都有它的独特作用:

  • Pod:承载 vLLM 容器,是模型推理的最小运行单元
  • Deployment:保证 Pod 数量,支持滚动更新和回滚
  • Service:提供稳定的网络入口,屏蔽 Pod IP 变化
  • ConfigMap:管理模型路径和启动参数,实现配置与镜像解耦
  • Secret:安全存储 Token 和密码,避免敏感信息泄露

嗯,地基打好了。后面咱们就可以放心地往上盖楼了。


专注资料整理