智汇华云—通过iscsi为容器提供存储
作者:唐昧 栏目:新闻 来源:中国经济观察网 发布时间:2022-02-09 16:34 阅读量:11941 会员投稿
内容摘要:介绍将远端的存储通过iscsi协议为容器提供块存储,是一种通用的容器存储解决方案,下面将通过kubernetes中的in-tree方式来演示该例子,并分析其中的细节。iSCSI协议是C/S架构,client是iSCSIinitiator,s...介绍
将远端的存储通过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 |
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插件的场景下具有一定的使用场景。
郑重声明:此文内容为本网站转载企业宣传资讯,目的在于传播更多信息,与本站立场无关。仅供读者参考,并请自行核实相关内容。