news 2026/9/2 15:54:20

AI Infra实战07(上):在K8s部署KServe,把大模型跑成推理服务

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
AI Infra实战07(上):在K8s部署KServe,把大模型跑成推理服务

AI Infra实战07(上):在K8s部署KServe,把大模型跑成推理服务

本篇配套的全部脚本、YAML 和 Terraform 配置已开源在 GitHub:https://github.com/Jich1123/gpu-k8s-lab 。clone 下来可按顺序复现全部实验(仓库不含任何真实 IP、密钥或账号信息)。

本篇目标

第03到05篇,我们用 vLLM 把大模型跑起来,也用 Helm 把它部署进了 K8s。但那还是把模型当成一个普通服务在管。到了 KServe,思路变了:你不再自己拼 Deployment、Service、Ingress,而是只声明一个 InferenceService,平台帮你把这一整套配齐。

这篇是 KServe 实战的上篇,目标是从零把控制面搭起来,最终用一个 InferenceService 把 Qwen 跑成 OpenAI 兼容接口。

学完本篇你会掌握:

  • 为什么宿主机能看到 GPU,K8s 却调度不了,以及 GPU Operator 到底装了什么
  • k3s、cert-manager、Istio、KServe 各自的角色和安装顺序
  • KServe 0.20 一个容易卡住的真实坑:默认不带 ServingRuntime
  • 提交一个 InferenceService 后,KServe 自动生成了哪些资源
  • 用 OpenAI 兼容接口调用真实模型

证据等级:B级实验复现。本篇命令、输出和结果来自一次真实执行(AWS g4dn.2xlarge / T4 16GB,us-east-1)。


实操环境

配置
平台AWS EC2 g4dn.2xlarge
GPUTesla T4(16GB显存)
系统Ubuntu 22.04.5 LTS
驱动595.84 / CUDA 13.2(宿主机预装)
k3sv1.34.10+k3s1
GPU Operatorv26.3.3
cert-managerv1.21.1
Istio1.28.10
KServev0.20.0
模型Qwen/Qwen2.5-0.5B-Instruct

为什么用 g4dn.2xlarge 而不是前几篇的 g4dn.xlarge:KServe 要叠加 cert-manager、Istio、KServe 控制面,还有下篇的 Knative,组件多,16GB 内存偏紧。8 vCPU / 32GB 的 g4dn.2xlarge 更稳。这也需要 AWS 的 G/VT 实例配额达到 8 vCPU。


为什么要装 GPU Operator:宿主机能看到 GPU,不等于 K8s 能调度 GPU

这是很多人第一次在 K8s 上跑 GPU 时最容易困惑的地方,先讲清楚。

宿主机上nvidia-smi正常,只说明一件事:这台机器的驱动装好了,操作系统能用 GPU。但 K8s 的调度器并不直接看硬件,它只认「资源」。默认情况下,节点的可分配资源里只有 cpu、memory 这些,并没有 GPU。

也就是说:

宿主机 nvidia-smi 正常 → 机器能用 GPU K8s 节点 Allocatable 无 gpu → 调度器不知道有 GPU 结果:GPU 的 Pod 会一直 Pending

要让 K8s 能把 GPU 当成资源调度出去,需要 NVIDIA GPU Operator。它不是单一组件,而是一套:

组件作用
GPU 驱动宿主机的 NVIDIA 驱动(我们已预装 595.84,不用它再装)
Container Toolkit让容器运行时能访问 GPU
Device Plugin把 GPU 注册成 K8s 资源 nvidia.com/gpu(关键)
GPU Feature Discovery给节点打 GPU 相关标签
DCGM ExporterGPU 监控指标(第02篇用过)

其中最关键的是 Device Plugin。没有它,kubectl describe node里就没有nvidia.com/gpu,KServe 的模型 Pod 拿不到 GPU。

所以本篇的安装策略是:驱动不用再装(宿主机已有),但 GPU Operator 要装,用它的 Device Plugin 把 GPU 接入 K8s。这就是下面 GPU Operator 用 preinstalled 驱动模式的原因。


组件栈与安装顺序

整套控制面从下到上是这样堆起来的,每一层都依赖下一层:

组件职责
1k3s轻量 Kubernetes,集群底座
2GPU Operator让 K8s 能调度 GPU
3cert-manager给 KServe 的 webhook 签发证书
4IstioKServe 的网关,负责对外路由
5KServe模型服务平台,本篇主角

下面按这个顺序装。每步只贴关键片段,完整脚本在 GitHub 仓库的07-kserve/scripts/下。


第一步:装 k3s

