热门标签 | 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源码剖析》


推荐阅读
  • 开发心得:利用 Redis 构建分布式系统的轻量级协调机制
    开发心得:利用 Redis 构建分布式系统的轻量级协调机制 ... [详细]
  • 在开发过程中,我最初也依赖于功能全面但操作繁琐的集成开发环境(IDE),如Borland Delphi 和 Microsoft Visual Studio。然而,随着对高效开发的追求,我逐渐转向了更加轻量级和灵活的工具组合。通过 CLIfe,我构建了一个高度定制化的开发环境,不仅提高了代码编写效率,还简化了项目管理流程。这一配置结合了多种强大的命令行工具和插件,使我在日常开发中能够更加得心应手。 ... [详细]
  • Docker网络基础探讨了如何通过高效的技术手段实现跨主机容器间的顺畅通信与访问。本文深入分析了Docker网络架构,特别是其在多主机环境下的应用,为Go语言开发者提供了宝贵的实践指导和理论支持。 ... [详细]
  • 秒建一个后台管理系统?用这5个开源免费的Java项目就够了
    秒建一个后台管理系统?用这5个开源免费的Java项目就够了 ... [详细]
  • 在《Cocos2d-x学习笔记:基础概念解析与内存管理机制深入探讨》中,详细介绍了Cocos2d-x的基础概念,并深入分析了其内存管理机制。特别是针对Boost库引入的智能指针管理方法进行了详细的讲解,例如在处理鱼的运动过程中,可以通过编写自定义函数来动态计算角度变化,利用CallFunc回调机制实现高效的游戏逻辑控制。此外,文章还探讨了如何通过智能指针优化资源管理和避免内存泄漏,为开发者提供了实用的编程技巧和最佳实践。 ... [详细]
  • 在本文中,我们将探讨如何在Docker环境中高效地管理和利用数据库。首先,需要安装Docker Desktop以确保本地环境准备就绪。接下来,可以从Docker Hub中选择合适的数据库镜像,并通过简单的命令将其拉取到本地。此外,我们还将介绍如何配置和优化这些数据库容器,以实现最佳性能和安全性。 ... [详细]
  • CentOS 7环境下Jenkins的安装与前后端应用部署详解
    CentOS 7环境下Jenkins的安装与前后端应用部署详解 ... [详细]
  • ZeroMQ在云计算环境下的高效消息传递库第四章学习心得
    本章节深入探讨了ZeroMQ在云计算环境中的高效消息传递机制,涵盖客户端请求-响应模式、最近最少使用(LRU)队列、心跳检测、面向服务的队列、基于磁盘的离线队列以及主从备份服务等关键技术。此外,还介绍了无中间件的请求-响应架构,强调了这些技术在提升系统性能和可靠性方面的应用价值。个人理解方面,ZeroMQ通过这些机制有效解决了分布式系统中常见的通信延迟和数据一致性问题。 ... [详细]
  • [转]doc,ppt,xls文件格式转PDF格式http:blog.csdn.netlee353086articledetails7920355确实好用。需要注意的是#import ... [详细]
  • MySQL 5.7 学习指南:SQLyog 中的主键、列属性和数据类型
    本文介绍了 MySQL 5.7 中主键(Primary Key)和自增(Auto-Increment)的概念,以及如何在 SQLyog 中设置这些属性。同时,还探讨了数据类型的分类和选择,以及列属性的设置方法。 ... [详细]
  • C# 实现可浮动工具栏功能
    本文介绍如何在 C# 中实现一个可浮动的工具栏,即工具栏可以从其初始位置拖出,并且可以重新拖回原位。通过创建一个新的窗口作为工具栏的容器,并利用 .NET Framework 提供的 ToolStrip 控件,可以轻松实现这一功能。 ... [详细]
  • 本文介绍了UUID(通用唯一标识符)的概念及其在JavaScript中生成Java兼容UUID的代码实现与优化技巧。UUID是一个128位的唯一标识符,广泛应用于分布式系统中以确保唯一性。文章详细探讨了如何利用JavaScript生成符合Java标准的UUID,并提供了多种优化方法,以提高生成效率和兼容性。 ... [详细]
  • 2019年后蚂蚁集团与拼多多面试经验详述与深度剖析
    2019年后蚂蚁集团与拼多多面试经验详述与深度剖析 ... [详细]
  • MySQL 5.6 引入了全局事务标识符(GTID)和多线程复制机制,显著提升了数据库的可靠性和性能。GTID 作为一种新的事务标识方式,确保了事务在主从节点间的一致性,避免了传统基于日志位置的复制可能出现的问题。多线程复制则通过并行处理多个复制任务,大幅提高了复制效率,特别是在大型数据库环境中表现更为突出。这些新特性不仅增强了 MySQL 的高可用性和扩展性,还为数据库管理带来了更多灵活性和便利性。 ... [详细]
  • 探讨.NET技术与Silverlight中控件拖放及复制功能的实现方法
    Silverlight拖动复制控件,就是将控件从一个容器中向另一个容器中拖动时,不是移动控件而把该控件到另一个容器中。这种情形在程序中经常遇到ÿ ... [详细]
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社区 版权所有