写点什么

智汇华云 | 通过 iscsi 为容器提供存储

作者:华云数据
  • 2022 年 2 月 15 日
  • 本文字数:3639 字

    阅读完需:约 12 分钟

介绍


将远端的存储通过 iscsi 协议为容器提供块存储,是一种通用的容器存储解决方案,下面将通过 kubernetes 中的 in-tree 方式来演示该例子,并分析其中的细节。


iSCSI 协议是 C/S 架构,client 是 iSCSI initiator,server 端为 iSCSI target。iSCSI 协议的主要功能是利用 TCP/IP 网络,在主机系统(可称为 initiator)和目标存储设备(称为 target)之间进行大量的数据封装和可靠传输过程。主要分成两个组成部分,分别为 iSCSI 服务器端和 iSCSI 客户端


iSCSI 服务器端 (iSCSI Target)


iSCSI 服务器端为 iSCSI target,这是 I/O 操作的执行者。主要是为了导出一个或多个块设备供启动者(initiator)使用,可以通过硬件和软件的方式来实现。在 Linux 中可以使用 scsi-target-utils 软件包来模拟实现。在使用 iSCSI 时,会在 iSCSI 储存设备上去建立 LUN(Logical Unit Number)来提供给具备 iSCSI Initiator 功能的主机来存取 数据的。LUN 好比是个“逻辑单位磁碟”,物理上通常是由数个实体磁碟( RAID 或 LVM 技术的技术实现)所组成。LUN ID 由 iSCSI 目标设备(Target)分配。iSCSI 启动端(Initiator)设备当前支持在每个目标设备(Target)中导出最多 256 个 LUN。即最大支持 16 个 target。


iSCSI target 设备名称采用如下格式来命名:iqn..[:],需要事先进行配置,保证唯一性。


iSCSI 客户端 (iSCSI Initiator)


iSCSI 客户端为 iSCSI initiator,这是 I/O 操作的发起者。是 I/O 操作的发起者,需要通过发现过程请求远端快设备。在 Linux 系统中可以通过软件来模拟,需要安装 iSCSI 设备驱动。如 iscsi-initiator-utils。


实验


可以通过 iSCSI 将远程的磁盘分区映射到本地之后就可以像使用本地磁盘一样,将该远程盘进行格式化以及挂载操作,给容器使用。


我们通过 scsi-target-utils 来实现 iSCSI target,将主机上的/dev/sdb 磁盘分区作为 Lun,如下图所示


[root@iscsi-server yum.repos.d]# tgtadm -L iscsi -o show -m target


Target 1: iqn.2021-11.com.huayun.san:123456


System information:
Driver: iscsi
State: ready
I_T nexus information:
LUN information:
LUN: 0
Type: controller
SCSI ID: IET 00010000
SCSI SN: beaf10
Size: 0 MB, Block size: 1
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
SWP: No
Thin-provisioning: No
Backing store type: null
Backing store path: None
Backing store flags:
LUN: 1
Type: disk
SCSI ID: IET 00010001
SCSI SN: beaf11
Size: 10737 MB, Block size: 512
Online: Yes
Removable media: No
Prevent removal: No
Readonly: No
SWP: No
Thin-provisioning: No
Backing store type: rdwr
Backing store path: /dev/vdb
Backing store flags:
Account information:
ACL information:
复制代码


之后在 kubernetes 的 node 节点上需要事先安装 iscsi-initiator-utils,并且设置对应的 initiatorname,如果开启了 acl 认证,需要将 node 节点的 initiatorname 添加到 acl 里面。


之后创建一个 pod,其中指定一个存在的 iscsi lun 对接信息如下


apiVersion: v1


kind: Pod


metadata:


name: iscsipd


spec:


containers:


  • name: iscsipd-rw

  • image: kubernetes/pause

  • volumeMounts:

  • mountPath: "/mnt/iscsipd"

  • name: iscsipd-rw


volumes:


  • name: iscsipd-rw

  • iscsi:

  • targetPortal: 10.0.2.15:3260

  • portals: ['10.0.2.16:3260', '10.0.2.17:3260']

  • iqn: iqn.2001-04.com.example:storage.kube.sys1.xyz

  • lun: 0

  • fsType: ext4

  • readOnly: true


之后可以看到远程的卷被成功的挂载到 node 上,被容器所使用


Volume.iscsi 说明


pod 的 spec 中可以在 volumes.iscsi 中指定对接信息包括如下


iscsi.iqn


required,string


Target iSCSI Qualified Name.


iscsi.lun


required,int32


iSCSI Target Lun number.


iscsi.targetPortal


required,string


iSCSI Target Portal. The Portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).


iscsi.chapAuthDiscovery


bolean


whether support iSCSI Discovery CHAP authentication


iscsi.chapAuthSession


boolean


whether support iSCSI Session CHAP authentication


iscsi.fsType


string


Filesystem type of the volume that you want to mount. Tip: Ensure that the filesystem type is supported by the host operating system. Examples: "ext4", "xfs", "ntfs". Implicitly inferred to be "ext4" if unspecified.


