热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

K8s容器存储接口(CSI)介绍

ContainerStorageInterface是由来自Kubernetes、Mesos、Docker等社区member联合制定的一个行业标准接口规范,旨在将任意存储系统暴露给容
Container Storage Interface是由来自Kubernetes、Mesos、Docker等社区member联合制定的一个行业标准接口规范,旨在将任意存储系统暴露给容器化应用程序。
CSI规范定义了存储提供商实现CSI兼容的Volume Plugin的最小操作集和部署建议。CSI规范的主要焦点是声明Volume Plugin必须实现的接口。
 
CSI Plugin开发者要实现三类gRPC服务接口:
K8s容器存储接口(CSI)介绍
实现了此接口的CSI插件,不但可以在k8s中使用,在所有参与了CSI标准制订的Container Orchestration system中都是通用的。
 

二、CSI sidecar容器

为了协助存储提供商开发CSI兼容插件,Kubernetes官方提供了一些CSI sidecar容器(对应了从Kubernetes项目里面剥离出来的存储管理功能)
  • external-provisioner(csi-provisioner)

在启动时通过--provisioner指定自身provisioner名称,与StorageClass中的provisioner字段对应。
(1)watch PVC对象,判断PVC是否需要动态创建存储卷,标准如下:
①PVC的annotation[volume.beta.kubernetes.io/storage-provisioner](由PV Controller创建)是否与自己的provisioner名称相等。
②PVC对应StorageClass的VolumeBindingMode若为Immediate,则表示需要立即提供动态存储卷。
此时调用CSI Plugin的CreateVolume接口,同时创建名为${Provisioner指定的PV前缀}-${PVC uuid}的PV
(2)watch PV对象,判断其是否需要删除,标准如下:
①判断其.status.phase是否为Release。
②判断其.spec.PersistentVolumeReclaimPolicy是否为Delete。
③判断其annotation[pv.kubernetes.io/provisioned-by]是否与自己的provisioner名称相等。
若需要,则调用CSI Plugin的DeleteVolume接口,同时删除PV对象
  • external-attacher(csi-attacher)

(1)watch VolumeAttachment对象,获得PV的所有信息,如volume ID、node ID等。根据VolumeAttachment的DeletionTimestamp和.status.attached来判断是调用CSI Plugin的ControllerPublish做attach,还是调用CntrollerUnpublish接口做detach
(2)在attacher时为相关PV打上Finalizer;当PV处于删除状态(DeletionTimestamp非空)时,删除Finalizer
  • external-snapshotter

(1)watch VolumeSnapshot对象,根据其状态调用CSI Plugin的CreateSnapshot接口
等存储快照生成后,它会将存储快照生成的相关信息放到VolumeSnapshotContent对象中,并和用户提交的VolumeSnapshot做bound
(2)当VolumeSnapsho处于删除状态(DeletionTimestamp非空)时,调用CSI Plugin的DeleteSnapshot接口
  • external-resizer

watch PVC对象,判断用户在PVC中是否增加了需求的存储空间。如果PVC状态是Bound且.status.Capacity与.spec.Resources.Requests不等,则进行卷扩展:
①更新PVC的.status.Conditions,表明此时处于Resizing状态
②调用CSI Plugin的ControllerExpandVolume接口,若返回值中NodeExpansiOnRequired=true(还需要Kubelet中的Volume Manager继续调用CSI Plugin的NodeExpandVolume接口进行扩容),则更新PVC的status.Conditions 为 FileSystemResizePending;否则,更新 PVC的.Status.Conditions为空,且更新PVC的status.Capacity。
③更新PV的spec.Capacity
  • node-driver-registrar

调用CSI Plugin的接口获取插件信息,通过Kubelet的插件注册机制将CSI Plugin注册到kubelet 
  • livenessprobe

 调用CSI Plugin的Probe接口,同时在/healthz暴露HTTP健康检查探针 

 

三、CSI插件与CSI sidecar容器的组合

一般会在一个CSI Plugin容器中同时实现所有接口,使其同时作为CSI Controller Server和CSI Node Server
它会和Kubernetes官方提供的CSI sidecar容器组成Pod,每种组合都会完成某种功能:
K8s容器存储接口(CSI)介绍
CSI Controller Server和External CSI SideCar、CSI Node Server和Kubelet通过Unix Socket来通信:
K8s容器存储接口(CSI)介绍
 
