从 Bit 到 AGI第十一章:工程化(Serving)

Kubernetes

从 Bit 到 AGI · 第十一章:工程化(Serving) · LLM 服务的 Kubernetes 部署

作者 David更新于 第 167 篇(共 186 篇)

Ray 解决了应用层编排;Kubernetes(K8s) 解决集群层——GPU 节点池、滚动发布、健康检查、Secret、Ingress。生产 LLM 服务几乎都在 K8s(或等价编排)上跑:每个 vLLM pod 申请 nvidia.com/gpu: 1,HPA 按自定义指标扩缩,Pod Disruption Budget 保证升级时不掉光容量。

直觉

K8s 像数据中心操作系统:你声明「我要 3 个跑 Llama-8B 的容器,每个要 1 张 A100、64 GB 内存」,Scheduler 找满足条件的 Node 并启动 Pod。节点挂了?Controller 自动在别处重建。要发新版权重?Rolling update 逐个替换,旧 pod Drain 前仍接流量。

图表加载中…

定义

LLM on K8s 关键对象:

资源LLM 场景用法
Deployment无状态 vLLM replica,replicas: N
StatefulSet多卡 TP 需固定 pod 身份、RDMA 拓扑时
ServiceClusterIP 负载均衡到 pod
Ingress / Gateway APITLS 终止、路径路由
HPA / KEDA按 QPS、队列长度、GPU SM 利用率扩缩
Device Pluginnvidia.com/gpu 资源上报

生产指标:Pod 就绪时间(含模型 load)、PDB 允许最小可用副本、滚动更新 maxUnavailable。

例子

例 1:vLLM Deployment(8B,单卡)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: llama3-8b-vllm
spec:
  replicas: 3
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0          # 零停机
  template:
    spec:
      containers:
        - name: vllm
          image: vllm/vllm-openai:v0.6.3
          args:
            - --model=meta-llama/Meta-Llama-3-8B-Instruct
            - --max-model-len=8192
            - --gpu-memory-utilization=0.90
          resources:
            limits:
              nvidia.com/gpu: "1"
              memory: "64Gi"
            requests:
              nvidia.com/gpu: "1"
              memory: "48Gi"
          readinessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 120   # 模型 load ~60-90s
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 8000
            initialDelaySeconds: 180
            failureThreshold: 3
      nodeSelector:
        gpu-type: a100-80gb

例 2:70B TP=4 StatefulSet

项配置
Pod 数1(4 容器 sidecar 或 1 pod 4 GPU)
nvidia.com/gpu4
节点单节点 4×A100 + NVLink 全互联
就绪时间~8~12 min(权重 140 GB 拉取 + load)
滚动更新需 second cluster 蓝绿;单 pod TP 无法 rolling

例 3:容量与 SLO

集群 12×A100,每 pod 1 GPU 跑 8B,3 replica 占 3 GPU:

负载QPS所需 podGPU
低峰3022
高峰12055
冗余 + 升级+1 PDB66

剩余 6 GPU 可跑其他模型或 batch job。

量化

Pod 启动预算:

Tready=Tpull image+Tload weights+TwarmupT_{\text{ready}} = T_{\text{pull image}} + T_{\text{load weights}} + T_{\text{warmup}}

8B 从 ACR/ECR:pull ~2 min(镜像 8 GB + 权重 16 GB 若 baked in)+ load ~45 s → readinessProbe initialDelaySeconds 设 ≥ 120。

网络:同 AZ Pod 间 ~0.3 ms RTT;跨 AZ ~2 ms。TP 多 pod 跨 AZ 灾难性(AllReduce 延迟 ×100)——TP pod 必须同节点 / 同 NVLink domain。

成本:K8s 本身不省钱;价值在 利用率——混部离线推理与在线,node pool 自动缩容非高峰 GPU VM。

国内站若用腾讯云 + EdgeOne,回源到 K8s Ingress 的 HTTP 路径与第十一章 Gateway 层配合做限流与鉴权。

常见误区

  1. 「HPA 默认 CPU 指标够用」——LLM pod CPU 常 < 10%(GPU bound);用 KEDA + Prometheus(vLLM avg_generation_tokens_per_s)或 DCGM GPU 利用率。
  2. 「readiness=进程起来」——必须等 /health 返回 200 且能完成一次 dummy inference,否则流量打到 half-loaded 模型。
  3. 「70B 像 8B 一样 rolling update」——TP 多卡单 pod 更新=全中断;用 双池蓝绿 或 新 Deployment 并行 再切流量。

GPU 节点池与拓扑

生产集群按 GPU 型号 + 互联 分 node pool:

Node Pool用途标签
a100-80gb-nvlink-470B TP=4gpu-type=a100-tp4
a100-80gb-single8B 单卡gpu-type=a100-1
l40s-single小模型 / embeddinggpu-type=l40s

Topology Manager(K8s 1.33+ / GPU Operator):TP pod 申请 resources.limits["nvidia.com/gpu"] 时声明 preferred topology——4 GPU 必须同一 PCIe switch 下,否则 NCCL AllReduce 带宽从 600 GB/s 跌到 64 GB/s。

Disruption 预算:

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: llama3-8b-pdb
spec:
  minAvailable: 2
  selector:
    matchLabels:
      app: llama3-8b-vllm

集群升级时至少 2 pod 存活,保证 ~70 QPS 底线。

动手试一试

# minikube / kind 无 GPU 时可 dry-run
kubectl apply --dry-run=client -f llama3-8b-vllm.yaml

# 有 GPU 集群
kubectl apply -f llama3-8b-vllm.yaml
kubectl rollout status deployment/llama3-8b-vllm
kubectl top pods -l app=llama3-8b-vllm

记录从 apply 到 READY 3/3 的 wall time。若 >180 s,检查镜像是否 baked 权重(省 pull)或改用节点本地 cache。

小结

K8s 为 LLM 提供 GPU 调度、零停机发布、HPA 基础;8B vLLM Deployment 需 ~120 s readiness,70B TP=4 宜 StatefulSet + 蓝绿。下一篇 LiteLLM 在 K8s 之上统一多模型、多厂商 API。

→ 下一篇:LiteLLM

本页目录