- Published on
KServe 模型服务完全指南:InferenceService、Canary 部署、Transformer、InferenceGraph 生产运维
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 引言
- InferenceService CRD 深入解析
- Canary 部署策略
- 自定义 Transformer 实现
- InferenceGraph:基于 DAG 的复合推理
- 自动伸缩策略
- v0.15 新特性
- 失败案例与故障排查
- 运维注意事项
- 参考资料

引言
训练 ML 模型和在生产环境中稳定地提供服务,本质上是两类不同的工程课题。在训练阶段,GPU 利用率和收敛速度是关键,而在服务阶段,延迟、吞吐量、版本管理、安全上线、故障恢复才是决定性因素。尤其是在多个模型相互协作的复合推理流水线中,单纯把模型丢进 Flask 的做法根本承受不住运维复杂度。
KServe(前身为 KFServing)是一个 CNCF Incubating 项目,专为以 Kubernetes 原生方式解决这类生产模型服务问题而设计。通过 InferenceService CRD 可以声明式地部署模型,借助基于 Knative 的自动伸缩来应对流量波动,用 Canary 部署实现安全上线,并可用 InferenceGraph 构建基于 DAG 的复合推理。
KServe 于 2019 年以 KFServing 之名作为 Kubeflow 项目的一部分起步,2021 年独立出来并更名为 KServe。2023 年加入 CNCF Sandbox 后快速成长,到 2025 年晋升为 Incubating 阶段。它支持 TFServing、TorchServe、Triton、vLLM 等主要推理运行时,并顺应 LLM 时代扩展到了 vLLM 后端与 Envoy AI Gateway 的集成。
本文将从 KServe 的核心架构一路讲到生产运维策略,配合代码覆盖实战所需的一切。
InferenceService CRD 深入解析
Predictor / Transformer / Explainer 架构
KServe 的 InferenceService 由三个核心组件构成。
Client Request
│
▼
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Transformer │────▶│ Predictor │────▶│ Explainer │
│ (前处理/ │ │ (模型推理) │ │ (生成解释) │
│ 后处理) │◀────│ │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│
▼
Client Response
- Predictor:核心推理引擎。支持 TFServing、TorchServe、Triton、XGBoost、LightGBM、Sklearn、vLLM 等多种运行时。
- Transformer:负责推理请求的前处理与响应的后处理。将图像缩放、分词、特征工程等工作从 Predictor 中分离出来,可以独立进行伸缩。
- Explainer:为推理结果生成解释。通过 Alibi Explainer、AIF360 等提供模型预测依据。
支持的运行时对比
| 运行时 | 框架 | GPU 支持 | 动态批处理 | LLM 服务 | 主要用途 |
|---|---|---|---|---|---|
| TFServing | TensorFlow | O | O | X | TF SavedModel 服务 |
| TorchServe | PyTorch | O | O | X | PyTorch 模型服务 |
| Triton | 多框架 | O | O | O | 多模型并发服务 |
| vLLM | PyTorch/HuggingFace | O | O | O | LLM 推理优化 |
| Sklearn | Scikit-learn | X | X | X | 轻量级 ML 模型 |
| XGBoost | XGBoost | O | X | X | 梯度提升 |
| LGBM | LightGBM | X | X | X | 梯度提升 |
基本的 InferenceService YAML
最基本形态的 InferenceService 只定义 Predictor。下面是一个为存放在 S3 上的 Sklearn 模型提供服务的示例。
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: sklearn-iris
namespace: ml-serving
annotations:
serving.kserve.io/deploymentMode: Serverless
spec:
predictor:
minReplicas: 1
maxReplicas: 10
scaleTarget: 5
scaleMetric: concurrency
model:
modelFormat:
name: sklearn
storageUri: 's3://ml-models/sklearn/iris/v1'
resources:
requests:
cpu: '500m'
memory: '512Mi'
limits:
cpu: '1'
memory: '1Gi'
应用这份 YAML 后,KServe 控制器会创建 Knative Service,通过 Istio VirtualService 配置路由,并由 Knative Pod Autoscaler 基于 concurrency 执行自动伸缩。
vLLM 后端的 LLM 服务
从 KServe v0.13 起,vLLM 作为一级运行时得到支持。它会自动暴露与 OpenAI 兼容的 API,因此可以直接沿用现有的 OpenAI 客户端代码。
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: llama3-vllm
namespace: ml-serving
spec:
predictor:
minReplicas: 1
maxReplicas: 4
model:
modelFormat:
name: vLLM
storageUri: 'pvc://llm-model-cache/Meta-Llama-3.1-8B-Instruct'
args:
- '--max-model-len=8192'
- '--gpu-memory-utilization=0.90'
- '--enable-chunked-prefill'
- '--max-num-batched-tokens=16384'
- '--tensor-parallel-size=2'
resources:
requests:
cpu: '8'
memory: '32Gi'
nvidia.com/gpu: '2'
limits:
cpu: '16'
memory: '64Gi'
nvidia.com/gpu: '2'
tolerations:
- key: 'nvidia.com/gpu'
operator: 'Exists'
effect: 'NoSchedule'
nodeSelector:
gpu-type: 'a100'
在 storageUri 中指定 PVC,可以把体积庞大的 LLM 权重提前缓存到节点上,从而实现快速加载。tensor-parallel-size=2 会把模型分散部署到 2 张 GPU 上,突破单张 GPU 的显存上限。
Canary 部署策略
用 canaryTrafficPercent 实现渐进式上线
在生产环境更新模型时,最危险的时刻就是新版本刚部署完之后。KServe 通过 canaryTrafficPercent 字段原生支持 Canary 部署,可以把流量逐步迁移到新版本。
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: fraud-detector
namespace: ml-serving
annotations:
serving.kserve.io/deploymentMode: Serverless
spec:
predictor:
canaryTrafficPercent: 10
minReplicas: 2
maxReplicas: 20
model:
modelFormat:
name: sklearn
storageUri: 's3://ml-models/fraud/v2'
resources:
requests:
cpu: '1'
memory: '2Gi'
limits:
cpu: '2'
memory: '4Gi'
上面的配置只把 10% 的总流量路由到新模型(v2),其余 90% 仍发往现有的稳定版本。部署后通过监控验证新版本的表现,再逐步调高 canaryTrafficPercent。
分阶段切换脚本
编写自动化的渐进式上线脚本,可以减少人为失误。
#!/bin/bash
# canary-promote.sh - 渐进式 Canary 晋级脚本
ISVC_NAME="fraud-detector"
NAMESPACE="ml-serving"
STAGES=(10 30 50 80 100)
MAX_ERROR_RATE=0.05
OBSERVE_MINUTES=10
for pct in "${STAGES[@]}"; do
echo "=== 将 Canary 流量更新为 ${pct}% ==="
kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
--type='json' \
-p="[{\"op\": \"replace\", \"path\": \"/spec/predictor/canaryTrafficPercent\", \"value\": $pct}]"
echo "正在观察 ${OBSERVE_MINUTES} 分钟的指标..."
sleep $((OBSERVE_MINUTES * 60))
# 从 Prometheus 查询 canary 错误率
ERROR_RATE=$(curl -s "http://prometheus:9090/api/v1/query" \
--data-urlencode "query=rate(revision_request_count{revision_name=~\".*canary.*\",response_code!=\"200\"}[5m]) / rate(revision_request_count{revision_name=~\".*canary.*\"}[5m])" \
| jq -r '.data.result[0].value[1] // "0"')
if (( $(echo "$ERROR_RATE > $MAX_ERROR_RATE" | bc -l) )); then
echo "错误率 ${ERROR_RATE} 超过阈值 ${MAX_ERROR_RATE}。执行回滚。"
kubectl patch inferenceservice "$ISVC_NAME" -n "$NAMESPACE" \
--type='json' \
-p='[{"op": "replace", "path": "/spec/predictor/canaryTrafficPercent", "value": 0}]'
exit 1
fi
echo "错误率 ${ERROR_RATE} —— 处于正常范围。继续下一阶段。"
done
echo "=== Canary 晋级完成。v2 现已承载 100% 流量。 ==="
这个脚本将流量分 5 个阶段从 10% 切换到 100%,每个阶段都会监控 10 分钟的错误率。若错误率超过 5%,会自动回滚到 0%。
自定义 Transformer 实现
前处理/后处理流水线设计
在实际生产环境中,需要把客户端发来的原始数据(图像 URL、文本、JSON)转换成模型期望的张量格式。将 Transformer 与 Predictor 分离,能带来以下好处。
- 独立伸缩:当前处理是 CPU 密集型、而推理是 GPU 密集型时,可以分别应用不同的伸缩策略
- 可复用性:同一个 Transformer 可以在多个模型版本间复用
- 部署独立性:更改 Transformer 逻辑时无需重新部署模型即可更新
继承 kserve.Model 并实现处理函数
通过继承 KServe Python SDK 的 kserve.Model 类来实现自定义 Transformer。
import kserve
from kserve import InferRequest, InferResponse, InferInput
from typing import Dict, List
import numpy as np
from PIL import Image
import requests
from io import BytesIO
import logging
logger = logging.getLogger(__name__)
class ImageTransformer(kserve.Model):
"""接收图像 URL,前处理后转发给 Predictor 的 Transformer"""
def __init__(self, name: str, predictor_host: str):
super().__init__(name)
self.predictor_host = predictor_host
self.target_size = (224, 224)
self.mean = np.array([0.485, 0.456, 0.406])
self.std = np.array([0.229, 0.224, 0.225])
self.ready = False
def load(self):
"""模型初始化。在此处放置 Warm-up 逻辑。"""
logger.info("ImageTransformer 初始化完成")
self.ready = True
def preprocess(
self, payload: Dict, headers: Dict = None
) -> InferRequest:
"""接收图像 URL,转换为归一化后的张量"""
instances = payload.get("instances", [])
processed_images = []
for instance in instances:
image_url = instance.get("image_url")
response = requests.get(image_url, timeout=10)
response.raise_for_status()
image = Image.open(BytesIO(response.content)).convert("RGB")
image = image.resize(self.target_size)
# 转换为 numpy 数组后做归一化
img_array = np.array(image, dtype=np.float32) / 255.0
img_array = (img_array - self.mean) / self.std
img_array = np.transpose(img_array, (2, 0, 1)) # CHW
processed_images.append(img_array)
input_tensor = np.stack(processed_images)
infer_input = InferInput(
name="input",
shape=list(input_tensor.shape),
datatype="FP32",
data=input_tensor.tolist(),
)
return InferRequest(
model_name=self.name,
infer_inputs=[infer_input],
)
def postprocess(
self, response: InferResponse, headers: Dict = None
) -> Dict:
"""将模型输出转换为易于阅读的格式"""
predictions = response.outputs[0].data
class_names = ["cat", "dog", "bird", "fish", "other"]
results = []
for pred in predictions:
if isinstance(pred, list):
probs = np.array(pred)
else:
probs = np.array([pred])
top_idx = int(np.argmax(probs))
results.append({
"class": class_names[top_idx],
"confidence": float(probs[top_idx]),
"all_scores": {
name: float(score)
for name, score in zip(class_names, probs)
},
})
return {"predictions": results}
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--predictor_host", required=True)
parser.add_argument("--model_name", default="image-classifier")
args = parser.parse_args()
transformer = ImageTransformer(
name=args.model_name,
predictor_host=args.predictor_host,
)
transformer.load()
kserve.ModelServer(workers=4).start([transformer])
包含 Transformer 的 InferenceService YAML
把 Transformer 集成进 InferenceService 后,KServe 会自动配置 Transformer 与 Predictor 之间的内部路由。
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: image-classifier
namespace: ml-serving
spec:
transformer:
minReplicas: 2
maxReplicas: 15
scaleTarget: 10
scaleMetric: concurrency
containers:
- name: image-transformer
image: registry.example.com/ml/image-transformer:v1.2.0
args:
- '--model_name=image-classifier'
resources:
requests:
cpu: '1'
memory: '2Gi'
limits:
cpu: '2'
memory: '4Gi'
env:
- name: STORAGE_URI
value: ''
predictor:
minReplicas: 1
maxReplicas: 8
model:
modelFormat:
name: pytorch
storageUri: 's3://ml-models/image-classifier/resnet50-v2'
resources:
requests:
cpu: '2'
memory: '4Gi'
nvidia.com/gpu: '1'
limits:
cpu: '4'
memory: '8Gi'
nvidia.com/gpu: '1'
在这个配置中,Transformer 在 CPU 节点上最多可扩展到 15 个,Predictor 在 GPU 节点上最多可扩展到 8 个。当前处理成为瓶颈时,只需增加 Transformer 的数量即可,因此更具成本效益。
InferenceGraph:基于 DAG 的复合推理
4 种节点类型
InferenceGraph 是 KServe 的高级功能,可以把多个 InferenceService 连接成 DAG,构建复合推理流水线。它从 v0.11 起晋升为 GA,支持 4 种节点类型。
| 节点类型 | 执行方式 | 输入传递 | 主要用例 | 说明 |
|---|---|---|---|---|
| Sequence | 顺序执行 | 把前一节点的输出作为下一节点的输入 | 前处理链 | 把 A 的结果传给 B 作为输入 |
| Switch | 条件分支 | 根据条件选择一个节点 | A/B 测试、路由 | 基于条件选择单一路径 |
| Ensemble | 并行执行 + 汇总 | 把相同输入传给所有节点 | 集成推理 | 汇总/投票多个模型的结果 |
| Splitter | 加权分配 | 按比例选择一个节点 | 流量拆分、Canary | 基于权重的流量路由 |
A/B 测试与集成模式
生产环境中经常使用的模式,是集成与 A/B 测试的组合。例如在欺诈检测系统中,同时运行基于规则的模型、XGBoost 模型和深度学习模型,再对结果做集成,就能比单一模型获得更高的准确率。
apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
name: fraud-detection-ensemble
namespace: ml-serving
annotations:
serving.kserve.io/propagateHeaders: 'x-request-id,x-trace-id'
spec:
nodes:
root:
routerType: Sequence
steps:
- name: feature-enrichment
serviceName: feature-enricher
weight: 100
- name: ensemble-node
nodeName: model-ensemble
model-ensemble:
routerType: Ensemble
steps:
- name: xgboost-model
serviceName: fraud-xgboost
weight: 40
- name: deep-model
serviceName: fraud-deep-learning
weight: 40
- name: rule-engine
serviceName: fraud-rule-engine
weight: 20
result-combiner:
routerType: Sequence
steps:
- name: weighted-average
serviceName: ensemble-combiner
weight: 100
这个 InferenceGraph 的运行方式如下。
- root 节点(Sequence):首先由 feature-enricher 把原始数据转换为丰富的特征,再把结果传给 model-ensemble 节点。
- model-ensemble 节点(Ensemble):XGBoost、深度学习、规则引擎三个模型以相同的输入并行执行。各模型的 weight 会在汇总最终结果时用作权重。
- 最终结果由三个模型的加权平均得出。
用于 A/B 测试的 Splitter 模式
apiVersion: serving.kserve.io/v1alpha1
kind: InferenceGraph
metadata:
name: recommendation-ab-test
namespace: ml-serving
spec:
nodes:
root:
routerType: Splitter
steps:
- name: model-v1-stable
serviceName: recommender-v1
weight: 80
- name: model-v2-experiment
serviceName: recommender-v2
weight: 20
Splitter 会把 80% 的流量分配给稳定版本,20% 分配给实验版本。与 InferenceService 的 Canary 不同,InferenceGraph 的 Splitter 是在完全独立的 InferenceService 之间做流量拆分,因此适用于不同模型架构之间的 A/B 测试。
自动伸缩策略
Knative Pod Autoscaler(KPA)vs HPA vs KEDA
KServe 支持三种自动伸缩器。适合的伸缩器会因工作负载特性而异。
| 特性 | KPA(Knative) | HPA(Kubernetes) | KEDA |
|---|---|---|---|
| Scale-to-Zero | O | X | O |
| 伸缩指标 | concurrency、rps | cpu、memory、custom | 外部指标(Prometheus、CloudWatch 等) |
| 响应速度 | 快(1-2 秒) | 一般(15-30 秒) | 一般(15 秒) |
| GPU 工作负载 | 有限 | 适合 | 非常适合 |
| 自定义指标 | 有限 | 需要 Metrics API | 丰富的 Scaler 支持 |
| Cold Start 应对 | activationScale | N/A | minReplicaCount |
| 配置复杂度 | 低 | 中 | 高 |
GPU 工作负载的 Scale-to-Zero
GPU 实例成本较高,因此 Scale-to-Zero 很重要。但 GPU 模型的 cold start 时间较长(从数十秒到数分钟),需要格外留意。使用 KPA 时,应恰当设置 scaledown 的延迟时间。
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
metadata:
name: gpu-model
namespace: ml-serving
annotations:
# 启用 Scale-to-Zero(默认值)
serving.kserve.io/enable-scale-to-zero: 'true'
# 最后一次请求后到 Scale-to-Zero 的等待时间
autoscaling.knative.dev/scale-to-zero-pod-retention-period: '15m'
# 缩容延迟(防止骤然缩容)
autoscaling.knative.dev/scale-down-delay: '5m'
# 可并发处理的请求数(GPU 模型应设置得较低)
autoscaling.knative.dev/target: '2'
autoscaling.knative.dev/metric: 'concurrency'
spec:
predictor:
minReplicas: 0
maxReplicas: 4
model:
modelFormat:
name: pytorch
storageUri: 's3://ml-models/large-model/v1'
resources:
requests:
nvidia.com/gpu: '1'
limits:
nvidia.com/gpu: '1'
KEDA + vLLM 指标自动伸缩
在 LLM 服务中,不依赖 CPU/内存,而是基于 vLLM 自身的指标(等待中的请求数、KV 缓存使用率)进行伸缩更为有效。借助 KEDA 的 Prometheus Scaler 可以实现这一点。
apiVersion: keda.sh/v1alpha1
kind: ScaledObject
metadata:
name: llama3-vllm-scaler
namespace: ml-serving
spec:
scaleTargetRef:
apiVersion: serving.kserve.io/v1beta1
kind: InferenceService
name: llama3-vllm
minReplicaCount: 1
maxReplicaCount: 8
pollingInterval: 15
cooldownPeriod: 300
advanced:
restoreToOriginalReplicaCount: true
horizontalPodAutoscalerConfig:
behavior:
scaleUp:
stabilizationWindowSeconds: 30
policies:
- type: Pods
value: 2
periodSeconds: 60
scaleDown:
stabilizationWindowSeconds: 300
policies:
- type: Pods
value: 1
periodSeconds: 120
triggers:
# 基于 vLLM 等待请求数的伸缩
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
metricName: vllm_waiting_requests
query: |
avg(vllm:num_requests_waiting{model_name="llama3-vllm"})
threshold: '5'
# 基于 KV Cache 使用率的伸缩
- type: prometheus
metadata:
serverAddress: http://prometheus.monitoring:9090
metricName: vllm_kv_cache_usage
query: |
avg(vllm:gpu_cache_usage_perc{model_name="llama3-vllm"})
threshold: '0.85'
这个配置在以下两个条件中任意一个满足时,就会触发扩容。
- vLLM 平均等待请求数超过 5 个时,增加 Pod。
- GPU KV 缓存使用率超过 85% 时,增加 Pod。
缩容时会应用 5 分钟的稳定化窗口与每 2 分钟减少 1 个的策略,以防止骤然缩容。
v0.15 新特性
Envoy AI Gateway 集成
KServe v0.15(2025 年 6 月)中最值得关注的功能是 Envoy AI Gateway 集成,它为 LLM 服务提供了专门的路由与可观测性。
- 基于 Token 的 Rate Limiting:按 API 密钥限制每分钟/每小时的 Token 使用量
- 模型级路由:基于请求中的
model字段路由到相应的后端(vLLM、Triton、外部 API) - Semantic Caching:对相似 Prompt 的响应进行缓存,降低成本与延迟
- Usage Tracking:按模型/用户/团队跟踪 Token 使用量、延迟、错误率等
LocalModelCache 多节点组
如果每次都从 S3 下载大规模 LLM 权重,cold start 会耗费数分钟。v0.15 的 LocalModelCache 会把模型提前缓存到节点本地磁盘,大幅缩短 startup 时间。
apiVersion: serving.kserve.io/v1alpha1
kind: LocalModelCache
metadata:
name: llama3-cache
namespace: ml-serving
spec:
sourceModelUri: 's3://ml-models/Meta-Llama-3.1-8B-Instruct'
nodeGroups:
- name: a100-nodes
nodeSelector:
gpu-type: 'a100'
persistentVolumeClaimSpec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 50Gi
storageClassName: local-nvme
这个配置会在所有带有 gpu-type: a100 标签的节点上创建 50Gi 的 NVMe 卷,并提前从 S3 下载模型权重。Pod 启动时会从本地磁盘而非 S3 加载权重,因此 cold start 时间可以从数分钟缩短到数秒。
LLM 服务优化
v0.15 中包含了多项针对 LLM 工作负载的优化。
- LoRA 适配器 Hot-Swapping:在保留基础模型的同时,动态替换 LoRA 适配器。在多租户环境中可高效地为每个客户提供各自微调后的模型
- 支持 Speculative Decoding:在 vLLM 后端借助 Draft Model 进行推测解码,将 Token 生成速度提升 2-3 倍
- Prefix Caching:共享系统 Prompt 等重复前缀的 KV 缓存,缩短 TTFT(Time To First Token)
失败案例与故障排查
案例 1:Transformer OOM 导致推理流水线中断
现象:在图像分类流水线中,Transformer Pod 间歇性地被 OOMKilled,导致整个推理链失败。
原因分析:Transformer 在把大尺寸图像(8K 分辨率)加载到内存时,PIL 会按解压后的原始尺寸分配内存。当同时涌入 10 个请求时,瞬间需要 10 x 200MB = 2GB,而内存 limit 却设置为 1Gi。
解决方法:
# 在前处理的最早阶段就限制图像尺寸
from PIL import Image
# PIL DecompressionBomb 防护设置
Image.MAX_IMAGE_PIXELS = 89_478_485 # 约 9500x9500
def safe_load_image(image_bytes: bytes, max_size: int = 2048):
"""内存安全的图像加载"""
img = Image.open(BytesIO(image_bytes))
# 若原始尺寸超过 max_size,立即缩放
if max(img.size) > max_size:
ratio = max_size / max(img.size)
new_size = (int(img.width * ratio), int(img.height * ratio))
img = img.resize(new_size, Image.LANCZOS)
return img.convert("RGB")
此外还把 Transformer 的内存 limit 上调到 4Gi,并把 concurrency target 降到 5,以此限制并发处理量。
案例 2:Scale-to-Zero 状态下的 Cold Start 延迟
现象:GPU 模型在 Scale-to-Zero 状态下,首个请求出现超过 60 秒的超时。
原因分析:从 S3 下载模型权重(2GB)并加载到 GPU 内存所需的时间,超过了 Knative 的默认超时时间(30 秒)。
解决方法:
- 将
progressDeadline扩展为 600 秒 - 应用 LocalModelCache,把模型预先缓存到节点本地
- 设置
minReplicas: 1,始终保留至少 1 个 Pod(在成本允许的情况下)
调试清单
调试 KServe 部署问题时,应系统性检查以下项目。
- 确认 InferenceService 状态:在
kubectl get isvc -n ml-serving中确认 READY 是否为 True - 确认 Pod 状态:用
kubectl get pods -n ml-serving -l serving.kserve.io/inferenceservice=MODEL_NAME检查 Pod 状态 - 确认事件:在
kubectl describe isvc MODEL_NAME -n ml-serving中查看 Events 部分 - 确认 Knative Revision:在
kubectl get revisions -n ml-serving中检查 revision 状态 - 确认存储访问:检查 StorageInitializer 日志中是否存在 S3/GCS 访问错误
- 确认 Istio 路由:在
kubectl get virtualservice -n ml-serving中检查流量路由规则 - 确认资源是否不足:在
kubectl describe node中检查 GPU 可分配量与内存余量
运维注意事项
GPU 节点调度与 tolerations
GPU 节点通常都设置了 taint,因此 InferenceService 必须明确指定 tolerations 和 nodeSelector。若遗漏这一点,Pod 会一直停留在 Pending 状态。
spec:
predictor:
tolerations:
- key: 'nvidia.com/gpu'
operator: 'Exists'
effect: 'NoSchedule'
nodeSelector:
gpu-type: 'a100'
model:
modelFormat:
name: vLLM
# ... 模型设置
模型缓存策略
运维大规模模型时,分层缓存策略必不可少。
- 一级缓存(节点本地):利用 LocalModelCache,把模型权重保存在 NVMe SSD 上。加载速度最快
- 二级缓存(PVC):利用 PersistentVolumeClaim,缓存到网络存储。可在节点间共享
- 三级原始存储(Object Storage):在 S3、GCS 等处保存模型的原始文件。速度最慢但持久性最高
资源 Quota 管理
按命名空间设置 ResourceQuota,以防止团队之间的 GPU 资源争抢。
apiVersion: v1
kind: ResourceQuota
metadata:
name: ml-serving-quota
namespace: ml-serving
spec:
hard:
requests.cpu: '64'
requests.memory: '256Gi'
requests.nvidia.com/gpu: '8'
limits.cpu: '128'
limits.memory: '512Gi'
limits.nvidia.com/gpu: '8'
persistentvolumeclaims: '20'
这个 Quota 把 ml-serving 命名空间的使用上限限制为最多 8 张 GPU、128 核 CPU、512Gi 内存。按团队拆分命名空间并各自分配合适的 Quota,就能实现稳定的多租户运维。