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:认证插件身份信息,提供插件名称、版本等。
go
// 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:处理存储卷的创建、删除、挂接、摘除、扩容等操作。
go
// ControllerServer is the server API for Controller service.
type ControllerServer interface {
// 创建存储卷
CreateVolume(context.Context, *CreateVolumeRequest) (*CreateVolumeResponse, error)
// 删除存储卷
DeleteVolume(context.Context, *DeleteVolumeRequest) (*DeleteVolumeResponse, error)
// 挂接存储卷到特定节点
ControllerPublishVolume(context.Context, *ControllerPublishVolumeRequest) (*ControllerPublishVolumeResponse, error)
// 从特定节点摘除存储卷
ControllerUnpublishVolume(context.Context, *ControllerUnpublishVolumeRequest) (*ControllerUnpublishVolumeResponse, error)
// 验证存储卷能力是否满足要求,比如是否支持跨节点多读多写
ValidateVolumeCapabilities(context.Context, *ValidateVolumeCapabilitiesRequest) (*ValidateVolumeCapabilitiesResponse, error)
// 列举全部存储卷信息
ListVolumes(context.Context, *ListVolumesRequest) (*ListVolumesResponse, error)
// 获取存储资源池可用空间大小
GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error)
// 获取ControllerServer支持功能点,比如是否支持快照能力
ControllerGetCapabilities(context.Context, *ControllerGetCapabilitiesRequest) (*ControllerGetCapabilitiesResponse, error)
// 创建快照
CreateSnapshot(context.Context, *CreateSnapshotRequest) (*CreateSnapshotResponse, error)
// 删除快照
DeleteSnapshot(context.Context, *DeleteSnapshotRequest) (*DeleteSnapshotResponse, error)
// 获取所有快照信息
ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error)
// 扩容存储卷
ControllerExpandVolume(context.Context, *ControllerExpandVolumeRequest) (*ControllerExpandVolumeResponse, error)
}
- NodeServer:负责存储卷在节点上的挂载、卸载、获取容量信息等。
go
// ControllerServer is the server API for Controller service.
type ControllerServer interface {
// 创建存储卷
CreateVolume(context.Context, *CreateVolumeRequest) (*CreateVolumeResponse, error)
// 删除存储卷
DeleteVolume(context.Context, *DeleteVolumeRequest) (*DeleteVolumeResponse, error)
// 挂接存储卷到特定节点
ControllerPublishVolume(context.Context, *ControllerPublishVolumeRequest) (*ControllerPublishVolumeResponse, error)
// 从特定节点摘除存储卷
ControllerUnpublishVolume(context.Context, *ControllerUnpublishVolumeRequest) (*ControllerUnpublishVolumeResponse, error)
// 验证存储卷能力是否满足要求,比如是否支持跨节点多读多写
ValidateVolumeCapabilities(context.Context, *ValidateVolumeCapabilitiesRequest) (*ValidateVolumeCapabilitiesResponse, error)
// 列举全部存储卷信息
ListVolumes(context.Context, *ListVolumesRequest) (*ListVolumesResponse, error)
// 获取存储资源池可用空间大小
GetCapacity(context.Context, *GetCapacityRequest) (*GetCapacityResponse, error)
// 获取ControllerServer支持功能点,比如是否支持快照能力
ControllerGetCapabilities(context.Context, *ControllerGetCapabilitiesRequest) (*ControllerGetCapabilitiesResponse, error)
// 创建快照
CreateSnapshot(context.Context, *CreateSnapshotRequest) (*CreateSnapshotResponse, error)
// 删除快照
DeleteSnapshot(context.Context, *DeleteSnapshotRequest) (*DeleteSnapshotResponse, error)
// 获取所有快照信息
ListSnapshots(context.Context, *ListSnapshotsRequest) (*ListSnapshotsResponse, error)
// 扩容存储卷
ControllerExpandVolume(context.Context, *ControllerExpandVolumeRequest) (*ControllerExpandVolumeResponse, error)
}
K8s CSI API对象
K8s 为支持 CSI 标准,包含如下 API 对象:
- CSINode:判断CSI插件是否注册成功,关联K8s节点和三方存储节点,显示卷拓扑信息。
yaml
apiVersion: storage.k8s.io/v1beta1
kind: CSINode
metadata:
name: node-10.212.101.210
spec:
drivers:
- name: yodaplugin.csi.alibabacloud.com
nodeID: node-10.212.101.210
topologyKeys:
- kubernetes.io/hostname
- name: pangu.csi.alibabacloud.com
nodeID: a5441fd9013042ee8104a674e4a9666a
topologyKeys:
- topology.pangu.csi.alibabacloud.com/zone
- CSIDriver:方便发现外部CSI插件,自定义K8s行为。
yaml
apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
name: pangu.csi.alibabacloud.com
spec:
# 插件是否支持卷挂接(VolumeAttach)
attachRequired: true
# Mount阶段是否CSI插件需要Pod信息
podInfoOnMount: true
# 指定CSI支持的卷模式
volumeLifecycleModes:
- Persistent
- VolumeAttachment:记录存储卷挂接/摘除和节点信息。
yaml
apiVersion: storage.k8s.io/v1
kind: VolumeAttachment
metadata:
annotations:
csi.alpha.kubernetes.io/node-id: 21481ae252a2457f9abcb86a3d02ba05
finalizers:
- external-attacher/pangu-csi-alibabacloud-com
name: csi-0996e5e9459e1ccc1b3a7aba07df4ef7301c8e283d99eabc1b69626b119ce750
spec:
attacher: pangu.csi.alibabacloud.com
nodeName: node-10.212.101.241
source:
persistentVolumeName: pangu-39aa24e7-8877-11eb-b02f-021234350de1
status:
attached: true
CSI支持特性
- 拓扑支持:依据节点拓扑挂载存储卷,提升数据访问效率。
- 存储卷扩容:用户修改PVC存储请求字段就能扩容,不过只能扩容不能缩容。
- 单节点卷数量限制:限制单个节点挂载存储卷的数量。
- 存储卷监控:存储商实现相关接口,Kubelet获取存储卷容量、使用量等指标。
- Secret:通过Secret处理存储过程中的私密数据。
- 块设备:三方存储厂商实现特定接口,K8s提供工具包支持块设备使用。
- 卷快照/卷克隆能力:可对存储卷进行快照和克隆,用于数据备份、恢复和快速创建新卷。
好了完结撒花!