k3s 安装有两个决策要说清楚:

curl-sfLhttps://get.k3s.io|\INSTALL_K3S_VERSION="v1.34.10+k3s1"\INSTALL_K3S_EXEC="--disable=traefik --write-kubeconfig-mode=644"\sh-
  • 版本固定v1.34:KServe 0.20 的兼容矩阵覆盖 Kubernetes 1.32 到 1.34,所以不用更新的 1.36,避免踩兼容性问题。
  • --disable=traefik:k3s 默认自带 Traefik 做 Ingress,但我们要用 Istio 做 KServe 的网关,两者会冲突,所以先关掉。
  • --write-kubeconfig-mode=644:让普通用户免 sudo 就能用 kubectl。

装完确认节点 Ready,同时看一眼节点资源:

kubectl getnode-ojsonpath='{.items[0].status.allocatable}'# cpu:8 memory:32484040Ki pods:110# 注意:这里没有 nvidia.com/gpu

这一步就印证了前面说的:k3s 装好、驱动也正常,但 K8s 里还看不到 GPU。这是预期结果,正好说明下一步为什么必须装 GPU Operator。


第二步:装 GPU Operator(preinstalled 驱动模式)

这一步最容易踩坑的是 k3s 的 containerd 路径。先看关键片段:

helm upgrade--installgpu-operator nvidia/gpu-operator\--namespacegpu-operator--versionv26.3.3\--setdriver.enabled=false\--settoolkit.enabled=true\--set-string toolkit.env[0].name=CONTAINERD_CONFIG\--set-string toolkit.env[0].value=/var/lib/rancher/k3s/agent/etc/containerd/config.toml\--set-string toolkit.env[1].name=CONTAINERD_SOCKET\--set-string toolkit.env[1].value=/run/k3s/containerd/containerd.sock\--set-string toolkit.env[2].name=RUNTIME_CONFIG_SOURCE\--set-string toolkit.env[2].value=file=/var/lib/rancher/k3s/agent/etc/containerd/config.toml

两个关键点:

  • driver.enabled=false:复用宿主机的 595.84 驱动。如果不关,Operator 会尝试装自己的驱动容器,和宿主机驱动冲突,通常会反复重启或失败。
  • toolkit.env那三行:k3s 的 containerd 配置和 socket 路径和标准 Kubernetes 不一样(在/var/lib/rancher/k3s/下),必须显式告诉 Operator,否则 Container Toolkit 无法正确配置 GPU 运行时。这是 k3s 上装 GPU Operator 最常见的坑。

装完等各组件就绪,然后做两个验证。

验证一:节点是否公布了 GPU 资源

kubectl getnode-ojsonpath='{.items[0].status.allocatable.nvidia\.com/gpu}'# 输出:1

对比第一步(k3s 装完时没有这个资源),现在出现了nvidia.com/gpu: 1。这就是 GPU Operator 的价值:把 GPU 接进了 K8s 的调度体系。

验证二:容器里能不能真正用 GPU

跑一个官方 CUDA vectorAdd 测试 Pod:

kubectl run cuda-vectoradd--restart=Never\--image=nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04\--limits=nvidia.com/gpu=1kubectl logs cuda-vectoradd

输出:

[Vector addition of 50000 elements] CUDA kernel launch with 196 blocks of 256 threads Test PASSED Done

到这里,「宿主机能看到 GPU → K8s 能调度 GPU → 容器内能用 GPU」三层就全部打通了。


第三步:装 cert-manager、Istio、KServe

这三个按依赖顺序装。cert-manager 先装,因为 KServe 的 webhook 需要它签发的证书;Istio 提供网关;最后装 KServe。

cert-manager

helm upgrade--installcert-manager oci://quay.io/jetstack/charts/cert-manager\--versionv1.21.1--namespacecert-manager --create-namespace\--setcrds.enabled=true--wait

它的角色单一:给 KServe 控制器的准入 webhook 提供 TLS 证书。少了它,KServe 装上也起不来。

Istio

istioctlinstall--setprofile=default-y

Istio 是 KServe 对外暴露推理服务的网关。它的 Ingress 网关(istio-ingressgateway)是外部请求进入模型的入口。

KServe(Standard 模式)

helm upgrade--installkserve oci://ghcr.io/kserve/charts/kserve-resources\--versionv0.20.0--namespacekserve\--setkserve.controller.deploymentMode=Standard\--setkserve.controller.gateway.ingressGateway.className=istio--wait

