Container Storage Interface (CSI)是一项规定存储供应商如何来提供存储服务作为Plugin,可以同时被多个Container Orchestration (CO)系统接受的接口标准。
目前接受CSI的CO有K8s,Mesos,Cloudfoundary。CSI的标准和Protobuf接口代码位于github的这里
生成的plugin可以灵活部署。分为controller plugin和node plugin两部分。既可以分别部署在master和普通node上,也可以单独部署controller plugin和node plugin。其中controller plugin是用来做管理的比如创建/删除,attach/detach。node plugin是运行在每个节点上的,特别是在使用storage的节点上必须安装。
headless plugin.
"headless"这个词用在Computer science的context是指缺少一部分,特别是图像显示的部分。比如命令行的mode。参见
这里用headless的意思是master node上就不安装插件了,完全是在node节点上运行,controller和node plugin可以分开来运行,也可以合一来运行,也可以单单运行node plugin。因为没有master,所以没有头了。无头指挥。
Spec里的状态机如下。
Controller.createVolume() => CREATED => Controller.publishVolume() => NODE_READY => Node.stageVolume() => VOL_READY => Node.publishVolume() => PUBLISHED
首先是Controller把Volume的状态改变成对某些节点available。然后是node接收,把这个Volume变成在本节点可使用。
CO ------------ gRPC ---------- plugin (Indentity service, controller service, and node service)
service Identity {
rpc GetPluginInfo(GetPluginInfoRequest)
returns (GetPluginInfoResponse) {}
rpc GetPluginCapabilities(GetPluginCapabilitiesRequest)
returns (GetPluginCapabilitiesResponse) {} // 这里会拿到feature,比如是否支持online volume expansion,是否VOLUME被cluster内的所有节点
rpc Probe (ProbeRequest)
returns (ProbeResponse) {} // 类似于Ping,report初始化是否ready
}
service Controller {
rpc CreateVolume (CreateVolumeRequest) // 提出各种需求比如,capacity,topology, etc
returns (CreateVolumeResponse) {} // 返回创建的volume
rpc DeleteVolume (DeleteVolumeRequest)
returns (DeleteVolumeResponse) {}
rpc ControllerPublishVolume (ControllerPublishVolumeRequest)
returns (ControllerPublishVolumeResponse) {} // 使这个Volume在指定node上available
rpc ControllerUnpublishVolume (ControllerUnpublishVolumeRequest)
returns (ControllerUnpublishVolumeResponse) {}
rpc ValidateVolumeCapabilities (ValidateVolumeCapabilitiesRequest)
returns (ValidateVolumeCapabilitiesResponse) {}
rpc ListVolumes (ListVolumesRequest)
returns (ListVolumesResponse) {} // 返回volume entries
rpc GetCapacity (GetCapacityRequest)
returns (GetCapacityResponse) {}
rpc ControllerGetCapabilities (ControllerGetCapabilitiesRequest)
returns (ControllerGetCapabilitiesResponse) {}
rpc CreateSnapshot (CreateSnapshotRequest)
returns (CreateSnapshotResponse) {} // 打快照,返回快照信息
rpc DeleteSnapshot (DeleteSnapshotRequest)
returns (DeleteSnapshotResponse) {}
rpc ListSnapshots (ListSnapshotsRequest)
returns (ListSnapshotsResponse) {}
rpc ControllerExpandVolume (ControllerExpandVolumeRequest)
returns (ControllerExpandVolumeResponse) {}
}
service Node {
rpc NodeStageVolume (NodeStageVolumeRequest) // 提供Volume要被stage的path
returns (NodeStageVolumeResponse) {}
rpc NodeUnstageVolume (NodeUnstageVolumeRequest)
returns (NodeUnstageVolumeResponse) {}
rpc NodePublishVolume (NodePublishVolumeRequest) // 当负载需要使用volume的时候,CO会call它。access mode会决定是不是多个NODE共享volume
returns (NodePublishVolumeResponse) {}
rpc NodeUnpublishVolume (NodeUnpublishVolumeRequest)
returns (NodeUnpublishVolumeResponse) {}
rpc NodeGetVolumeStats (NodeGetVolumeStatsRequest)
returns (NodeGetVolumeStatsResponse) {}
rpc NodeExpandVolume(NodeExpandVolumeRequest)
returns (NodeExpandVolumeResponse) {}
rpc NodeGetCapabilities (NodeGetCapabilitiesRequest)
returns (NodeGetCapabilitiesResponse) {}
rpc NodeGetInfo (NodeGetInfoRequest)
returns (NodeGetInfoResponse) {}
}
可以看到这里功能分层还是比较明显的。分controller和node实现了上面说的状态机。
K8s支持不同TYPE的Volume,比如FC,Iscsi,cephfs,nfs,azureDisk,azureFile。
所以包含了FS和BLOCK。
也有基于公司的,portworxVolume,scaleIO,storageos
特殊的几个:csi 前面刚刚提到的, downwardAPI (expose metadata via a file interface),persistentVolumeClaim
Volume的生命周期和POD一样。定义 POD的时候可以定义Volume。
注意K8s利用Volume概念克服了Container crash的问题。Volume的生命周期与Container不同。
PV是独立于POD生命周期之外的存储资源,是K8s集群的系统资源,所以称之为Persistent。PVC是使用这些资源的请求。
PV可以在使用PVC的时候被动态provisioned,就像malloc。PVC需要指定StorageClass, which consists of
通过定义下面几项,StorageClass具体定义了某种存储,就是declare一个StorageClass Object
一个K8s官方的例子
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: standard
provisioner: kubernetes.io/aws-ebs
parameters:
type: gp2
reclaimPolicy: Retain
mountOptions:
- debug
volumeBindingMode: Immediate
PVC需要声明使用者的意图,所以需要引用已经定义好的StorageClass Object。
PVC:
前面说的每个TYPE都要提供自己的StorageClass说明,才能被PVC使用。
PV也类似,但是直接定义卷
就像上面Kubernetes官方文档显示的定义一个provisioner for AWS的EBS卷一样。要使用CSI, type CSI也要定义自己的StorageClass。
Docker把K8s里面的TYPE,叫做DRIVER。根据这篇文章, K8s先搞出Volume这个概念。
比如REX-ray就是Container的DRIVER概念。是Docker的一个plugin。REX-Ray是Vendor neutral的。
Docker/Docker Swarm的Volume概念比K8s要简单,没有生命周期的管理,没有动态分配。也许我不知道而已。
如果你两套机制都用的话,可以用K8s的declare来overwrite Docker definition。见Stackoverflow文章