Seldon Core v2 CLI 模型卸载指南:深入解析 `seldon model unload` 命令

原创2026-10-14 16:36:101,863 阅读
文章标签:人工智能大模型MLOpsLLMOps模型推理服务云原生后端

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 工具函数解析目标模型,支持两种方式:

  1. 位置参数指定名称:直接以模型名作为第一个位置参数传入,例如 seldon model unload iris。
  2. -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
}

其处理逻辑分两步:

  1. 同步移除模型:调用 s.modelStore.RemoveModel(req) 从模型仓库中移除该模型。若移除失败(例如模型不存在、正处于其他不可卸载状态),返回 FailedPrecondition 状态错误;
  2. 异步触发重调度:在 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 根命令帮助。

如需深入底层实现,可继续阅读仓库中的以下文件:

登录后查看全文
seldon-core