iSCSI 配置
前言:iSCSI 作为最通用的块存储协议,在数据中心、计算集群里获得了广泛应用。
iSCSI 协议的配置比 NFS、SMB/Samba 等常见的文件共享协议要复杂很多,其中涉及到 target、initiator、session 等多个概念,本文尝试从服务端和客户端两个角度进行配置。
- 服务端
- TrueNAS SCALE
- Debian 12
- 客户端
- Windows 10/Server
- Debian 12
1. iSCSI 服务端配置·
iSCSI 的配置非常复杂,介绍复杂系统一般有两种写作方法。第一种是先介绍前置知识,然后介绍技术流程,第二种是在技术流程中随机插入需要的前置知识。前者体系性较好,但是容易让读者在阅读前期理解困难。后者从流程出发,故事线漂亮,但是缺乏对知识的梳理。本文采取第一种介绍流程。因此为了保证准确理解 iSCSI 服务端配置过程中的一些术语,我要对下面几个词组进行解释。
- Portals
- 指的是存储区域网络(SAN)中的一个网络位置,由 IP 地址和 TCP 端口(一般是 3260)构成,可以把它想象成一扇门,后面是 initiator 可以连接到的存储对象。该目标用来进行 SAN 网络中的寻址。
- Initiators 和 Target
- iSCSI 发起者,即 iSCSI 协议中的客户端。在原版的 SCSI 协议中,initiator 发起 SCSI 命令的设备,通常是一台电脑或者一个主机控制器;Target 通常指的是接受或执行 SCSI 指令的设备,通常是硬盘驱动器或者磁带库。iSCSI 继承了 SCSI 的相关术语。Target 的概念在后面会详细介绍。
- Initiator Name 与 iqn
- 这个选项非常重要,它决定了在存储网络中这台设备的名字。因为服务一般需要有 DNS 支持,现代资本主义社会中,每个公司的内部数字资产都有一套严格的、规范的命名方式。比如我这台机器被命名为
epyc-truenas
,所属的一级域名是littlenewton.cn
,我于2019 年 8 月
获得该域名。根据这些信息,按照 RFC3721 的要求,倒序打点连接起来便得到 initiator-name:iqn.2019-08.cn.littlenewton:epyc-truenas
,其中iqn
指的是iSCSI Qualified Name
. 这个名字会用来进行身份验证。
- 这个选项非常重要,它决定了在存储网络中这台设备的名字。因为服务一般需要有 DNS 支持,现代资本主义社会中,每个公司的内部数字资产都有一套严格的、规范的命名方式。比如我这台机器被命名为
- Initiator Groups (重点)
- 又称 ACL,即一般意义上的访问控制列表。以 Initiator Group ID 为唯一标识(主键),服务器可以把某些 iSCSI 客户端的 iqn 添加到这个组里,实现访问控制。通过 Initiator Groups,服务器可以控制哪些 Initiator 有资格访问哪些 Targets.
- Targets
- 指的是在 Portal 后面真正提供存储的 iSCSI 对象,Initiator 通过 SAN 网络连接到 Target 即可获得存储服务。Target 本身也有自己的名字,该名字和存储服务器的
iqn
连接在一起,就构成了这个 Target 的iqn
,如iqn.2019-08.cn.littlenewton:epyc-truenas:openwrt-code
指的是littlenewton.cn
组织的epyc-truenas
存储服务器上的一个名为openwrt-code
的存储对象。
- 指的是在 Portal 后面真正提供存储的 iSCSI 对象,Initiator 通过 SAN 网络连接到 Target 即可获得存储服务。Target 本身也有自己的名字,该名字和存储服务器的
- Extents
- 这是 iSCSI 中最底层的概念,指的是 Target 统领的一段“存储空间”,它可以是某个物理磁盘,也可以是某个磁盘上的某个分区,也可以是某个 ZFS Pool 中的一个 ZVoL. 注意,TrueNAS SCALE 目前不支持把物理磁盘作为 Extent 使用,而 TrueNAS CORE 是可以的。一个 iSCSI Target 可以对应多个 Extents,这个观察非常关键。通过下面两张图片可以观察到确实如此。如果强行把 Target 理解成一个硬盘,那么 Extent 就是上面的分区,因此挂载一个 Target 就相当于把所有分区都挂载上。这么理解没有问题,但是没有用。
由此我们简单总结一下:
Portal
代表 SAN 网络中的网络位置,其实就是 IP 地址加 TCP 端口号。Target
代表一个存储服务依赖的资源,这是一个抽象概念,它既不是一个硬盘,也不是一台服务器。在现实中找不到很一致的类比。Extent
指的是一个逻辑硬盘(LUN
),多个 Extents 可以挂在同一个 Target 上,这样通过一次iscsiadm login
操作就能识别 SAN 中多个硬盘,这多个硬盘就构成了一个独立的服务。这与我们日常的操作逻辑是完全一致的。
可以通过下图理解一下 SAN 网络的拓扑结构。
重点看一下一个 Target (cloud
) 对应多个 Extents (nutstore
和 onedrive
) 的情况。
1.1 TrueNAS SCALE·
1.1.1 配置 iqn·
TrueNAS SCALE 作为通用存储的开源解决方案,配置 iSCSI 共享非常简单。在 Shares 界面找到 Block (iSCSI) Shares Targets 选项卡,点击 Configure,首先修改 Base Name. 改成合适的 iqn
.
1.1.2 配置 Portals·
如前所述,Portal 就是一个网卡和监听端口。此处不再赘述。
Portals 里面也可以配置 CHAP 加密,但是 TrueNAS SCALE 的设计有问题,Authorized Access 引用 ID 会产生重复。鉴于不加认证就能发起 Discovery 并不会造成很大风险,因此可以忽略这个认证。
1.1.3 配置 Initiator Groups·
如前所述,Initiator Group 在术语介绍部分讲过,是用来做 ACL 的重要信息。Group ID 将被填写到某些 Target 里,iqn 存在于 Group 里的 Initiator 才能在 discover 阶段发现这些 Target.
1.1.4 配置 Authorized Access 密码本·
某些 Initiator 将会使用 CHAP 加密建立 iSCSI 通信,因此,从逻辑上讲需要在 iSCSI 服务器上维护一个用户、密钥列表。Authorized Access 就是做这个工作。
图中虽然存在一个 Group ID,但它只是用来标识这一行用户、密码。填写到 Target 里的也只是这个 ID,因此,原则上一个 iqn 可以拥有多个密码,但这是很不常见的。
1.1.5 配置 Targets·
上述基本都是为了配置 Target 而存在。
让我们看一下细节:
Target 作为连接 endpoint,在安全性上可谓是层层加码:
- 为了防止不同 SAN 网络的机器通过多网卡胡乱连接,首先加一层网段/主机限制。只允许特定网段的机器或特定主机访问。但是要注意,客户端的 IP 由客户端自己决定,因此限制访问者的 IP 并不能保证安全。
- 为了防止连接从不受控制的网卡发起,限制 Portal. 这只是 Server 自己对自己的限制,避免不处于 SAN 网络中的以太网卡对外提供存储服务。
- 为了防止同一个 SAN 网络中不合法的机器连接 Target,要设置 Initiator Group ID,即白名单。但是要注意,Initiator name 也是由发起者自由更改,因此限制 iqn 也不能保证安全。
- CHAP 认证,只有拥有正确的
iqn:secret
pair 的机器才能发起连接。由于 Initiator 登录的口令被存储在 Server 的 Target 里,因此具有强鉴权能力。但是貌似也不能防范爆破攻击。
如此一来,基本可以保证可访问性、机密性的“万无一失”。而且这个组还可以添加多个,配置非常灵活。
注意:此处有三个 Targets,但是 SAN 拓扑图里只有两个,因为我后面可能要购置一台服务器,所以把 Target 分离开比较好。此处的截图是真实情况。
1.1.6 配置 Extents·
Extents 在这个语境里很难翻译,如果认为是“程度”则完全不合适。我倾向于认为这就是逻辑硬盘,即 LUN. Extents 可以是某个文件,可以是一个 ZVoL,如果你用的是 TrueNAS CORE,那么 Extents 还可以是一整个物理硬盘。
1.1.7 将 Extents 与 Targets 相关联·
Targets 后面可以拖一堆 Extents,将某个 Extent 关联到某个 Target,可以让 Initiator 发起连接时直接找到这个 Target 下面的所有 Extents 逻辑盘。
1.1.8 小结·
由此,我们通过截图、介绍的方式,按照步骤讲解清楚了 iSCSI 块存储共享的配置。许多场景可能需要 RDMA 支持的 iSCSI,但是目前 TrueNAS 还不支持,所以我们把这个问题留到未来解决。
1.2 Debian 12 通用系统 iSCSI 服务端配置·
pass,我现在还不会,也没有需求。
2. iSCSI 客户端配置·
在 Windows Server 以及普通版本 Windows 上设置 iSCSI 客户端非常简单,图形化操作就是爽。但是在 Linux 上,需要对相关命令行非常熟悉。本着解决难题的想法,我们把主要精力放到 Linux 上。
2.1 Debian 12 iSCSI 客户端配置·
熟悉 Linux 软 RAID 的用户对 mdadm(Multiple Devices Administrator) 应该不陌生,配置 iSCSI 的命令行软件与其名字类似:iscsiadm
. 要学会使用 iscsiadm
,需要对 iSCSI 协议履行过程中的流程非常熟悉,总体来看,大致归为以下五个步骤:
- 某 initiator 对存储网络中某个存储服务器(Portal)发起
discovery
请求,试图获取 iscsi-target 列表 - Server 通过 Portal 收到 initiator discovery 请求之后,查看 initiator 发送过来的
iqn
,对本机所有的 target 进行遍历。target 中存储着下列一组四元组:{Portal_Group_ID, Initiator_Group_ID, Authentication_Method, Authentication_Group_Number}
. Server 将允许此 Initiator 访问的 Targets 发送给 Initiator. Target 四元组信息如下:
Portal_Group_ID
,指的是这个 Target 存储在哪个 Portal 后面。毕竟一个存储服务器可以有多张网卡、接入多个 SAN,因此指定 Portal 很重要。Initiator_Group_ID
,initiator Group 里存放了许多客户端的iqn
,Initiator_Group
绑定到该 Target,代表只有该组里的iqn
才有资格查看到这个 Target.Authentication_Method
,认证方法,一般是CHAP
.Authentication_Group_Number
,填写Authorized Access
,而Authorized Access
里存储着与客户端iqn
相关联的 CHAP secret 口令。如果你在客户端里配置了 CHAP secret,那么就需要启用此项:把客户端的iqn
以及对应 CHAP secret 写入Authorized Access
,再把Authorized Access
ID 写到Authentication_Group_Number
.
- initiator 拿到 target 列表,则按照需要登录到特定的 target,从而获得逻辑硬盘。随后
cat /proc/partitions
即可查看多出来的硬盘。
登录到 target 之后,查看硬盘的妥善方法是使用 ls -al /dev/disk/by-id
命令查看输出:
1 | $ ll /dev/disk/by-id |
可以看到 11 行包含 openwrt-code
字样,这正是我日常用来防止 OpenWrt 源代码的逻辑盘。它指向 /dev/sda
,我们可以使用 mkfs
、mount
等命令对其进行格式化、挂载等常规操作。
熟悉完上述流程,我们再学习一下如何使用 iscsiadm.
2.1.1 iscsiadm
软件安装与配置·
Debian 12 系统可以通过下列命令安装 iSCSI 客户端软件:
1 | sudo apt install open-iscsi |
随后在命令行输入 iscsiadm -V
查看软件版本。一般来说,Debian 12 上游里的 open-iscsi 版本还是比较新的。
随后配置 Initiator iqn 名字:
1 | sudo vim /etc/iscsi/initiatorname.iscsi |
输入 InitiatorName=iqn.2019-08.cn.littlenewton:epyc-debian
,这也是此文件唯一的有效行。
最后配置 iSCSI 相关参数:
1 | sudo vim /etc/iscsi/iscsid.conf |
将相关行改为如下样式:
1 | node.session.auth.authmethod = CHAP |
**要重点区分 node 和 discovery 两个不同场景下的认证方法及口令。**不过我认为 discovery 有了 iqn 限制也基本够用了,只要在 session 建立时加一层认证即可。唯一的危险就是当 SAN 网络里存在恶意用户通过穷举 iqn 的方式发起 discovery 时,有泄露 LUN 名字的危险。
2.1.2 使用 iscsiadm
登录到 Portal·
由于我们没有改 iSCSI 服务默认端口,所以只写 IP 地址即可。
1 | sudo iscsiadm -m discovery --type sendtargets --portal 10.2.1.33 |
iscsiadm
使用 mode
(-m
) 和 operation-type
(-type
) 组合的方式实现操作。我们登录时的 mode 是 discovery
,要求对方给我们发送 Targets 列表。
2.1.3 使用 iscsiadm
登录到某个 Target·
此时使用 node
模式,-T
(--targetname
) 指代要连接到的 Target,行为是 --login
(-l
),即登录。
1 | sudo iscsiadm -m node -T iqn.2019-08.cn.littlenewton:epyc-truenas:openwrt-code --login |
如果要登录到所有已知的 Targets,可以直接写 --loginall
(-L
).
2.1.4 使用 iscsiadm
修改开机自动挂载·
如果不修改,那么重启之后系统不会自动搜索 Target 并连接,很多服务可能因此无法启动。为此,我们在 discovery 之后,查看
1 | sudo cat /etc/iscsi/nodes/iqn.2019-08.cn.littlenewton:epyc-truenas:openwrt-code/10.2.1.33,3260,1/default |
会得到一大串输出:
1 | # BEGIN RECORD 2.1.3 |
这是我们登录到该 Target (Node) 之后,客户端记录到的有关信息。其中第四行 node.startup
为手动,我们需要改成自动,可通过如下命令实现:
1 | sudo iscsiadm -m node -T iqn.2019-08.cn.littlenewton:epyc-truenas:openwrt-code -o update -n node.startup -v automatic |
如此一来,即可完成开机自动启动。如果对这个硬盘初始化完成(以 ext4 文件系统为例),可以在 /etc/fstab
里添加下面一行代码实现自动挂载(前提是已经创建好挂载点,即 mkdir /home/newton/epyc-truenas-openwrt
)。如此一来便于普通硬盘没有区别。
1 | /dev/sda /home/newton/epyc-truenas-openwrt ext4 _netdev 0 0 |
2.2 Windows Server iSCSI 客户端配置·
Windows 客户端非常简单。
2.2.1 配置 iscsi 发起程序·
在 Windows 搜索中输入“iSCSI 发起程序”,进入程序。首先点击配置选项卡,将本机的 iqn
按照之前提到的方法修改。
由于我们不需要设置 discovery 验证,因此无需继续配置。
2.2.2 进行目标发现·
2.2.3 高级选项·
会话的 CHAP 认证可以在这里找到。如果连接不稳定,可以在连接方式中手动配置。