CSI 規範
官方文檔:https://github.com/container-storage-interface/spec/blob/master/spec.md
CSI目標
定義API:
自動化創建/刪除數據卷;
從一個節點掛載/卸載數據卷;
在一個節點上Mount/Umount一個卷設備;
使用可掛載/塊 數據卷;
本地存儲供應者 - LVM
創建、刪除快照;
從一個快照恢復數據卷;
推薦細節:
容器部署意見:CAP_SYS_ADMIN,mnt命名空間;
CSI介紹
CSI聚焦的中心是容器編排系統(CO)和Plugin之間的協議;插件應該是可以跨CO運行的。
部署模式
模式1:中心化控制器(Master節點) + 分佈式插件(所有節點)
CO "Master" Host
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | CO | gRPC | Controller | |
| | +-----------> Plugin | |
| +------------+ +------------+ |
| |
+-------------------------------------------+
CO "Node" Host(s)
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | CO | gRPC | Node | |
| | +-----------> Plugin | |
| +------------+ +------------+ |
| |
+-------------------------------------------+
模式2:每個Worker節點部署 2個組件,分別是控制器、插件;
CO "Node" Host(s)
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | CO | gRPC | Controller | |
| | +--+--------> Plugin | |
| +------------+ | +------------+ |
| | |
| | |
| | +------------+ |
| | | Node | |
| +--------> Plugin | |
| +------------+ |
| |
+-------------------------------------------+
模式3:每個Worker節點部署 一個組件(包含控制器 + 插件)
CO "Node" Host(s)
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | CO | gRPC | Controller | |
| | +-----------> Node | |
| +------------+ | Plugin | |
| +------------+ |
| |
+-------------------------------------------+
模式4:只有worker節點部署 一個組件,只包含插件
GetPluginCapabilities接口不能返回CONTROLLER_SERVICE;
CO "Node" Host(s)
+-------------------------------------------+
| |
| +------------+ +------------+ |
| | CO | gRPC | Node | |
| | +-----------> Plugin | |
| +------------+ +------------+ |
| |
+-------------------------------------------+
數據卷生命週期:
略
控制器插件應該實現所有 控制器 服務接口,不支持的接口要返回CALL_NOT_IMPLEMENTED;
插件提供的能力會列在ControllerGetCapabilities、NodeGetCapabilities接口中;
接口定義
容器編排系統通過RPC調用Plugin。
兩種插件:
節點插件:每個節點上都會運行;
控制器插件:不確定那個節點運行,執行provider功能;
三種類型RPC:
身份服務:兩種插件都要實現這個接口;
GetPluginInfo:
GetPluginCapabilities:
Probe:
控制服務:
CreateVolume:
DeleteVolume:
ControllerPublishVolume:
ControllerUnpublishVolume:
ValidateVolumeCapabilities:
ListVolumes:
GetCapacity:
ControllerGetCapabilities:
CreateSnapshot:
DeleteSnapshot:
ListSnapshots:
節點服務:
NodeStageVolume:
NodeUnstageVolume:
NodePublishVolume:
NodeUnpublishVolume:
NodeGetId:
NodeGetCapabilities:
NodeGetInfo:
併發支持:
一般CO不會併發發送請求,在異常情況下收到一個volume的多個請求的時候要等冪處理;
返回:OPERATION_PENDING_FOR_VOLUME
校驗 RPC
GetPluginInfo
# CO --(GetPluginInfo)--> Plugin
request:
response:
name: org.foo.whizbang.super-plugin
vendor_version: blue-green
manifest:
baz: qaz
message GetPluginInfoResponse {
string name = 1;
string vendor_version = 2;
// This field is OPTIONAL.
map<string, string> manifest = 3;
}
GetPluginCapabilities
# CO --(GetPluginCapabilities)--> Plugin
request:
response:
capabilities:
- service:
type: CONTROLLER_SERVICE
message PluginCapability {
message Service {
enum Type {
UNKNOWN = 0;
CONTROLLER_SERVICE = 1;
ACCESSIBILITY_CONSTRAINTS = 2;
}
Type type = 1;
}
oneof type {
Service service = 1;
}
}
readiness:
# CO --(Probe)--> Plugin
request:
response: {}
控制服務 RPC
如果GetPluginCapabilities 包含CREATE_DELETE_VOLUME標籤,則必須實現CreateVolume;
CreateVolume接口
message CreateVolumeRequest {
// 必須項
// 1) 冪等性 - 多次相同請求不會產生多個volume;
// 2) 可以使用這個名字,來命名PV Name;
string name = 1;
// 可選項,定義volume的大小範圍,最小值和最大值;
CapacityRange capacity_range = 2;
// 必須項
// 定義AccessType:
// VolumeCapability_Block:塊存儲設備;
// VolumeCapability_Mount:可掛載文件系統;
// 定義AccessMode:
// VolumeCapability_AccessMode_UNKNOWN
// VolumeCapability_AccessMode_SINGLE_NODE_WRITER:只能掛載單節點、讀寫模式
// VolumeCapability_AccessMode_SINGLE_NODE_READER_ONLY:只能掛載單節點、只讀模式
// VolumeCapability_AccessMode_MULTI_NODE_READER_ONLY:多個節點、只讀模式
// VolumeCapability_AccessMode_MULTI_NODE_SINGLE_WRITER:多個節點、一個節點是讀寫,其他節點只讀;
// VolumeCapability_AccessMode_MULTI_NODE_MULTI_WRITER:多個節點,都是讀寫;
repeated VolumeCapability volume_capabilities = 3;
// 可選
// 鍵值對參數,plugin需要解析這個map;
map<string, string> parameters = 4;
// 加密信息,可以在plugin引用;
map<string, string> controller_create_secrets = 5;
// OPTIONAL.
VolumeContentSource volume_content_source = 6;
// 可選:
TopologyRequirement accessibility_requirements = 7;
}
錯誤碼:
ALREADY_EXISTS:名字存在,但是參數不同;
RESOURCE_EXHAUSTED:資源可用,但是權限不足,例如:quota問題;
ABORTED:Operation pending for volume;
OUT_OF_RANGE:Unsupported capacity_range
UNIMPLEMENTED:Call not implemented
DeleteVolume
支持冪等性;
如果刪除的volume id不存在,則返回OK;
ControllerPublishVolume
如果聲明瞭PUBLISH_UNPUBLISH_VOLUME Capability,則必須實現;
當工作負載調度到某個節點時,CO通過此接口實現volume掛載到相應的節點;
不能假設RPC接口與調度的節點相同;
必須是冪等的;
如果volume已經掛載到了相應節點,則返回OK;
如果CO沒有收到掛載是否成功,CO可能重複發送ControllerPublishVolume或者發送ControllerUnpublishVolume;
message ControllerPublishVolumeRequest {
// 必須項
string volume_id = 1;
// 必選項:NodeGetInfo裏面可以查到的節點ID;
string node_id = 2;
// 必須項:
VolumeCapability volume_capability = 3;
// 必須項:
bool readonly = 4;
// 可選
map<string, string> controller_publish_secrets = 5;
// 可選
map<string, string> volume_attributes = 6;
}
ControllerUnpublishVolume
必須在NodeUnstageVolume、NodeUnpublishVolume調用成功後執行;
同樣,執行RPC不一樣在volume所掛載的節點上;
這個接口是冪等的,如果CO不確定返回值,則再次調用ControllerUnpublishVolume;
ValidateVolumeCapabilities
必須實現的接口;
用於CO檢查volume的功能;
message ValidateVolumeCapabilitiesRequest {
// 必須
string volume_id = 1;
// 必須
repeated VolumeCapability volume_capabilities = 2;
// 可選
map<string, string> volume_attributes = 3;
repeated Topology accessible_topology = 4;
}
ListVolumes
如果Plugin有LIST_VOLUMES 能力,則必須實現這個接口;
返回volume列表;
GetCapacity
如果Plugin有GET_CAPACITY 能力,則必須實現這個接口;
返回存儲池的能力;
ControllerGetCapabilities
必須實現;
CO檢查plugin所支持的能力;
CreateSnapshot
如果Plugin有CREATE_DELETE_SNAPSHOT 能力,則必須實現這個接口;
必須是冪等的;
[](#p7y7sk)DeleteSnapshot
如果Plugin有CREATE_DELETE_SNAPSHOT 能力,則必須實現這個接口;
ListSnapshots
如果Plugin有LIST_SNAPSHOTS 能力,則必須實現這個接口;
SnapShot狀態
有些provider會上傳到雲存儲;
節點服務 RPC
NodeStageVolume
如果Plugin有STAGE_UNSTAGE_VOLUME 能力,則必須實現這個接口;
CO會保證在ControllerPublishVolume 調用後再調用NodeStageVolume;並保證在NodePublishVolume調用前調用;
會在期望掛載節點上調用這個接口;
NodeUnstageVolume
如果Plugin有STAGE_UNSTAGE_VOLUME 能力,則必須實現這個接口;
保證在NodeUnpublishVolume之後調用;
NodePublishVolume
必須有的接口;
與RPC調用節點相同;
NodeUnpublishVolume
必須有的接口;
NodeGetCapabilities
必須實現的接口;
返回Node支持的能力;
NodeGetInfo
plugin必須實現這個接口,如果:PUBLISH_UNPUBLISH_VOLUME被配置;
協議
Identity:必須的接口類型;
Controller:可選的;
Node:必須的;
配置&操作
Plugin服務儘可能多的使用環境變量做配置;
CSI_ENDPOINT:Plugin的監聽地址;
啓動實例:
Supervisor -> Plugin: CSI_ENDPOINT=unix:///path/to/unix/domain/socket.sock.
Operator -> CO: use plugin at endpoint unix:///path/to/unix/domain/socket.sock.
CO: monitor /path/to/unix/domain/socket.sock.
Plugin: read CSI_ENDPOINT, create UNIX socket at specified path, bind and listen.
CO: observe that socket now exists, establish connection.
CO: invoke GetPluginCapabilities.