deploymentMode=Standard:这是给 GPU 生成式推理用的模式,固定副本、常驻 GPU。KServe 官方建议生成式大模型用 Standard,因为请求时间长、GPU 贵,需要可预测的资源控制。另一种 Knative(Serverless)模式,是下篇讲 Scale to Zero 和灰度时用的。

装完把 Istio 网关暴露成一个固定 NodePort(本实验用 30080),外部才能通过它访问:

kubectl patch svc istio-ingressgateway-nistio-system--type=json\-p='[{"op":"replace","path":"/spec/ports/1/nodePort","value":30080}]'

提示:如果用脚本自动 patch,注意确认端口是否真的落到了 30080。实测中用某些方式 patch 会被随机分配成别的端口,需要按端口索引精确指定。


一个容易卡住的坑:KServe 0.20 默认不带 ServingRuntime

控制面装完,正准备部署模型时,会遇到一个不查日志根本想不到的问题。

Qwen 的 InferenceService 里写的是modelFormat.name: huggingface,这需要集群里存在一个支持 huggingface 的 ClusterServingRuntime 来匹配。但装完 KServe 后查一下:

kubectl get clusterservingruntime# 空的

一个都没有。KServe 0.20 把内置 ServingRuntime 与核心 chart 解耦了,默认不再随控制面一起装。这和很多旧教程不一样,照着做会卡在「no runtime found」。

解法是单独装官方的 huggingface runtime 清单。但还有一个细节:官方清单里镜像是占位符huggingfaceserver:replace,用 Helm 装 runtime 时才会自动填充,单独用 YAML 必须手动替换成真实镜像。而且 GPU 推理要用带 CUDA 的-gpu版本:

containers:-name:kserve-container# 必须用 -gpu 版本,CPU 版缺少 CUDA 跑不了 GPU 推理image:kserve/huggingfaceserver:v0.20.0-gpu
kubectl apply-fstandard/huggingface-runtime.yaml kubectl get clusterservingruntime# kserve-huggingfaceserver huggingface ...

记住这个结论:KServe 0.20 上,ServingRuntime 要单独装,GPU 模型要用 -gpu 镜像。这是照旧教程操作时最容易卡的一步。


部署 Qwen:只写一个 InferenceService

前面都是铺垫,真正部署模型只需要一个 InferenceService。核心片段:

apiVersion:serving.kserve.io/v1beta1kind:InferenceServicemetadata:name:qwen-llmspec:predictor:minReplicas:1maxReplicas:1model:modelFormat:name:huggingfacestorageUri:hf://Qwen/Qwen2.5-0.5B-Instructargs:---model_name=qwen---backend=vllm---max_model_len=4096---gpu_memory_utilization=0.90resources:limits:nvidia.com/gpu:"1"

几个要点:

  • modelFormat: huggingface+backend=vllm:用 huggingface runtime,底层跑 vLLM。前几篇的 vLLM 调优经验在这里依然生效。
  • storageUri: hf://...:直接从 HuggingFace 拉模型。
  • minReplicas=maxReplicas=1:单张 T4 固定一个副本。

部署后 Pod 会分两个阶段:先 init 容器 storage-initializer 下载模型,再主容器用 vLLM 加载。整个过程在本次实验约 4 分 40 秒就绪。

就绪后看一眼 KServe 到底帮我们创建了什么:

kubectl get inferenceservice,deployment,replicaset,pod,svc,ingress-nkserve-test
inferenceservice/qwen-llm URL: http://qwen-llm-kserve-test.example.com READY True deployment/qwen-llm-predictor 1/1 replicaset/qwen-llm-predictor-xxxx 1 pod/qwen-llm-predictor-xxxx 1/1 Running service/qwen-llm-predictor ClusterIP 80/TCP ingress/qwen-llm istio qwen-llm-kserve-test.example.com,...

这就是 KServe 作为「平台」的意义:你只写了一个 InferenceService,Deployment、ReplicaSet、Pod、Service、Ingress 全套都是它自动生成的。对照第06篇的定位,vLLM 和 Triton 是「引擎」,KServe 是「平台」,这里就是最直观的体现。


终端一屏展示kubectl get inferenceservice,deployment,replicaset,pod,svc,ingress -n kserve-test的实际输出,证明只提交一个 InferenceService 后 KServe 自动创建了整套资源。

此时看 GPU 占用:

nvidia-smi --query-gpu=memory.used,memory.total--format=csv# 14043 MiB, 15360 MiB

gpu_memory_utilization=0.90生效,vLLM 为 0.5B 模型加 KV Cache 预留了约 14GB。


nvidia-smi完整输出,可见 vLLM 进程与约 14GB 显存占用,证明模型确实加载到 T4 上运行。


调用推理接口