iscsi.initiatorName


string


Custom iSCSI Initiator Name. If initiatorName is specified with iscsiInterface simultaneously, new iSCSI interface:will be created for the connection.


iscsi.iscsiInterface


string


iSCSI Interface Name that uses an iSCSI transport. Defaults to 'default' (tcp).


iscsi.portals


[]string


iSCSI Target Portal List. The portal is either an IP or ip_addr:port if the port is other than default (typically TCP ports 860 and 3260).


iscsi.readOnly


boolean


ReadOnly here will force the ReadOnly setting in VolumeMounts. Defaults to false.


iscsi.secretRef


LocalObjectReference


CHAP Secret for iSCSI target and initiator authentication


源码分析


挂载阶段


pod 调度到某个 node 上,之后由 kubelet 中的 volumemanager 完成对于 volume attach&mount 操作,核心代码位于 kubernetes/pkg/volume/iscsi 目录下,在 volume 挂载的过程中,会首先调用 WaitForAttach()完成挂载流程,SetUpDevice()挂载到某个容器所对应的目录。iscsiAttacher.WaitForAttach()流程如图所示:


Step1: 通过 iscsiadm -m iface -l b. InitIface -o show 获取对应的 iscsiTransport,如果不额外指定的话 b. InitIface 为 default,iscsiTransport 为 tcp.


Step2: 如果 pod 的定义中指定 iscsi.initiatorName ,则需要 cloneIface(), 指定 iscsi.initiatorName 需要与 node 的不一致,这样当开启 ACL initiatorName 控制的时候,pod 可以运行在不同的节点上。


Step3: 基于 iqn 号获取 lock,主要解决的场景为相同 target 下不同 volume 同时挂载或者 login 与 logout 操作并发进行,这个锁引入的目的主要是为了后面 volume 在 Detach 的时候,需要根据 isSessionBusy 来判断是否需要 logout,断开 node 与 target 的所有链接。


Step4: GetISCSIPortalHostMapForTarget 主要根据 target iqn 获取到 login 到该 target 上的 scsi hosts number, 返回的结构为


{


"192.168.30.7:3260": 2,
"192.168.30.8:3260": 3,
复制代码


}


通过这个 map 的引入后面用于判断是否需要 login,还是直接通过 scanOneLun()来发现接入的 Lun,避免没有必要的 login 操作。scanOneLun 之后会发现挂载到 node 上的 device。


Step5: 根据 volomeMode 的类型是直接的 PersistentVolumeBlock 还是 PersistentVolumeFileSystem 模式,二者的区别在于是否需要对 device 进行格式化,创建文件系统,之后创建 globalPDPath 目录,目录位置采用如下格式


/var/lib/kubelet/plugins/kubernetes.io/iscsi/ /{ifaceName}/{portal-some_iqn-lun-lun_id},之后持久化的 iscsi disk 元数据到 globalPDPath 目录下 iscsi.json,元数据主要用于 DetachVolume 的时候会涉及到,内容如下所示:


{


"VolName":"iscsipd-rw",
"Portals":[
"178.104.162.58:3260",
],
"Iqn":"iqn.2021-11.com.huayun.san:123456",
"Lun":"1",
"InitIface":"default",
"Iface":"default",
"InitiatorName":"",
"MetricsProvider":null
复制代码


}


在 WaitForAttach 阶段完成了 device 远端挂载、格式化以及挂载到 globalPDPath 目录下,SetUpDevice 流程较为简单主要是将 globalPDPath mount –bind 到容器对应的目录,之后对目录进行 SetVolumeOwnership()操作。


卸载阶段


pod 销毁的时候,会由 kubelet 完成 volume 的 umount&detach 操作,核心代码位于 kubernetes/pkg/volume/iscsi 目录下,主要完成 umount node 上的挂载信息,之后根据 globalPDPath 目录下 iscsi.json 元数据信息来完成 TearDownDevice 断开 device,之后清理掉 globalPDPath。


Step1: 根据 mntPath 挂载点信息获得 device 盘符,之后 Unmount()掉挂载点信息


Step2:loadISCSI 中根据 mntPath 获得该 iscsi 挂载信息的元数据信息,其中包括 iqn iface volName initiatorName 等信息


Step3: deleteDevices()中通过对 device 进行 echo 1> delete 操作,删除掉盘符


Step4: 基于 iqn 获取 targetLocks.LockKey,之后判断该 target 在 node 上是否存在其他的盘挂载,如果没有存在,则进行 iscsi logout 操作,断开 node 与 target 之后的连接


总结


In-tree 下的 iscsi 方式为容器提供 iscsi 的存储类似于静态供应,需要事先系统管理员创建好后端的 iscsi 存储,之后容器提供指定对应的配置来使用。对于已经存在支持 iscsi 协议挂载的后端存储,并且不具备动态功能 csi 插件的场景下具有一定的使用场景。

用户头像

华云数据

关注

还未添加个人签名 2020.11.02 加入

还未添加个人简介

评论

发布
暂无评论
智汇华云 | 通过iscsi为容器提供存储