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 能力类型用于扩展。适配时建议按以下步骤实现:
- 根据插件实际实现的服务(Controller / Node)声明对应能力。
- 如果后端存储支持拓扑约束,添加
VOLUME_ACCESSIBILITY_CONSTRAINTS并实现拓扑键。 - 对于不支持的能力(如快照、扩容),不要在 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 响应示例(就绪状态)
{
"ready": true
}
// Probe 响应示例(未就绪状态)
{
"ready": false
}
// 或返回 gRPC 错误码 NOT_READY
4.5 三个 RPC 的调用流程与适配要点
下图展示了 kubelet 在节点注册阶段调用 Identity Service 三个 RPC 的完整流程:
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 并验证响应字段的合规性,是快速定位适配问题的有效手段。