因此,CSI分为两部分:
  • 由k8s社区驱动实现的通用的部分,如图中的csi-provisioner和csi-attacher
  • 由云存储厂商实现的csi-controller-server和csi-node-server(一般集成到一个一个CSI Plugin容器中),对接云存储厂商的API实现真正的create/delete/mount/unmount存储的相关操作
K8s容器存储接口(CSI)介绍
 

四、通过CRD管理CSI

对CSI的管理是通过CRD的形式实现的,所以引入了自定义对象类型VolumeAttachment、CSINode、CSIDriver 

K8s容器存储接口(CSI)介绍(1)VolumeAttachmen

VolumeAttachment描述一个Volume的attach/detach信息。可以通过VolumeAttachment对一个Volume在某个节点上的attach状态进行跟踪。
 
VolumeAttachmentSpec数据结构:
  • Attacher
根据Driver name指定由哪个CSI Plugin来进行attach/detach
  • NodeName
指定了attach/detach是发生在哪个节点上的
  • Source
指定了对哪一个PV进行attach/detach。
 
VolumeAttachmentStatus数据结构:
  • Attached
指示了是否已经attach
    如果VolumeAttachment的DeletionTimestamp为空且Attached=false,则external-attacher需要调用CSI Plugin的ControllerPublish做attach
    如果VolumeAttachment的DeletionTimestamp不为空且Attached=true,则external-attacher需要调用CSI Plugin的ControllerUnPublish做detach
 

(2)CSIDriver

CSIDriver描述了部署的CSI Plugin、定义了Kubernetes调用CSI Plugin的行为,需要管理员根据插件类型进行创建
CSIDriverSpec数据结构:
  • AttachRequired
定义一个Plugin是否支持Attach功能。
不需要Attach操作时,该标签就是False,说明无需部署external-attacher,也不需要VolumeAttachment对象。
例子:调用CreateVolume接口时,CreateVolumeRequest中VolumeCapability决定了是文件系统直接挂载还是块设备挂载。块存储需要Attach操作,但文件存储不需要Attach操作,例如NFS没有挂载、格式化的概念,只需要mount远端文件系统到本地即可
K8s容器存储接口(CSI)介绍
 K8s容器存储接口(CSI)介绍
 
  • PodInfoOnMount
定义了调用CSI Plugin的NodePublishVolume接口时是否带上Pod信息(PodName、PodUID、PodNamespace)。
默认为false,即CSI Plugin无法获知Pod信息
  • VolumeLifecycleModes
该CSI Plugin支持哪些VolumeLifecycleMode
包括Persistent和Ephemeral两种
  • StorageCapacity
若为true,表示希望调度器调度时考虑节点的存储容量
  • FSGroupPolicy
Volume挂载前是否允许更改属主、权限的定义
  • TokenRequests
CSI Plugin可能需要Pod的Service Account Token
  • RequiresRepublish
若为true,表示CSI Plugin希望不断被调用NodepublishVolume接口,以更新挂载到Pod中的Volume的相关变化。
不过只能更新Volume的contents,running状态Pod的挂载点是不能改变的

(3)CSINode

CSINode是集群中的节点信息,由Node上的node-driver-registrar在启动时创建。
因此,可以只定义集群中一部分节点拥有CSINode。
 
CSINodeSpec由一组CSIDriver信息组成。每一个新的CSI Plugin注册后,都会在其中添加自身信息
每个CSI Plugin可添加的CSIDriver信息包括:
  • Name
  • NodeID
  • Allocatable
节点最多可以attach多少个Volume
  • TopologyKeys
该CSINode支持哪些TopologyKeys。进行支持拓扑感知的provisioning时,将会根据这些TopologyKeys从Node获取values,会传递给CSI Plugin
如果CSI Plugin不支持拓扑,可以置为null。
 

五、总结

插件注册

(1)kubelet在启动的时候有一个约定,例如在/var/lib/kubelet/plugins_registry目录每新加一个文件,就相当于新加了一个Plugin。
(2)node-driver-registrar首先会调用CSI-Plugin的GetPluginInfo接口,获取CSI Plugin监听的地址以及其Driver name。
(3)node-driver-registrar会监听自身的GetInfo和NotifyRegistrationStatus接口。
(4)在/var/lib/kuberlet/plugins_registry这个目录下启动一个Socket,生成一个Socket文件 ,例如:"com.nfs.csi.tds-reg.sock”
(5)kubelet Watche到Socket后,通过该Socket调用node-driver-registrar的GetInfo接口,获取其刚刚获得的CSI-Plugin的信息
(6)获取成功之后,Kubelet会:
①根据CSI Plugin监听地址调用其NodeGetInfo接口,获取[nodeID]、[Drive name]、[AccessibleTopology]、maxAttachLimit(节点最大可挂载卷数量)
    为Node新建(或更新已有)annotation[csi.volume.kubernetes.io/nodeid]=xxx
    基于[AccessibleTopology]给Node添加label
    根据maxAttachLimit更改Node的.status.Allocatable:attachable-volumes-csi-[Drive name]=[maxAttachLimit]。