KServe 默认按 Host 路由(下篇会深挖这个机制)。所以调用时要连 NodePort,但带上模型的 Host 头:

curl-H"Host: qwen-llm-kserve-test.example.com"\http://<公网IP>:30080/openai/v1/chat/completions\-H"Content-Type: application/json"\-d'{"model":"qwen","messages":[{"role":"user","content":"用一句话解释什么是Kubernetes"}],"max_tokens":80}'

真实返回(节选):

{"model":"qwen","choices":[{"message":{"role":"assistant","content":"Kubernetes(简称K8s)是一种开源的容器编排平台,用于管理和调度应用程序在多个节点上运行..."},"finish_reason":"stop"}],"usage":{"prompt_tokens":35,"completion_tokens":71,"total_tokens":106}}

OpenAI 兼容格式,后端是 vLLM。到这里,GPU 主线就跑通了:KServe 控制面就绪、InferenceService Ready、Predictor 拿到 T4、OpenAI 接口返回真实回答。

踩坑提示:KServe 默认 Host 路由,直接用 IP 加路径访问会返回 404。必须带上-H "Host: <模型域名>",否则网关找不到对应路由。为什么是 Host 而不是 path、这个 Host 路由到底配在哪,下篇专门讲。


实践边界

如实说明本篇的验证范围:

  • GPU InferenceService 的部署与推理:已在真实 T4 上验证。
  • 单张 T4 固定一个副本运行,未验证多 GPU 副本的水平扩容。配额为 8 vCPU(一张 T4),扩到 2 个 GPU 副本需要第二张卡或 MIG。这一点不夸大。

小结

  1. 宿主机能看到 GPU,不等于 K8s 能调度 GPU:前者靠驱动,后者靠 GPU Operator 的 Device Plugin。
  2. 组件依赖顺序:k3s、GPU Operator、cert-manager、Istio、KServe,每层依赖下一层。
  3. k3s 上装 GPU Operator 的坑:驱动预装用driver.enabled=false,并通过toolkit.env指定 k3s 的 containerd 路径。
  4. KServe 0.20 的坑:默认不带 ServingRuntime,需单独装,GPU 模型用-gpu镜像。
  5. KServe 是平台:只写一个 InferenceService,自动生成 Deployment、Service、Ingress 一整套。

下一篇预告

AI Infra实战07(下):KServe 路由机制与 Serverless 灰度

下篇讲两件上篇留下的事:

  • KServe 的 Host 路由到底配在哪,和手写 Istio 的 Gateway + VirtualService 按 path 分流有什么区别(会用真实的 Envoy 配置和 Ingress 对照)
  • 用 Knative 模式验证 Scale to Zero、从 0 冷启动、10% Canary 灰度、回滚和推广

参考链接

  • KServe 官方文档
  • NVIDIA GPU Operator 文档
  • Kubernetes Schedule GPUs
  • k3s 官方文档
  • Istio 官方文档
  • 本篇配套代码仓库
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/2 15:53:37

STM8S标准外设库V2.3.1实战:从寄存器封装到工程应用全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/2 15:50:21

AI卫星与遥感图像分类:从PyTorch训练到ONNX部署的完整实践

最近有一条消息在科技圈引起不少讨论&#xff1a;马斯克提出一个听起来很像科幻片设定的计划&#xff0c;打算用 AI 卫星让地球在“未来约 10 亿年”内保持宜居。很多人第一反应是段子&#xff0c;第二反应是“这和我有什么关系”。但从技术角度&#xff0c;这个设想真正值得拆…

作者头像 李华
网站建设 2026/9/2 15:50:10

四年级孩子的GESP C++四级7天冲刺刷题清单

这份适配四年级孩子的GESP C四级7天冲刺刷题清单&#xff0c;每天任务量控制在40分钟以内&#xff0c;避开复杂知识点&#xff0c;完全贴合小学生的接受节奏&#xff0c;兼顾校内学习不占用过多精力。 Day1 核心语法与客观题入门 1、目标‌&#xff1a; 快速唤醒之前学过的C基…

作者头像 李华
网站建设 2026/9/2 15:49:42

从龙珠人造人看工程控制:能源、自主性与AI对齐的系统级拆解

1. 这篇文章真正要解决的问题如果你只是把《龙珠》里的人造人当作一群战斗力爆表的反派&#xff0c;那你大概率会错过一个更有意思的视角&#xff1a;格罗博士其实是在做一个典型的“高科技项目”。这个结论听起来像玩笑&#xff0c;但仔细拆一拆&#xff1a;他有明确的目标&am…

作者头像 李华