CSI 协议规范

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.
上一篇:CSI 系统介绍


下一篇:CSI介绍