②根据CSI Plugin监听地址调用其NodeGetVolumeStats接口,并反映在其metrics:
    kubelet_volume_stats_capacity_bytes:存储卷容量
    kubelet_volume_stats_used_bytes:存储卷已使用容量
    kubelet_volume_stats_available_bytes:存储卷可使用容量
    kubelet_volume_stats_inodes:存储卷inode总量
    kubelet_volume_stats_inodes_used:存储卷inode使用量
    kubelet_volume_stats_inodes_free:存储卷inode剩余量
③创建一个CSINode对象(或更新已有CSINode对象)
④调用node-driver-registrar的NotifyRegistrationStatus接口,告诉它CSI-Plugin已经注册成功了。

Provisioning Volumes

(1)PV Controller观察到集群中新创建的PVC没有与之匹配的PV,且其对应SC指定的Provisioner不是Internal Provisioner,于是为PVC打annotation[volume.beta.kubernetes.io/storage-provisioner]=xxx
(2)对应external-provisioner判断需要创建存储卷,于是调用CSI Plugin的CreateVolume接口
(3)external-provisioner在请求参数设置AccessibilityRequirements
    如果SC的VolumeBindingMode为Immediate模式:如果SC指定了AllowedTopologies则,只考虑AllowedTopologies,否则需要将所有包含TopologyKeys键的节点Value添进来。
    如果SC的VolumeBindingMode为WaitForFirstConsumer模式:获取Pod调度到的节点的CSINode对象的TopologyKeys,根据这些TopologyKeys从Node的Label获取values值,与SC的AllowedTopologies比对,不符合则报错
(4)CSI Plugin返回成功后,表示存储卷已经在Cloud Storage Vendor真正创建完成
存储卷既有可能是新的,也有可能是根据VolumeSnapshotContent中的Snapshot的ID创建的:
K8s容器存储接口(CSI)介绍
(5)external-provisioner会创建一个PV,PV Controller会将PV与PVC进行绑定。
 

Attaching Volumes

(1)AD  Controller观察到使用VolumeSource为CSI的PV的Pod被调度到某一节点,会调用AD  Controller内部in-tree CSI插件(csiAttacher)的Attach函数,由其创建一个VolumeAttachment
(2)同时,external-attacher也会同步一些PV的信息在VolumeAttachment里。
(3)external-attacher观察到该VolumeAttachment对象,如果其.spec.Attacher中的Driver name指定的是自己同一Pod内的CSI Plugin,则调用CSI Plugin的ControllerPublish接口
(4)CSI Plugin会调用云存储厂商的API,把远端的Volume attach到目标节点中上(如/dev/vdb)
(5)external-attacher更新该VolumeAttachment的.status.Attached为true。
(4)AD  Controller内部in-tree CSI插件(csiAttacher)观察到该VolumeAttachment的.status.Attached为 true,于是更新AD  Controller内部状态(ActualStateOfWorld),该状态会显示在Node资源的.status.VolumesAttached上。
K8s容器存储接口(CSI)介绍

Mounting Volumes

(1)kubelet组件Volume Manager观察到有新的使用PersistentVolumeSource为CSI的PV的Pod调度到本节点上,于是调用内部in-tree CSI插件(csiAttacher)的WaitForAttach函数。
(2)内部in-tree CSI插件(csiAttacher)等待attach完成后,调用MountDevice函数,由其调用CSI plugin的NodeStageVolume接口;
(3)插件csiAttacher调用内部 in-tree CSI 插件(csiMountMgr)的SetUp函数,由其调用CSI plugin的NodePublishVolume接口。

Unmounting Volumes

用户删除相关Pod后
(1)kubelet组件Volume Manager观察到有新的使用PersistentVolumeSource为CSI的PV的Pod被删除,于是调用内部 in-tree CSI 插件(csiMountMgr)的TearDown函数,由其调用CSI plugin的NodeUnpublishVolume接口。
(2)kubelet组件Volume Manager调用内部in-tree CSI 插件(csiAttacher)的 UnmountDevice函数,由其调用CSI plugin的NodeUnpublishVolume接口。

