Ubuntu 22.04下用Tgt搭建iSCSI共享存储的完整流程(含多客户端配置)
在Ubuntu 22.04上构建企业级iSCSI共享存储:Tgt实战与多客户端并发访问深度指南
最近在为一个中小型开发团队搭建统一的测试数据存储环境时,我再次将目光投向了iSCSI。你可能听说过NFS或者Samba,但在需要块设备级别共享、追求更低延迟和更高性能的场景下,iSCSI往往是更专业的选择。尤其是在虚拟化环境、数据库集群或者需要共享同一块“物理”磁盘给多台服务器的场景里,iSCSI提供的是一种近乎直连的存储体验。而Ubuntu 22.04 LTS作为当前长期支持版本,其稳定性和软件生态使其成为部署这类服务的理想平台。今天,我们就来深入聊聊如何用Tgt这个轻量高效的iSCSI Target软件,在Ubuntu 22.04上打造一个不仅能用,而且好用、安全的共享存储系统,并重点攻克多客户端并发访问这一常见痛点。
1. 理解iSCSI与Tgt:为何选择这个组合?
在动手之前,我们有必要先理清几个核心概念。iSCSI(Internet Small Computer System Interface)本质上是一种将SCSI命令封装在TCP/IP网络包中进行传输的协议。它允许客户端(Initiator)通过网络访问远程服务器(Target)上的存储设备,就像访问本地硬盘一样。这种架构带来的最大好处是解耦了计算与存储,使得存储扩容、数据迁移和维护变得异常灵活。
那么,在Linux世界里实现iSCSI Target的工具有不少,比如LIO(Linux-IO Target)、SCST和Tgt。我偏爱Tgt的原因在于它的“简单直接”。Tgt(STGT的继承者)配置语法直观,文档清晰,对于大多数中小规模的应用场景来说,它提供了恰到好处的功能集,而不会引入不必要的复杂性。它的后台服务tgt在Ubuntu仓库中维护良好,安装和后续升级都省心。
注意:选择存储方案时,需要明确你的需求。如果你需要极致的性能调优和最丰富的企业级功能(如完整的SCSI-3持久预留支持),可能需要评估LIO。但对于开发测试、中小型文件服务器、虚拟机共享存储等场景,Tgt的易用性和稳定性已经绰绰有余。
一个典型的Tgt iSCSI架构包含以下组件:
- Target(目标端):运行Tgt服务的Ubuntu服务器,它“导出”一个或多个存储块设备(LUN)。
- Initiator(发起端):需要连接并使用这些存储的客户端,可以是另一台Ubuntu服务器、Windows机器,甚至是ESXi主机。
- IQN(iSCSI Qualified Name):每个Target和Initiator的唯一标识符,格式通常为
iqn.YYYY-MM.倒序域名:自定义标识。
理解了这些,我们就可以开始动手搭建了。
2. 目标端(Target)部署:从安装到精细配置
我们的旅程从存储服务器开始。假设你有一台安装了Ubuntu 22.04 LTS的机器,并准备好了一块用于共享的磁盘(例如/dev/sdb)。如果使用虚拟机,可以添加一块新的虚拟硬盘。
2.1 安装与基础服务管理
首先,更新软件包列表并安装tgt。在Ubuntu 22.04上,这个过程非常简洁。
sudo apt update sudo apt install tgt -y安装完成后,系统会自动启动tgt服务并启用开机自启。我们可以检查一下服务状态,确保它正在健康运行。
sudo systemctl status tgt你应该能看到类似“active (running)”的输出。如果服务没有启动,使用sudo systemctl start tgt手动启动,并用sudo systemctl enable tgt确保开机自启。
2.2 核心配置:定义你的存储目标
Tgt的配置文件主要位于/etc/tgt/conf.d/目录下。推荐的做法是为每个Target创建独立的配置文件,而不是全部堆在/etc/tgt/targets.conf里,这样管理起来更清晰。我们来创建一个名为mydatastore.conf的配置文件。
sudo nano /etc/tgt/conf.d/mydatastore.conf接下来是配置的核心部分。我们将定义一个Target,并指定要共享的后端存储。这里假设我们使用整块磁盘/dev/sdb。
<target iqn.2024-05.local.ubuntu:tgt.datastore> # 共享的存储设备,这里是一个完整的磁盘 backing-store /dev/sdb # 为LUN分配一个ID,默认为0,但显式声明是个好习惯 lun 1 # 设置厂商信息,便于客户端识别 vendor_id MyStorageCorp # 启用写缓存(根据硬件和需求谨慎设置) write-cache on # 可选的CHAP认证,增强安全性(后续详述) # incominguser myusername mysecretpassword </target>对关键参数的解释:
| 参数 | 说明 | 建议值/示例 |
|---|---|---|
backing-store | 后端存储设备的路径。可以是物理磁盘(/dev/sdb)、分区(/dev/sdb1)、镜像文件或逻辑卷。 | 根据实际设备填写 |
lun | 逻辑单元号。一个Target下可以有多个LUN。 | 通常从1开始 |
vendor_id | 厂商标识字符串,会在客户端显示。 | 自定义,便于识别 |
write-cache | 是否启用写缓存。启用可提升性能,但在断电等异常情况下有数据丢失风险。 | 根据数据安全性要求选择 |
保存并退出编辑器。然后,重新加载Tgt的配置,使其生效。这里有个小技巧:使用reload而不是restart,可以避免中断已建立的连接(如果有的话)。
sudo tgt-admin --update all # 或者使用systemctl重新加载服务 sudo systemctl reload tgt现在,使用tgt-admin命令验证我们的Target是否已正确加载并在线。
sudo tgt-admin --show输出应该会详细显示你刚定义的Target信息,包括它的IQN、状态以及关联的LUN详情。
2.3 网络与防火墙配置
iSCSI默认使用TCP 3260端口。确保你的防火墙允许该端口的入站流量。如果使用Ubuntu内置的ufw,命令如下:
sudo ufw allow 3260/tcp sudo ufw reload如果你的服务器在云上(如AWS、Azure、GCP),别忘了在云服务商的安全组/防火墙规则中同样开放3260端口。
3. 发起端(Initiator)配置:单客户端连接
现在,切换到另一台作为客户端的Ubuntu 22.04机器上。我们需要安装open-iscsi软件包,它包含了iSCSI发起端所需的工具。
sudo apt update sudo apt install open-iscsi -y安装后,服务open-iscsi会自动启动。接下来,我们将发现并登录到目标端。
发现目标:使用
iscsiadm命令,指定目标端服务器的IP地址进行发现。sudo iscsiadm -m discovery -t st -p 192.168.1.100请将
192.168.1.100替换为你Tgt服务器的实际IP地址。成功后,你会看到类似下面的输出,其中包含了目标端的IQN:192.168.1.100:3260,1 iqn.2024-05.local.ubuntu:tgt.datastore这条信息会自动记录到
/etc/iscsi/nodes/目录下。登录目标:执行登录命令,建立连接。
sudo iscsiadm -m node --targetname iqn.2024-05.local.ubuntu:tgt.datastore --portal 192.168.1.100 --login看到“successful”的提示即表示登录成功。
此时,在客户端使用lsblk或fdisk -l命令,你应该能看到一个新的磁盘设备,通常命名为/dev/sdX(如/dev/sdc)。它现在就像一块本地硬盘一样待你使用。
格式化和挂载:你可以像操作普通硬盘一样,对其进行分区、创建文件系统并挂载。
# 假设新磁盘是 /dev/sdc sudo mkfs.ext4 /dev/sdc sudo mkdir /mnt/iscsi_shared sudo mount /dev/sdc /mnt/iscsi_shared现在,
/mnt/iscsi_shared目录就可以用来读写数据了。配置自动连接与挂载:为了让系统重启后能自动连接iSCSI磁盘并挂载,需要做两件事。
- 将iSCSI节点配置为自动登录:
sudo iscsiadm -m node --targetname iqn.2024-05.local.ubuntu:tgt.datastore --portal 192.168.1.100 --op update -n node.startup -v automatic - 在
/etc/fstab中添加挂载项。这里有个关键点:不能直接用/dev/sdc,因为设备名可能变化。推荐使用磁盘的UUID。先用blkid命令获取UUID:
然后在sudo blkid /dev/sdc/etc/fstab中添加一行:
注意UUID=你的磁盘UUID /mnt/iscsi_shared ext4 _netdev,defaults 0 0_netdev挂载选项非常重要,它告诉系统这是一个网络设备,必须在网络就绪后再尝试挂载。
- 将iSCSI节点配置为自动登录:
4. 多客户端并发访问:挑战与解决方案
让多个客户端同时连接同一个iSCSI Target很容易,但让它们安全、有序地并发读写同一块磁盘,则是另一个层面的挑战。这是很多初学者容易踩坑的地方。
4.1 问题本质:文件系统锁
当你将/dev/sdb通过iSCSI共享给客户端A和客户端B后,它们各自看到的是一块“物理”硬盘。如果两个客户端都在上面创建了ext4或XFS这样的常规Linux文件系统,并同时挂载读写,后果将是灾难性的——文件系统元数据损坏,数据丢失。因为这些文件系统设计时假设只有一个操作系统在直接控制硬件,它们无法感知网络另一端还有另一个系统也在操作同一份元数据。
4.2 解决方案:集群文件系统
解决之道是使用集群文件系统。这类文件系统内置了分布式锁管理机制,允许多个节点同时安全地访问同一个块设备。常见的选择有:
- OCFS2 (Oracle Cluster File System 2): 相对成熟,配置稍复杂,适合Oracle环境或需要稳定集群文件系统的场景。
- GFS2 (Global File System 2): 通常需要配合Red Hat的集群套件使用。
- GlusterFS / Ceph: 它们本身是分布式文件系统,架构上与iSCSI这种块存储共享不同,通常不建立在共享块设备之上。
对于我们的Tgt iSCSI环境,OCFS2是一个不错的起点。下面简述在两个客户端(ClientA和ClientB)上配置OCFS2的流程。
在所有客户端安装OCFS2工具:
sudo apt install ocfs2-tools -y在一个客户端上格式化磁盘为OCFS2(只需要做一次):
# 在ClientA上执行,假设iSCSI磁盘为/dev/sdc sudo mkfs.ocfs2 -N 2 -L "shared_data" /dev/sdc-N 2指定了最大集群节点数(即预计有多少个客户端会同时挂载),这里设为2。配置集群节点信息: 在所有客户端上编辑
/etc/ocfs2/cluster.conf,定义集群节点。两个节点的配置内容一致即可。sudo nano /etc/ocfs2/cluster.conf内容示例:
cluster: node_count = 2 name = my_iscsi_cluster node: ip_port = 7777 ip_address = 192.168.1.101 number = 1 name = clientA cluster = my_iscsi_cluster node: ip_port = 7777 ip_address = 192.168.1.102 number = 2 name = clientB cluster = my_iscsi_cluster加载OCFS2内核模块并启动集群服务:
sudo modprobe ocfs2 sudo service o2cb start sudo service ocfs2 start # 并配置为开机启动 sudo update-rc.d o2cb enable sudo update-rc.d ocfs2 enable在所有客户端上挂载磁盘:
sudo mkdir /mnt/ocfs2_shared sudo mount -t ocfs2 /dev/sdc /mnt/ocfs2_shared
现在,ClientA和ClientB都可以安全地向/mnt/ocfs2_shared读写文件了。你可以在一台机器上创建文件,在另一台机器上立刻看到并修改它。
提示:生产环境部署OCFS2前,务必仔细阅读其文档,并充分测试。对于更高要求的环境,可以考虑使用基于分布式存储(如Ceph RBD)的方案,它提供了更强大的扩展性和可靠性。
4.3 替代思路:逻辑卷管理器(LVM)与多路径
在多客户端场景下,除了文件系统,存储管理本身也有讲究。一种更灵活的架构是:在Tgt服务器端,使用LVM(Logical Volume Manager)来管理物理磁盘,然后导出逻辑卷(LV)作为iSCSI LUN。这样做的好处是:
- 灵活扩容:可以轻松扩展LV的大小,而客户端无需重新分区。
- 快照功能:可以创建LV的快照,用于数据备份或测试。
- 精简配置:可以创建大于实际物理空间的精简配置卷。
此外,对于要求高可用的客户端,可以配置iSCSI多路径(Multipathing)。即客户端通过多条网络路径(如两块网卡)连接到Target,当一条路径故障时,自动切换到另一条,同时还能实现负载均衡。这需要安装multipath-tools并进行相应配置。
5. 安全加固与性能调优
一个面向多客户端的存储系统,安全和性能不容忽视。
5.1 访问控制与CHAP认证
默认情况下,任何知道IP和IQN的发起端都可以连接你的Target。这显然不安全。Tgt支持使用CHAP(Challenge-Handshake Authentication Protocol)进行双向认证。
配置Target端CHAP: 在Target配置文件中,为特定的Target启用CHAP。
<target iqn.2024-05.local.ubuntu:tgt.datastore> backing-store /dev/vg_shared/lv_data lun 1 # 启用单向CHAP认证(Initiator向Target认证) incominguser alice secretpass123 # 启用双向CHAP认证(Mutual CHAP) # outgoinguser bob targetpass456 </target>修改配置后,记得
sudo tgt-admin --update all。配置Initiator端CHAP: 在发起端,需要将CHAP凭证添加到对应的节点记录中。
sudo iscsiadm -m node --targetname iqn.2024-05.local.ubuntu:tgt.datastore --portal 192.168.1.100 --op update -n node.session.auth.authmethod -v CHAP sudo iscsiadm -m node --targetname iqn.2024-05.local.ubuntu:tgt.datastore --portal 192.168.1.100 --op update -n node.session.auth.username -v alice sudo iscsiadm -m node --targetname iqn.2024-05.local.ubuntu:tgt.datastore --portal 192.168.1.100 --op update -n node.session.auth.password -v secretpass123
5.2 网络与磁盘性能优化
iSCSI性能很大程度上取决于网络和磁盘I/O。以下是一些调优方向:
- 专用网络: 如果条件允许,为iSCSI流量划分一个独立的VLAN或使用专用的物理网卡,避免与业务流量争抢带宽。
- 巨型帧(Jumbo Frames): 在网络交换机、Target和Initiator的网卡上启用MTU 9000,可以显著降低CPU开销并提升大块数据传输效率。确保网络路径上所有设备都支持并配置一致。
- 调整队列深度: 在发起端,可以尝试增加SCSI设备的队列深度以提升并发I/O能力。这可以通过udev规则或
/sys/block/sdX/device/queue_depth文件来设置。 - Target端缓存策略: 如前所述,
write-cache选项需要权衡。在配有BBU(电池备份单元)的RAID卡或服务器上,启用写缓存通常是安全的,并能极大提升写性能。否则,在数据安全性和性能之间需要谨慎选择。
6. 监控、维护与故障排查
系统上线后,持续的监控和维护是保证其稳定运行的关键。
- 监控Target状态: 定期使用
sudo tgt-admin --show查看Target和会话状态。关注SESSION部分,可以看到哪些发起端已连接。 - 查看系统日志: Tgt的日志通常输出到
/var/log/syslog或/var/log/messages。使用journalctl -u tgt可以查看服务的详细日志。 - 发起端常用命令:
sudo iscsiadm -m session -P 3: 显示当前所有iSCSI会话的详细信息,包括连接状态、传输统计等,是排查连接问题的利器。sudo iscsiadm -m node: 列出所有已发现的节点。
- 一个常见的连接问题: 如果发起端无法发现或登录目标,请按以下顺序检查:
- 网络是否通畅?
ping <target_ip> - 防火墙是否开放了3260端口?
- Target服务是否正在运行?
sudo systemctl status tgt - Target配置是否正确?IQN是否有拼写错误?
- 如果使用CHAP,用户名和密码是否匹配?
- 网络是否通畅?
在最近一次为数据科学团队部署共享存储时,我们就遇到了因客户端网络MTU设置不一致导致的性能断续问题。使用iscsiadm -m session -P 3查看发现存在大量传输错误,最终通过统一配置巨型帧解决。这种基于块设备的共享存储,一旦调优得当,其稳定性和速度会给团队协作带来质的提升。
