4. Identity Service 详解:GetPluginInfo、GetPluginCapabilities、Probe 三个 RPC 的实现规范与适配要点

Identity Service 是 CSI 规范中所有存储插件必须实现的三个服务之一,也是 kubelet 与 CSI 驱动建立通信后调用的第一组 RPC。该服务不涉及任何存储数据面操作,其核心职责是身份声明、能力通告与健康自检。在移植适配过程中,Identity Service 的实现质量直接决定插件能否通过 Kubernetes 的节点注册与健康检查流程。

4.1 三个 RPC 的规范总览

下表从调用时机、核心字段、返回码三个维度对比三个 RPC 的规范差异:

RPC 名称 调用时机 核心请求字段 核心响应字段 关键错误码
GetPluginInfo 插件注册、kubelet 启动时 无 name, vendor_version, manifest OK, UNIMPLEMENTED
GetPluginCapabilities 紧随 GetPluginInfo 之后 无 capabilities (Service, VolumeAccessibility, etc.) OK, UNIMPLEMENTED
Probe 周期性健康检查、挂载前 无 ready (bool) OK, NOT_READY, UNIMPLEMENTED
适配要点:三个 RPC 的请求消息体均为空(无必填字段),但响应消息的字段完整性直接影响 kubelet 的注册决策。例如 GetPluginInfo 返回的 name 必须符合反向域名格式(如 csi.example.com),否则 kubelet 会拒绝注册。

4.2 GetPluginInfo:身份声明与版本契约

GetPluginInfo 是 kubelet 调用 CSI 驱动的第一个 RPC,用于获取插件的唯一标识与版本信息。该 RPC 的实现必须满足以下规范约束:

  • name 字段:必须为反向域名格式,且全局唯一。例如 csi.huawei.com 或 csi.ceph.com。kubelet 使用该名称在节点上注册 CSINode 对象。
  • vendor_version 字段:语义化版本号,如 3.5.0。该版本号会被记录在 CSINode 对象的 annotation 中,用于运维排查。
  • manifest 字段:可选键值对,用于携带驱动元数据(如驱动描述、支持协议版本等)。
  • 错误处理:如果插件无法提供身份信息,应返回 gRPC Status::UNIMPLEMENTED,但实际生产环境中该 RPC 必须实现,否则 kubelet 无法完成注册。
// GetPluginInfo 响应示例(protobuf 序列化后)
{
  "name": "csi.huawei.storage",
  "vendor_version": "2.1.0",
  "manifest": {
    "url": "https://github.com/huawei/csi-driver",
    "supported_csi_spec": "1.5.0, 1.6.0"
  }
}
移植陷阱:部分存储厂商在移植时直接返回硬编码的 name 和 version,但未考虑多实例部署场景。如果同一集群中部署了多个 CSI 驱动实例(如不同后端存储),name 必须区分,否则会导致 CSINode 对象冲突。

4.3 GetPluginCapabilities:能力通告与特性协商

GetPluginCapabilities 用于向 Kubernetes 通告插件支持的服务类型与扩展特性。CSI 规范定义了三种核心能力类型:

能力类型 枚举值 说明 适配要求
Controller Service CONTROLLER_SERVICE 支持卷的创建、删除、挂载、快照等控制面操作 如果插件实现了 Controller Server,必须声明此能力
Volume Accessibility VOLUME_ACCESSIBILITY_CONSTRAINTS 支持拓扑感知调度(如区域、可用区约束) 如果后端存储有拓扑限制,必须声明并实现拓扑键
Node Service NODE_SERVICE 支持节点级卷挂载、卸载、阶段挂载等操作 所有 CSI 驱动必须实现,否则无法完成挂载

此外,CSI 1.5+ 规范还引入了 UNKNOWN 能力类型用于扩展。适配时建议按以下步骤实现:

  1. 根据插件实际实现的服务(Controller / Node)声明对应能力。
  2. 如果后端存储支持拓扑约束,添加 VOLUME_ACCESSIBILITY_CONSTRAINTS 并实现拓扑键。
  3. 对于不支持的能力(如快照、扩容),不要在 capabilities 中声明,否则 Kubernetes 会尝试调用对应 RPC 并导致错误。
// GetPluginCapabilities 响应示例
{
  "capabilities": [
    {"service": {"type": "CONTROLLER_SERVICE"}},
    {"service": {"type": "NODE_SERVICE"}},
    {"volume_accessibility_constraints": {"required": true}}
  ]
}

4.4 Probe:健康自检与就绪状态

Probe RPC 是 kubelet 对 CSI 驱动进行健康检查的唯一接口。与 Kubernetes 的 livenessProbe 和 readinessProbe 不同,CSI 驱动的健康状态完全由 Probe 的返回值决定:

  • ready = true:驱动正常运行,可以处理后续 RPC 请求。
  • ready = false:驱动未就绪,kubelet 会停止向该驱动发送卷操作请求,并持续重试 Probe。
  • 返回 NOT_READY 错误:与 ready=false 等效,但更适用于驱动初始化未完成或依赖服务不可用等场景。
实现建议:Probe 的实现应轻量且快速。常见的检查项包括:
  • 后端存储连接状态(如 TCP 连接、API 响应超时)
  • 本地 socket 文件是否存在且可读写
  • 驱动内部 goroutine 是否健康(如心跳超时检测)
避免在 Probe 中执行重量级操作(如创建临时卷),否则可能导致 kubelet 健康检查超时。
// Probe 响应示例(就绪状态)
{
  "ready": true
}

// Probe 响应示例(未就绪状态)
{
  "ready": false
}
// 或返回 gRPC 错误码 NOT_READY

4.5 三个 RPC 的调用流程与适配要点

下图展示了 kubelet 在节点注册阶段调用 Identity Service 三个 RPC 的完整流程:

Identity Service 调用流程与适配要点 kubelet CSI Driver 1. GetPluginInfo name + vendor_version 2. GetPluginCapabilities capabilities 列表 3. Probe(周期性) ready: true / false 适配要点总结 • GetPluginInfo:name 必须反向域名格式,vendor_version 语义化版本 • GetPluginCapabilities:只声明实际实现的能力,避免虚假声明 • Probe:轻量快速,ready=false 时 kubelet 停止卷操作

4.6 移植适配中的常见问题与避坑指南

问题场景 现象 根因 解决方案
GetPluginInfo 返回空 name kubelet 日志报错 "invalid plugin name" name 字段为空或不符合反向域名格式 检查驱动配置,确保 name 为 csi.<vendor>.<product> 格式
GetPluginCapabilities 声明了未实现的能力 调用对应 RPC 时返回 UNIMPLEMENTED 能力声明与实际实现不一致 移除未实现的能力枚举值
Probe 返回 NOT_READY 但驱动实际正常 kubelet 反复重试,卷挂载延迟 Probe 实现中包含了不必要的依赖检查 简化 Probe 逻辑,仅检查核心依赖
Probe 超时导致 kubelet 认为驱动异常 CSINode 对象被标记为 NotReady Probe 实现中执行了阻塞操作 设置 Probe 超时时间(建议 < 5s),避免网络调用
调试技巧:在移植适配阶段,可以使用 csi-sanity 工具对 Identity Service 进行独立测试。该工具会依次调用三个 RPC 并验证响应字段的合规性,是快速定位适配问题的有效手段。