Detaching Volumes

(1)AD Controller观察到有PersistentVolumeSource为CSI的PV被删除,就会调用内部 in-tree CSI 插件(csiAttacher)的Detach函数。
(2)csiAttacher会删除相关VolumeAttachment对象(但由于存在finalizer,不会立即删除成功)。
(3)external-attacher观察到该VolumeAttachment对象的DeletionTimestamp非空,于是调用CSI Plugin的 ControllerUnpublish接口以从对应节点上detach Volume。
(4)detach成功后,external-attacher会移除该VolumeAttachment对象的finalizer字段,使其被彻底删除。
(4)AD Controller内部in-tree CSI插件(csiAttacher)观察到该VolumeAttachment对象已删除,于是更新AD Controller中的内部状态;同时从Node的.status.VolumesAttached中清除此attach信息。

Deleting Volumes

external-provisioner watch到用户删除了PVC,根据 PVC的回收策略(Reclaim)执行不同操作:
    Delete:调用CSI Plugin的DeleteVolume接口,由其去远端存储删除存储卷;一旦成功删除,external-provisioner会删除对应PV对象。
    Retain:external-provisioner不执行存储卷删除操作。
 
K8s容器存储接口(CSI)介绍

参考资料:

[1] https://kubernetes.io/docs/home/

[2] https://edu.aliyun.com/roadmap/cloudnative

[3] 郑东旭《Kubernetes源码剖析》


推荐阅读
  • SpringBoot简单日志配置
     在生产环境中,只打印error级别的错误,在测试环境中,可以调成debugapplication.properties文件##默认使用logbacklogging.level.r ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 在springmvc框架中,前台ajax调用方法,对图片批量下载,如何弹出提示保存位置选框?Controller方法 ... [详细]
  • Spring常用注解(绝对经典),全靠这份Java知识点PDF大全
    本文介绍了Spring常用注解和注入bean的注解,包括@Bean、@Autowired、@Inject等,同时提供了一个Java知识点PDF大全的资源链接。其中详细介绍了ColorFactoryBean的使用,以及@Autowired和@Inject的区别和用法。此外,还提到了@Required属性的配置和使用。 ... [详细]
  • 在一个包含四个活动的活动组中,作者遇到了一个屏幕方向的问题。在其中三个活动中,作者将屏幕方向设置为纵向,但需要一个活动在设备旋转时改变方向。通过删除ActivityGroup在AndroidManifest文件中的Portrait设置,作者解决了这个问题。 ... [详细]
  • golang反射,golang反射性能
    本文目录一览:1、关于反射2、尝试用golan ... [详细]
  • 闭包一直是Java社区中争论不断的话题,很多语言都支持闭包这个语言特性,闭包定义了一个依赖于外部环境的自由变量的函数,这个函数能够访问外部环境的变量。本文以JavaScript的一个闭包为例,介绍了闭包的定义和特性。 ... [详细]
  • Java学习笔记之面向对象编程(OOP)
    本文介绍了Java学习笔记中的面向对象编程(OOP)内容,包括OOP的三大特性(封装、继承、多态)和五大原则(单一职责原则、开放封闭原则、里式替换原则、依赖倒置原则)。通过学习OOP,可以提高代码复用性、拓展性和安全性。 ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
  • ASP.NET CORE 简介
    ASP.NETCore是一个跨平台的高性能开源框架,用于生成启用云且连接Internet的新式应用。使用ASP.NETCore,您可以:生成Web ... [详细]
  • 0.编写.proto文件:syntaxproto3;optionjava_multiple_filestrue;optionjava_packageio.grp ... [详细]
  • maven编译protobufpom添加如下依赖1.6.12.6 ... [详细]
  • 本文介绍了在Python中使用gRPC的方法示例,分享给大家,具体如下:使用ProtocolBuffers的跨平台RPC系统。安装使用pi ... [详细]
  • linux中znyw用户名,关于Linux,用户,组,权限,文本处理工具,正则表达式,vim文本编辑器(示例代码)...
    一、用户??在Linux系统中,可以创建多个用户,每一个用户都有一个与其对应的ID号,就像每一个人都有一个号一样,这就是用户 ... [详细]
author-avatar
淡定神仙2502891317
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有