WHY
In-Tree: 需要将後端存儲的代碼邏輯放到K8S的代碼中運作。邏輯代碼可能會引起與K8S其他部件之間的互相影響。
Flexvolume: 調用一個主機的可執行程式包的方式執行存儲卷的挂載使用。解決了In-Tree方式的強耦合,不過指令行調用的方式,在主機安全性、部署依賴的容器化、與K8S服務之間的互相擴充性等方面存在不足
Flexvolume運作在host 空間,不能使用rbac授權機制通路Kubernetes API,導緻其功能極大的受限。
CSI: CSI标準使K8S和存儲提供者之間将徹底解耦,将存儲的所有的部件作為容器形式運作在K8S上。
目前版本資訊:
Kubernetes | CSI Version | CSI Status |
---|---|---|
v1.9 | v0.1 | Alpha |
v1.10 | v0.2 | Beta |
v1.11 | v0.3 | Beta |
v1.12 | v0.3 | Beta |
v1.13 | v1.0.0 | GA |
CSI是Container Storage Interface的縮寫。CSI是由來自Kubernetes、Mesos、 Docker等社群的member聯合制定的一個行業标準接口規範,旨在将任意存儲系統暴露給容器化應用程式。CSI規範定義了存儲提供商(SP)實作CSI相容插件的最小操作集和部署建議。CSI規範的主要焦點是聲明插件必須實作的接口
架構圖

