源码导读:一张地图看懂 KServe 仓库

KServe 源码拆解系列 · 第 1 篇

概述文讲的是 KServe"能干什么":一个 InferenceService YAML apply 下去,Deployment、Service、流量、扩缩容全自动搞定。但 apply 之后那几秒:谁读到了你的 YAML?谁决定建几个 Pod?谁把 vLLM 参数填进容器启动命令?------本系列拆"内部怎么干",共 10 篇:

  1. 源码导读(本篇):仓库地图 + 代码入口
  2. InferenceService API:一个 CRD 承载全部配置
  3. 调和循环:从事件到 Deployment
  4. 组件构建:组件如何变成 Pod
  5. 模型加载与节点级缓存:模型从对象存储到 GPU
  6. 流量路由:请求送到正确的 Pod
  7. 自动扩缩容:HPA/KEDA/Knative
  8. 多模型管理:TrainedModel 与 ModelMesh
  9. InferenceGraph 推理流水线:多模型编排
  10. LLMService 新 API:新一代接口

控制面/数据面:2 分钟回顾

arduino 复制代码
   kubectl apply    ┌──────────────────────────────┐
  ───────────────▶  │  控制面 Control Plane        │
                    │  InferenceService Controller │
                    │  "期望状态" → 创建/改/删资源 │
                    └──────────────┬───────────────┘
                                   │ 下发 Deployment / Service / VirtualService
                                   ▼
                    ┌──────────────────────────────┐
                    │  数据面 Data Plane           │
                    │  Predictor/Transformer/      │
                    │  Explainer 真实推理 Pod      │
                    └──────────────────────────────┘

对应到代码:控制面 = cmd/manager + pkg/controller + pkg/webhook(全在 KServe 仓库,本系列主战场);数据面 = cmd/agent(Pod 里的代理)+ 推理服务端,服务端主体在独立仓库 kserve/python,本系列不深入。


仓库地图:pkg/ 逐个看

仓库根目录(省略次要目录):

bash 复制代码
kserve/
├── cmd/        # 可执行程序入口:manager / agent / router / llmisvc...
├── pkg/        # 核心库代码------本系列的主战场
├── config/     # Kustomize 部署清单:manager 部署、RBAC、Webhook、CRD
├── charts/     # Helm Chart:CRD 包、控制面包、运行时配置包
├── python/     # 推理服务端配套代码(主体在独立仓库 kserve/python)
├── hack/       # 代码生成脚本
└── test/       # e2e 测试

pkg/ 逐个看:

目录 职责 系列哪篇深入
pkg/apis CRD 的 Go 类型、默认值、校验、版本转换 第 2 篇
pkg/controller 所有调和循环(InferenceService、TrainedModel、InferenceGraph、LLMService...) 第 3、4 篇
pkg/agent 数据面代理:模型下载、请求日志、批处理 第 4、5 篇
pkg/webhook Admission Webhook:改 Pod、校验 Runtime/模型类 CRD 第 2 篇穿插
pkg/modelconfig ModelMesh 模型配置类型与 ConfigMap 更新 第 8 篇
pkg/credentials S3/GCS/Azure 存储凭据解析 第 5 篇穿插
pkg/logger 请求/响应日志落盘(JSON/CSV/Parquet) 第 4 篇穿插
pkg/batcher 请求动态批处理:攒一批再转发 第 4 篇穿插
pkg/tls TLS 配置解析 不单独成篇
pkg/constants 全局常量:ConfigMap 名、注解 key... 各篇都会碰到
pkg/scheme 把全部 CRD 类型注册进 controller-runtime 本篇入口
pkg/utils 工具函数:IsCrdAvailable 探测、env/volume 合并 各篇都会碰到
pkg/client 生成的 clientset/informers/listers 不单独成篇
pkg/validation EnvPolicy 屏蔽变量、Managed DRA 等校验 不单独成篇
pkg/types 跨包共享配置结构体(StorageInitializerConfig) 不单独成篇
pkg/openapi 生成的 OpenAPI/Swagger 定义(给 Python SDK) 不单独成篇
pkg/testing 测试工具:matchers、cleaner 不单独成篇

pkg/controller 按 API 版本再拆一层:

子目录 内容 系列哪篇
v1beta1 inferenceservice/ 主控制器(组件构建、ingress、autoscaler 全在它下面) 第 3、4、6、7 篇
v1alpha1 inferencegraphtrainedmodellocalmodellocalmodelnode 第 8、9 篇
v1alpha2 llmisvc(新一代 LLMService) 第 10 篇

三个版本并列是分层不是替换:v1alpha1 住着 ServingRuntime、InferenceGraph 等"配角"CRD,v1beta1 是 InferenceService 主场,v1alpha2 是孵化中的 LLMService。

cmd/ 下每个目录一个二进制:manager 控制面大脑(一个进程跑三套控制器 + Webhook);agent 数据面代理,跑在每个推理 Pod 里干下载、日志、批处理;llmisvc LLMService 的独立控制面;router InferenceGraph 路由器;localmodellocalmodelnode 节点级模型缓存控制面(第 5 篇)。

config/ 是 Kustomize 清单(manager 部署、RBAC、CRD,config/default 组装成可直接 apply 的完整部署),charts/ 是 Helm 版同一套,二选一即可。


代码入口:cmd/manager/main.go

控制面的一切从 cmd/manager/main.go(约 300 行)开始。启动参数(Options 结构体):metricsAddr 默认 ":8080"webhookPort 默认 9443probeAddr 默认 ":8081"

main() 主线:

