CSI出现的原因
K8s原生支持一些存储类型的PV,像iSCSI、NFS等。但这种方式让K8s代码与三方存储厂商代码紧密相连
,带来不少麻烦。比如更改存储代码就得更新K8s组件,成本高
;存储代码的bug还会影响K8s稳定性;K8s社区维护和测试负担重
,而且存储插件特权高,存在安全隐患。CSI的出现,就是为了解决这些问题,把三方存储代码和K8s代码分开
,让存储厂商开发插件更轻松。
CSI核心流程分三步
-
Provision/Delete(创盘/删盘):用户创建PVC,K8s根据PVC和StorageClass,让External Provisioner调用CSI插件创盘,之后创建PV并绑定PVC。删盘时,External Provisioner根据PVC回收策略,调用CSI插件删盘并删除PV。
-
Attach/Detach(挂接/摘除):Pod调度到节点后,AD控制器创建VolumeAttachment对象,External Attacher调用CSI插件挂接存储卷,完成后更新状态。Pod删除时,AD控制器删除VolumeAttachment对象,External Attacher调用插件摘除存储卷。
-
Mount/Unmount(挂载/卸载):Kubelet发现使用CSI类型PV的Pod调度到本节点,等待VolumeAttachment状态就绪,调用CSI插件挂载。Pod删除时,Kubelet调用插件卸载。
CSI Sidecar组件
为使 K8s 适配 CSI 标准,社区将与 K8s 相关的存储流程逻辑放在了 CSI Sidecar
组件中。
- Node Driver Registrar:负责把外部CSI插件注册到Kubelet,让Kubelet能调用插件函数。
- External Provisioner:创建或删除存储卷和PV资源。
- External Attacher:实现存储卷的挂接和摘除。
- External Resizer:监控PVC,满足条件时调用CSI插件扩容存储卷。
- livenessprobe:通过暴露端口检查CSI插件是否正常运行。
CSI接口
三方存储厂商需实现 CSI 插件的三大接口:IdentityServer
、ControllerServer
、NodeServer
。
- IdentityServer:认证插件身份信息,提供插件名称、版本等。
// IdentityServer is the server API for Identity service.
type IdentityServer interface {
// 获取CSI插件的信息,比如名称、版本号
GetPluginInfo(context.Context, *GetPluginInfoRequest) (*GetPluginInfoResponse, error)
// 获取CSI插件提供的能力,比如是否提供ControllerService能力
GetPluginCapabilities(context.Context, *GetPluginCapabilitiesRequest) (*GetPluginCapabilitiesResponse, error)
// 获取CSI插件健康状况
Probe(context.Context, *ProbeRequest) (*ProbeResponse, error)
}
- ControllerServer:处理存储卷的创建、删除、挂接、摘除、扩容等操作。
// ControllerServer is the server API for Controller service.
type ControllerServer interface {
// 创建存储卷
CreateVolume(context.Context, *CreateVolumeRequest)