三個獨立的外部元件(External Components),即:Driver Registrar、External Provisioner 和 External Attacher,對應的正是從 Kubernetes 項目裡面剝離出來的那部分存儲管理功能。
External Components 雖然是外部元件,但依然由 Kubernetes 社群來開發和維護。
參考:http://bamboox.online/k8s-15-%E5%AD%98%E5%82%A8-02.html
Driver Registrar
将插件注冊到 kubelet ,需要請求 CSI 插件的 Identity 服務來擷取插件資訊
External Provisioner
Watch APIServer 的 PVC 對象,PVC 被建立時,就會調用 CSI Controller 的 CreateVolume 方法,建立對應 PV
External Attacher
Watch APIServer 的 VolumeAttachment 對象,就會調用 CSI Controller 服務的 ControllerPublish 方法,完成它所對應的 Volume 的 Attach 階段
開發步驟
- Create a containerized application implementing the Identity, Node, and optionally the Controller services described in the CSI specification (the CSI driver container). See Developing CSI Driver for more information.
- Unit test it using csi-sanity. See Driver - Unit Testing for more information.
- Define Kubernetes API YAML files that deploy the CSI driver container along with appropriate sidecar containers. See Deploying in Kubernetes for more information.
- Deploy the driver on a Kubernetes cluster and run end-to-end functional tests on it. See Driver - Functional Testing
At a minimum, CSI drivers must implement the following CSI services:
- CSI
service
Identity
- Enables callers (Kubernetes components and CSI sidecar containers) to identify the driver and what optional functionality it supports.
- CSI
service
Node
- Only
,
NodePublishVolume
, and
NodeUnpublishVolume
are required.
NodeGetCapabilities
- Required methods enable callers to make a volume available at a specified path and discover what optional functionality the driver supports.
一. Identity 身份服務
Node Plugin和Controller Plugin都必須實作這些RPC集。協調kubernetes與csi的版本資訊,
負責對外暴露這個插件的資訊
service Identity {
rpc GetPluginInfo(GetPluginInfoRequest)
returns (GetPluginInfoResponse) {}
rpc GetPluginCapabilities(GetPluginCapabilitiesRequest)
returns (GetPluginCapabilitiesResponse) {}
rpc Probe (ProbeRequest)
returns (ProbeResponse) {}
}
- PluginCapability_Service_CONTROLLER_SERVICE:代表對 ControllerService 插件提供 RPC 服務,這個是可選的,如果實作了就開啟
- PluginCapability_Service_VOLUME_ACCESSIBILITY_CONSTRAINTS:代表 volume 在叢集中通路限制
二. Controller 控制器服務
Controller Plugin必須實作這些RPC集。建立以及管理volume管理卷
service Controller {
rpc CreateVolume (CreateVolumeRequest)
returns (CreateVolumeResponse) {}
rpc DeleteVolume (DeleteVolumeRequest)
returns (DeleteVolumeResponse) {}
rpc ControllerPublishVolume (ControllerPublishVolumeRequest)
returns (ControllerPublishVolumeResponse) {}
rpc ControllerUnpublishVolume (ControllerUnpublishVolumeRequest)
returns (ControllerUnpublishVolumeResponse) {}
rpc ValidateVolumeCapabilities (ValidateVolumeCapabilitiesRequest)
returns (ValidateVolumeCapabilitiesResponse) {}
rpc ListVolumes (ListVolumesRequest)
returns (ListVolumesResponse) {}
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) {}
}
- ControllerServiceCapability_RPC_CREATE_DELETE_VOLUME:支援動态 volume 執行 provision delete 操作
- ControllerServiceCapability_RPC_PUBLISH_UNPUBLISH_VOLUME:代表實作了 ControllerPublishVolume 和 ControllerUnpublishVolume 方法,對應 kubernetes 中 attach detach volume 操作
三. Node 節點服務
Node Plugin必須實作這些RPC集。 将volume存儲卷挂載到指定目錄中,/var/lib/kubelet/plugins/${plugin_name}/csi.sock
service Node {
rpc NodeStageVolume (NodeStageVolumeRequest)
returns (NodeStageVolumeResponse) {}
rpc NodeUnstageVolume (NodeUnstageVolumeRequest)
returns (NodeUnstageVolumeResponse) {}
rpc NodePublishVolume (NodePublishVolumeRequest)
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) {}
}
- NodeServiceCapability_RPC_STAGE_UNSTAGE_VOLUME:實作了 NodeStageVolume 和 NodeUnstageVolume 方法,對應了 kubernetes 中的 mount / unmount device 操作
1. DefaultIdentityServer儲存driver對象
實作了三個接口 GetPluginInfo,GetPluginCapabilities,Probe
// DefaultIdentityServer stores driver object
type DefaultIdentityServer struct {
Driver *CSIDriver
}
1.1 GetPluginInfo
獲得plugin 資訊,包括插件名字與版本
// GetPluginInfo returns plugin information
func (ids *DefaultIdentityServer) GetPluginInfo(ctx context.Context, req *csi.GetPluginInfoRequest) (*csi.GetPluginInfoResponse, error) {
klog.V(5).Infof("Using default GetPluginInfo")
if ids.Driver.name == "" {
return nil, status.Error(codes.Unavailable, "Driver name not configured")
}
if ids.Driver.version == "" {
return nil, status.Error(codes.Unavailable, "Driver is missing version")
}
return &csi.GetPluginInfoResponse{
Name: ids.Driver.name,
VendorVersion: ids.Driver.version,
}, nil
}
1.2 Probe 用于探測
// Probe returns empty response
func (ids *DefaultIdentityServer) Probe(ctx context.Context, req *csi.ProbeRequest) (*csi.ProbeResponse, error) {
return &csi.ProbeResponse{}, nil
}
1.3 GetPluginCapabilities用于獲得插件具有那些特權
// GetPluginCapabilities returns plugin capabilities
func (ids *DefaultIdentityServer) GetPluginCapabilities(ctx context.Context, req *csi.GetPluginCapabilitiesRequest) (*csi.GetPluginCapabilitiesResponse, error) {
klog.V(5).Infof("Using default capabilities")
return &csi.GetPluginCapabilitiesResponse{
Capabilities: []*csi.PluginCapability{
{
Type: &csi.PluginCapability_Service_{
Service: &csi.PluginCapability_Service{
Type: csi.PluginCapability_Service_CONTROLLER_SERVICE,
},
},
},
},
}, nil
}
2. DefaultNodeServer實作了NodeServer接口
- NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRequest)
- NodeUnstageVolume(ctx context.Context, req *csi.NodeUnstageVolumeRequest)
- NodeGetInfo(ctx context.Context, req *csi.NodeGetInfoRequest)
- NodeGetCapabilities(ctx context.Context, req *csi.NodeGetCapabilitiesRequest)
- NodeGetVolumeStats(ctx context.Context, in *csi.NodeGetVolumeStatsRequest)
// DefaultNodeServer stores driver object
type DefaultNodeServer struct {
Driver *CSIDriver
}
四. CSIDriver Object
主要有兩個目的:
- 簡化了 driver 服務發現:可以通過 Kubectl get CSIDriver
- 定制 k8s driver 行為功能:比如預設 Attach / Detach 操作
4.1 CSIDriver Object 定義格式
attachRequired::需要 attach 操作,實作了 ControllerPublishVolume 方法
podInfoOnMount:在 mount 操作中需要 pod 的資訊,比如 name UID 等,如果設定為 true,NodePublishVolume 方法中 volume_context 如下所示:
-
"csi.storage.k8s.io/pod.name": pod.Name
-
"csi.storage.k8s.io/pod.namespace": pod.Namespace
-
"csi.storage.k8s.io/pod.uid": string(pod.UID)
volumeLifecycleModes:k8s v1.16 版本新增,
apiVersion: storage.k8s.io/v1beta1
kind: CSIDriver
metadata:
name: hostpath.csi.k8s.io
spec:
attachRequired: true
podInfoOnMount: true
volumeLifecycleModes:
- Persistent
- Ephemeral
五. CSINode Object
主要有以下幾個目的:
- 影射 k8s node 名字到 CSI node 名字:如果新的 CSI driver 注冊,存儲資訊
- driver 可用性
- volume topology
5.1 CSINode Object 定義
-
- list of CSI drivers running on the node and their properties.drivers
-
- the CSI driver that this object refers to.name
-
- the assigned identifier for the node as determined by the driver.nodeID
-
- A list of topology keys assigned to the node as supported by the driver.topologyKeys
apiVersion: storage.k8s.io/v1beta1
kind: CSINode
metadata:
name: master-node
spec:
drivers:
- name: hostpath.csi.k8s.io
nodeID: master-node
topologyKeys:
- topology.hostpath.csi/node
node-driver-registrar sidecar container 建立 CSINode 對象
Kubernetes Changelog
Kubernetes 1.14
Breaking Changes
-
csi.storage.k8s.io/v1alpha1
andCSINodeInfo
CRDs are no longer supported.CSIDriver
Features
- New beta features:
- Topology
- Raw block
- Skip attach
- Pod info on mount
- New alpha features:
- Volume expansion
- New
storage.k8s.io/v1beta1
andCSINode
objects were introduced.CSIDriver
Kubernetes 1.13
Deprecations
- CSI spec 0.2 and 0.3 are deprecated and support will be removed in Kubernetes 1.18.
Features
- GA support added for CSI spec 1.0.
參考:
Kubernetes Container Storage Interface (CSI) Documentation
How to write a Container Storage Interface (CSI) plugin
https://arslan.io/2018/06/21/how-to-write-a-container-storage-interface-csi-plugin/