Seldon Core v2 CLI 模型卸载指南:深入解析 `seldon model unload` 命令
Seldon Core v2 CLI 模型卸载指南:深入解析 seldon model unload 命令
导读
seldon model unload 是 Seldon Core v2 命令行工具中用于卸载(卸载)已加载模型的子命令,其作用是通过 gRPC 调用控制面 Scheduler 服务,将指定模型从模型仓库中移除,并触发调度器重新调度以回收模型副本占用的资源。本文以该命令的官方 CLI 参考文档为主体,结合仓库源码深入讲解命令语法、全部参数、底层 gRPC 调用链与服务端处理逻辑,帮助你在 Kubernetes 集群或本地开发环境中安全、正确地执行模型卸载,并理解卸载操作与集群状态一致性的关系。
命令概览:它在 CLI 命令树中的位置
seldon model unload 隶属于 seldon model 子命令组。在 operator/cmd/seldon/cli/root.go 中可以看到,model 命令组注册了六个子命令:
cmdModel.AddCommand(cmdModelLoad, cmdModelUnload, cmdModelStatus, cmdModelInfer, cmdModelMeta, cmdModelList)
即模型管理共包含 load(加载)、unload(卸载)、status(状态查询)、infer(推理)、metadata(元数据)和 list(列表)六个操作。其中 model unload 与 model load 是一对对称操作,共同构成模型生命周期的核心环节;model status 则用于在卸载后确认模型的最终状态。
命令语法与 Synopsis
官方参考文档给出的语法如下:
seldon model unload <modelName> [flags]
<modelName>:要卸载的模型名称(位置参数,必填或与-f/--file-path二选一,详见下文"两种指定模型的方式")。[flags]:可选参数,用于指定 Scheduler 地址、请求显示方式等。
命令的作用描述为 "unload a model",即从 Scheduler 控制面卸载一个模型。
参数详解(Options)
官方文档的参数表如下,我们逐一解释并补充源码级细节:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
--authority string |
string | 空 | authority(HTTP/2 场景)或 virtual host(HTTP/1 场景) |
-h, --help |
- | - | 显示 unload 子命令的帮助信息 |
--scheduler-host string |
string | "0.0.0.0:9004" |
Seldon Scheduler 的主机地址 |
-r, --show-request |
bool | false |
显示请求内容 |
-o, --show-response |
bool | true |
显示响应内容 |
--scheduler-host:Scheduler 控制面地址
该参数指定 Scheduler 服务的 gRPC 端点,默认值为 0.0.0.0:9004。在 operator/cmd/seldon/cli/flags.go 中可以看到默认值常量 defaultSchedulerHost = "0.0.0.0:9004"。
该参数支持环境变量覆盖:命令注册标志时使用 env.GetString(envScheduler, defaultSchedulerHost),即环境变量 SELDON_SCHEDULE_HOST(注意拼写为 SCHEDULE 而非 SCHEDULER)优先于默认值。若在命令行中显式传入 --scheduler-host,则以命令行值为准;否则优先读取环境变量,其次使用默认值。
--authority:gRPC authority 头
该参数对应 gRPC 的 authority(HTTP/2)或虚拟主机名(HTTP/1),在创建连接时通过 grpc.WithAuthority(sc.authority) 注入(见 operator/pkg/cli/scheduler.go)。在通过 Envoy 代理或配置了 TLS SNI(Server Name Indication)的环境中,该参数用于指定虚拟主机名;本地直连 Scheduler 时通常无需设置。
-r/--show-request 与 -o/--show-response
这两个标志在官方文档中列出,用于控制请求与响应的显示。不过需要指出:从当前仓库的 operator/cmd/seldon/cli/model_unload.go 源码来看,unload 子命令实际注册的标志是 -v/--verbose、--scheduler-host、--authority、-f/--file-path 与 --force,未显式注册 show-request/show-response。这两个标志出现在文档中,与 server status、model infer 等命令共享的标志集一致(见 operator/cmd/seldon/cli/flags.go),属于文档自动生成时保留的公共选项。-o/--show-response 默认值为 true,表明命令默认打印响应。
源码中实际注册的标志(文档未列出)
在 operator/cmd/seldon/cli/model_unload.go 中,命令实际注册了以下标志:
| 标志 | 说明 |
|---|---|
-v, --verbose |
冗余输出,开启后在发送请求前打印请求 proto(见 scheduler.go 中 if sc.verbose { printProto(req) }) |
--scheduler-host |
Scheduler 地址,默认 0.0.0.0:9004 |
--authority |
gRPC authority / HTTP 虚拟主机 |
-f, --file-path |
模型清单文件(YAML),用于以文件方式指定模型 |
--force |
强制控制面模式,默认 false,由环境变量 SELDON_FORCE_CONTROL_PLANE 控制 |
两种指定模型的方式
unload 命令通过 operator/cmd/seldon/cli/file.go 中的 extractFileOrName 工具函数解析目标模型,支持两种方式:
- 位置参数指定名称:直接以模型名作为第一个位置参数传入,例如
seldon model unload iris。 -f/--file-path指定清单文件:传入 YAML 格式的 Model 清单文件。若同时提供位置参数与文件参数,则以文件参数为准。
若指定了文件而未提供模型名,CLI 会将文件解析为 Model 对象并取其 metadata.name 作为模型名。这一逻辑在 operator/pkg/cli/scheduler.go 的 UnloadModel 方法中体现:
if len(modelBytes) > 0 && modelName == "" {
model := &mlopsv1alpha1.Model{}
err := unMarshallYamlStrict(modelBytes, model)
...
modelName = model.Name
}
其中 unMarshallYamlStrict 使用严格的 YAML 解码(DisallowUnknownFields()),意味着清单文件中出现未知字段会直接报错,从而避免误卸载。
一个可用的 Model 清单示例见仓库 samples/models/iris-v1.yaml:
apiVersion: mlops.seldon.io/v1alpha1
kind: Model
metadata:
name: iris
spec:
storageUri: "gs://seldon-models/scv2/samples/rolling/iris/v1"
requirements:
- sklearn
将上述文件保存后,可执行 seldon model unload -f iris-v1.yaml 来卸载名为 iris 的模型。
底层调用链:从 CLI 到 Scheduler 服务端
第一步:创建 Scheduler gRPC 客户端
命令的 RunE 函数首先通过 cli.NewSchedulerClient(schedulerHost, schedulerHostIsSet, authority, verbose) 创建客户端(operator/pkg/cli/scheduler.go)。该客户端会:
- 尝试加载 CLI 配置文件
SeldonCLIConfig,若配置中指定了控制面地址(config.Controlplane.SchedulerHost)且命令行未显式传入--scheduler-host,则使用配置文件中的地址覆盖; - 根据配置决定使用 TLS 还是明文连接:若配置了
Controlplane.KeyPath等证书路径,则加载证书(loadKeyPair)建立 TLS 连接,否则使用insecure.NewCredentials(); - 为连接配置指数退避重试拦截器(
grpc_retry.BackoffExponential(100 * time.Millisecond))以及最大收发消息大小(math.MaxInt32)。
第二步:构造 UnloadModelRequest 并调用 gRPC
客户端构造 scheduler.UnloadModelRequest,其中携带 ModelReference(模型引用,含模型名与可选的版本号,见 apis/mlops/scheduler/scheduler.proto):
message ModelReference {
string name = 1;
optional uint32 version = 2;
}
message UnloadModelRequest {
ModelReference model = 1;
optional KubernetesMeta kubernetesMeta = 2;
}
message UnloadModelResponse {
}
随后通过 grpcClient.UnloadModel(context.Background(), req) 发起 gRPC 调用(operator/pkg/cli/scheduler.go)。服务端接口定义于 apis/mlops/scheduler/scheduler.proto:
rpc UnloadModel(UnloadModelRequest) returns (UnloadModelResponse) {};
第三步:服务端处理与异步调度
Scheduler 服务端的 UnloadModel 实现位于 scheduler/pkg/server/server.go:
func (s *SchedulerServer) UnloadModel(ctx context.Context, req *pb.UnloadModelRequest) (*pb.UnloadModelResponse, error) {
logger := s.logger.WithField("func", "UnloadModel")
logger.Debugf("Unload model %s", req.GetModel().Name)
err := s.modelStore.RemoveModel(req)
if err != nil {
return nil, status.Errorf(codes.FailedPrecondition, "%s", err.Error())
}
go func() {
err := s.scheduler.Schedule(req.GetModel().Name)
if err != nil {
logger.WithError(err).Warnf("Failed to schedule model %s (for unload)", req.GetModel().GetName())
}
}()
return &pb.UnloadModelResponse{}, nil
}
其处理逻辑分两步:
- 同步移除模型:调用
s.modelStore.RemoveModel(req)从模型仓库中移除该模型。若移除失败(例如模型不存在、正处于其他不可卸载状态),返回FailedPrecondition状态错误; - 异步触发重调度:在 goroutine 中调用
s.scheduler.Schedule(modelName),让调度器重新计算模型分配。卸载场景下,调度器会将该模型的副本从各服务器上移除,从而释放内存与 GPU 等资源,并把相关副本状态更新为终止态(ModelTerminated)。
第四步:结果输出
命令执行成功后返回空的 UnloadModelResponse。开启 -v/--verbose 时,CLI 会在发送请求前打印请求 proto,并在响应返回后调用 cli.PrintProto(res) 打印响应内容(operator/cmd/seldon/cli/model_unload.go)。
卸载后的验证
卸载是异步完成的(服务端触发后台 Schedule),因此建议在卸载后使用 seldon model status 命令确认模型状态:
seldon model status <modelName> [--wait ModelTerminated]
其中 --wait 参数可指定期望的等待条件,命令会轮询模型状态直至满足条件或超时(轮询间隔 1 秒,见 operator/pkg/cli/scheduler.go)。CLI 的 ListModels 实现中会过滤掉已处于 ModelTerminated 状态的模型(operator/pkg/cli/scheduler.go),因此卸载完成后该模型也不会再出现在 seldon model list 的输出中。
重要注意事项:--force 与集群一致性
从源码可见,seldon model unload 与 load、experiment start/stop 等控制面操作一样,都带有一个 --force 标志(operator/cmd/seldon/cli/flags.go):
--force force control plane mode (load model, etc.), default is false
执行命令时,CLI 会先打印一条警告(operator/cmd/seldon/cli/flags.go):
This command is likely to cause inconsistencies in your k8s cluster, enable with care.
该警告提醒:直接通过 CLI 控制面接口(而非 Kubernetes CRD)卸载模型,可能与 Kubernetes 集群中的期望状态产生不一致。在正常使用中,模型的加载与卸载应由 Kubernetes 控制器通过 Model 自定义资源(CRD)的增删来驱动;只有当显式传入 --force(或设置环境变量 SELDON_FORCE_CONTROL_PLANE=true)时,命令才会真正调用 Scheduler 执行卸载,否则在打印警告后直接返回。
因此,推荐的正规卸载方式是删除对应的 Kubernetes Model 资源(如 kubectl delete model iris),让控制器通过与 scheduler_client.go 相同的 gRPC 通道向 Scheduler 发起卸载。seldon model unload --force 仅适用于调试、故障恢复或本地(非 Kubernetes 托管)环境,使用时需自行承担集群状态不一致的风险。这一设计在 unload.go 中实现一致的通用 unload 命令中同样生效。
相关命令与延伸阅读
- seldon model:模型管理命令组总览,包含
load、infer、status、metadata、list等子命令; - seldon model load:模型加载命令,与
unload构成对称的生命周期操作; - seldon model status:查询模型加载状态,用于卸载后验证;
- seldon:CLI 根命令帮助。
如需深入底层实现,可继续阅读仓库中的以下文件:
- operator/cmd/seldon/cli/model_unload.go:
unload子命令的完整实现; - operator/pkg/cli/scheduler.go:Scheduler gRPC 客户端与
UnloadModel方法; - apis/mlops/scheduler/scheduler.proto:
UnloadModelgRPC 服务与消息定义; - scheduler/pkg/server/server.go:Scheduler 服务端的卸载处理逻辑;
- scheduler/pkg/scheduler/cleaner/versions.go:调度器卸载模型副本的相关实现。