markdown 复制代码
1. config.GetConfig() + kubernetes.NewForConfig(cfg)  → 拿 kubeconfig,建客户端
2. manager.New(cfg, manager.Options{...})             → controller-runtime 的 Manager 登场
3. kservescheme.AddAll(mgr.GetScheme())               → 注册全部 CRD 类型
4. 读 inferenceservice-config ConfigMap → Deploy/Ingress 配置  ← 集群级行为全靠它调
5. 注册三套控制器 + 一组 Webhook
6. mgr.Start(signals.SetupSignalHandler())            → 进入事件循环

第 5 步,主控制器挂载(真实代码):

go 复制代码
if err = (&v1beta1controller.InferenceServiceReconciler{
	Client:    mgr.GetClient(),
	Scheme:    mgr.GetScheme(),
	Recorder:  eventBroadcaster.NewRecorder(...),
}).SetupWithManager(mgr, deployConfig, ingressConfig); err != nil { ... }

同一段代码还挂了 TrainedModelReconcilerInferenceGraphReconciler。Webhook 侧注册了 /mutate-pods(处理器 pod.Mutator,每个推理 Pod 创建时被它"改一刀"注入 agent、storage-initializer、metrics-aggregator 等容器,第 4 篇),另有 ServingRuntime / ClusterServingRuntime / TrainedModel / InferenceGraph 四个 Validator,InferenceService 则是 Defaulter(漏填的字段它来补)+ Validator(填错的字段它来拦)一对。

注意:main.go 没直接用 ctrl.NewControllerManagedBy 建控制器,而是让每个 Reconciler 自己实现 SetupWithManager------KServe 的依赖是可选的。看 controller.go(真实代码):

go 复制代码
ksvcFound, err := utils.IsCrdAvailable(r.ClientConfig,
	knservingv1.SchemeGroupVersion.String(), constants.KnativeServiceKind)
if err != nil {
	return err
}   // ← 装没装 Knative?
...
ctrlBuilder := ctrl.NewControllerManagedBy(mgr).
	For(&v1beta1.InferenceService{}).   // ← 主对象
	Owns(&appsv1.Deployment{}).         // ← 我创建的子资源,它们变了也要调和
	Owns(&corev1.Service{})

if ksvcFound {
	ctrlBuilder = ctrlBuilder.Owns(&knservingv1.Service{})  // ← 装了 Knative 才 watch
}

同样的探测还出现在 KEDA ScaledObject、Istio VirtualService、Gateway API HTTPRoute 上------"运行时可插拔"的源码根基就在这。Reconcile 主循环骨架(真实代码,controller.go):

go 复制代码
componentReconcilers := []components.Component{}
if deploymentMode != constants.ModelMeshDeployment {
	componentReconcilers = append(componentReconcilers, components.NewPredictor(...))
}   // ← ModelMesh 模式不建 Predictor
if isvc.Spec.Transformer != nil {
	componentReconcilers = append(componentReconcilers, components.NewTransformer(...))
}
// Explainer 同理,写了才加
for _, reconciler := range componentReconcilers {
	reconciler.Reconcile(ctx, isvc)   // ← 逐个组件调和
}

YAML 里有什么组件,这里就实例化什么 reconciler------CRD 的 spec 和控制器代码在这接上头,完整流程第 3 篇逐行走。


源码阅读路线图

10 篇与目录的对应表(主线第 2、3、4 篇,其余是支线可跳读):

对应目录
1(本篇) cmd/managerpkg/ 全景
2 pkg/apis/serving/v1beta1
3 pkg/controller/v1beta1/inferenceservice/controller.go
4 .../inferenceservice/components/reconcilers/factory.gopkg/agentpkg/batcherpkg/logger
5 pkg/agentpkg/credentialspkg/controller/v1alpha1/localmodel
6 .../inferenceservice/reconcilers/ingress/
7 .../reconcilers/autoscaler/knative/keda/hpa/
8 pkg/controller/v1alpha1/trainedmodelpkg/modelconfig
9 pkg/controller/v1alpha1/inferencegraphcmd/router
10 pkg/controller/v1alpha2/llmisvcpkg/apis/serving/v1alpha2/llm_inference_service_types.go

一句话总结

KServe 仓库 = 控制面(cmd/manager + pkg/controller + pkg/webhook)+ 数据面(cmd/agent + kserve/python)。控制面一个进程跑三套控制器,启动时探测 CRD 动态装配 Knative/Istio/KEDA;agent 在数据面干下载、日志、批处理。读懂 KServe:从 cmd/manager/main.go 进,沿 pkg/apispkg/controller 下潜。

下一篇预告:第 2 篇 InferenceService API:一个 CRD 如何承载全部配置。predictor、transformer、explainer、canary、logger、batcher......这么多能力塞进一个 YAML,Go 结构体怎么组织的?默认值和校验谁在管?

相关推荐
黄敬峰5 小时前
一文讲透 JWT 登录鉴权:token 的「颁发 → 存储 → 携带 → 校验」完整闭环
面试
AKAMAI5 小时前
超大规模的新定义
人工智能·云计算
LayZhangStrive6 小时前
融360 一面
java·面试·后端开发
城管不管6 小时前
重生——第十次面试之开源中国一面挂
java·linux·开发语言·算法·面试·职场和发展·开源
tg_xianheyun7 小时前
阿里云国际账号注册代充值怎么选服务商?
服务器·阿里云·云计算·全球访问优化
程序猿阿森7 小时前
Python 闭包与装饰器:从入门到精通
开发语言·python·面试
翼龙云_cloud8 小时前
腾讯云国际代理商:CDB数据库自动备份和异地灾备配置 从快照到跨区域恢复
运维·数据库·云计算·腾讯云
做前端的娜娜子8 小时前
async/await 错误处理:try...catch vs .catch() 完全指南
前端·面试·掘金·金石计划
Scabbards_8 小时前
面试Leetcode - 算法合集
算法·leetcode·面试