ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Ubuntu 20.04 iSCSI生产部署:LIO内核态Target与Multipath深度实践

Ubuntu 20.04 iSCSI生产部署:LIO内核态Target与Multipath深度实践 1. 为什么在 Ubuntu 20.04 Server 上部署 iSCSI 不是“装个包就完事”——它本质是一次存储架构的重新定义iSCSI 这个词很多人第一反应是“网络硬盘”但如果你真把它当成一块插在 USB 口上的移动硬盘来用那接下来的三天你会反复重启服务器、重查日志、怀疑人生。我在给一家做边缘视频分析的客户部署存储集群时就栽在这上面他们要求用三台 Ubuntu 20.04 Server 构建一个高可用 iSCSI 存储池前端跑 OpenStack 计算节点挂载。结果第一天测试虚拟机启动到一半直接蓝屏没错Windows 虚拟机日志里全是connection reset by peer和target login failed。排查了整整 36 小时最后发现不是配置错而是根本没理解 iSCSI 在 Linux Server 环境下的真实角色——它不是“附加存储”而是把网络变成 SCSI 总线的延伸。Ubuntu 20.04 Server 作为 LTS 版本内核为 5.4自带targetcli-fb和open-iscsi但默认不启用、不配置、不校验路径可靠性。这意味着你apt install tgt或apt install iscsitarget后得到的只是一个能响应登录请求的“壳”而真正的 SCSI 协议栈行为、会话保持机制、多路径容错逻辑全靠你手动补全。这不是 Windows 下点几下“添加 iSCSI 发起程序”的体验这是在裸金属上重建一套存储通信协议栈。关键词里没有写明但所有实际生产环境都绕不开的三个硬约束是LUN 持久性映射、CHAP 认证强制启用、Multipath I/O 路径收敛。我见过太多人跳过 CHAP 直接用 IP 白名单结果被内网扫描器扫出 target 列表LUN 被未授权主机挂载写坏也见过没配 multipath 的场景单条链路抖动导致数据库事务中断MySQL 报Lost connection to server at reading initial communication packet——这和你搜到的 SQL Server 错误本质同源都是底层块设备连接不可靠引发的上层协议雪崩。所以这篇不是“Ubuntu20.04 安装 iSCSI 教程”而是带你从协议栈底层看清楚当iscsiadm -m discovery -t st -p 192.168.1.100执行时Linux 内核到底做了什么当targetcli创建一个backstore/block时它如何绕过 page cache 直接对接物理盘当你在/etc/iscsi/iscsid.conf里调node.session.iscsi.InitialR2T时你真正控制的是 TCP 连接建立后的第几个 SCSI 命令阶段。这些细节决定了你的 iSCSI 是能扛住 7×24 小时录像写入还是每小时掉一次链。2. 服务端targetcli与tgt的本质区别——别再用错工具选型Ubuntu 20.04 Server 默认仓库里有两个主流 iSCSI Target 实现tgt即iscsitarget和targetcli-fb基于 LIO 内核子系统。很多教程混着讲甚至教你在同一台机器上同时装两者这是灾难的开始。我必须说清楚tgt是用户态守护进程targetcli是内核态 LIO 的命令行前端——它们不在同一抽象层级不能共存更不能互相替代。先看tgt。它通过tgtd进程监听 3260 端口所有 SCSI 命令解析、状态维护都在用户空间完成。好处是调试方便、模块独立坏处是性能瓶颈明显尤其在高 IOPS 场景下CPU 会成为瓶颈。我们曾用tgt挂载一块 NVMe SSD 作为 LUN实测随机读写 IOPS 卡在 12,000 左右而同样盘直连发起端IOPS 超过 450,000。差距来自用户态到内核态的多次拷贝以及 SCSI 协议状态机的纯软件模拟。再看targetcli-fb。它操作的是 Linux 内核 2.6.38 引入的 LIOLinux IO Target子系统所有 SCSI 命令处理、会话管理、数据传输都在内核中完成。targetcli只是一个 shell 风格的配置界面背后调用的是configfs接口。这意味着LUN 创建后内核自动为其分配scsi_target设备节点CHAP 认证由内核 crypto API 完成无需额外进程多路径支持原生集成dm-multipath可直接识别同一 LUN 的多个路径。提示Ubuntu 20.04 默认安装的是targetcli-fb而非旧版targetcli。二者命令语法高度相似但targetcli-fb支持iblock直接块设备、fileio文件模拟、pscsi物理 SCSI 设备等多种 backstore 类型且对 NVMe、ZFS ZVOL、LVM LV 兼容性更好。务必确认你装的是targetcli-fb运行targetcli --version输出应含fb字样。实操选型决策树如下若目标 LUN 是普通 SATA SSD 或 HDD且并发连接数 32tgt配置简单适合快速验证若需挂载 NVMe、ZFS 数据集、或要求 LUN 支持 ALUAAsymmetric Logical Unit Assignment、SCSI PRPersistent Reservations必须用targetcli-fb若要对接 VMware vSphere 或 Hyper-V后者明确要求 LIO 支持的iblockbackstoretgt无法通过认证。我最终为客户选择targetcli-fb因为他们的 OpenStack 环境要求每个计算节点能同时挂载 8 个 LUN且需支持 SCSI-3 PR 实现集群锁。以下是完整部署流程每一步都附带内核级原理说明# 1. 安装 targetcli-fb注意不是 targetcli sudo apt update sudo apt install -y targetcli-fb # 2. 启动并启用开机自启 sudo systemctl enable target sudo systemctl start target # 3. 加载内核模块Ubuntu 20.04 通常已加载但需确认 sudo modprobe iblock target_core_mod configfs # 4. 进入 targetcli 交互环境 sudo targetcli进入后你看到的不是传统 CLI而是一个类似文件系统的树状结构/ ls o- / ..................................................................... [...] o- backstores .......................................................... [...] | o- block .............................................. [Storage Objects: 0] | o- fileio ............................................. [Storage Objects: 0] | o- pscsi .............................................. [Storage Objects: 0] | o- ramdisk ............................................ [Storage Objects: 0] o- iscsi ........................................................ [Targets: 0] o- loopback ................................................... [Targets: 0]这个结构直接映射内核configfs的挂载点/sys/kernel/config/target/。每一个backstores/block对象都会在/sys/kernel/config/target/core/下生成对应目录并触发内核创建scsi_target设备。这才是真正“内核态 Target”的证据。3. 核心配置从物理盘到可发现 LUN 的七步链路——每一步都决定稳定性很多教程停在create /backstores/block disk1 /dev/sdb就结束但生产环境失败率最高的环节恰恰是这之后的五步。我把它拆解为一条不可跳过的七步链路缺一不可3.1 步骤一物理盘预处理——禁用 udev 自动挂载与 journaling假设你要用/dev/sdb作为 LUN 底层设备。千万别直接fdisk /dev/sdb分区再挂载——iSCSI Target 要求的是裸块设备raw block device任何文件系统层ext4/xfs或 LVM PV 标签都会干扰 SCSI 协议识别。首先确认该盘未被 udev 规则自动挂载# 查看当前 udev 规则是否对 sdb 有动作 ls /etc/udev/rules.d/ | grep -E (99|60)-.*sdb # 若存在临时注释掉相关行或执行 echo SUBSYSTEMblock, KERNELsdb, ENV{UDISKS_IGNORE}1 | sudo tee /etc/udev/rules.d/99-ignore-sdb.rules sudo udevadm control --reload-rules sudo udevadm trigger然后禁用 ext4/xfs journaling若已格式化# 若已格式化为 ext4关闭日志以减少写放大 sudo tune2fs -O ^has_journal /dev/sdb # 若为 xfs卸载后用 xfs_repair -L 强制清除日志慎用仅用于测试盘注意这步不是为了性能而是避免内核在iblock初始化时因检测到文件系统 superblock 而拒绝注册。LIO 的iblockbackstore 要求设备处于“干净裸盘”状态否则targetcli会报Failed to create Storage Object。3.2 步骤二创建 backstore ——iblock与fileio的取舍真相在targetcli中执行/ cd /backstores/block /backstores/block create disk1 /dev/sdb这里disk1是逻辑名/dev/sdb是物理路径。关键点在于必须用iblock而非fileio。fileio用malloc分配内存模拟块设备适合测试iblock直接绑定物理块设备支持 TRIM、UNMAP、WRITE SAME 等 SCSI 命令是生产唯一选择。验证创建成功# 查看内核是否已注册该设备 ls /sys/kernel/config/target/core/iblock_0/disk1/ # 应输出alua/ blist/ dev/ enable/ hw_max_sectors/ max_sectors/ ... # 其中 enable 文件值为 1 表示已激活 cat /sys/kernel/config/target/core/iblock_0/disk1/enable # 输出 13.3 步骤三创建 iSCSI Target —— IQN 命名规范不是形式主义/ cd /iscsi /iscsi create iqn.2024-03.com.example:storage01IQNiSCSI Qualified Name格式为iqn.YYYY-MM.reverse.domain:identifier。很多人随便写iqn.1994-04.com.mycompany:storage但问题在于vSphere 和某些 SAN 管理工具会严格校验 IQN 格式错误格式导致发现失败。Ubuntu 20.04 的open-iscsi发起端虽宽松但目标端targetcli会记录日志警告影响审计。更关键的是identifier部分它必须全局唯一。若你有多个 Target不能都叫storage应按用途区分storage-db、storage-backup、storage-vms。因为后续 CHAP 用户绑定、ACL 控制都依赖此标识。3.4 步骤四绑定 LUN ——luns/目录下的隐藏逻辑/iscsi cd iqn.2024-03.com.example:storage01/tpg1/luns /iscsi/iqn.2024-03.com.example:storage01/tpg1/luns create /backstores/block/disk1这步看似简单但luns/目录下实际发生的是内核为该 LUN 分配一个scsi_target设备并在/sys/class/scsi_target/下生成targetX:X:X目录。你可以实时观察# 在另一个终端执行 watch -n 1 ls /sys/class/scsi_target/ # 当 create 执行后会出现 target1:0:0 目录LUN ID 默认为 0。若需多个 LUN重复create命令ID 自增。注意LUN ID 必须连续否则某些旧发起端如 Windows Server 2012会跳过缺失 ID 的 LUN。3.5 步骤五配置 ACL —— 不是加 IP而是绑定 Initiator IQN/iscsi/iqn.2024-03.com.example:storage01/tpg1/acls create iqn.1994-04.com.redhat:rhel7-client这里iqn.1994-04.com.redhat:rhel7-client是发起端的 IQN不是 IP 地址。Ubuntu 20.04 的open-iscsi默认生成的 IQN 格式为iqn.YYYY-MM.{hostname}:xxx可通过iscsiadm -m node查看。ACL 的本质是只有列出的 Initiator IQN 才能登录该 Target。IP 白名单是tgt的功能LIO 不支持。若你只记得发起端 IP必须先登录发起端获取其 IQN# 在发起端Ubuntu 客户机执行 sudo iscsiadm -m discovery -t sendtargets -p 192.0.2.100 # 输出包含 InitiatorName即 IQN3.6 步骤六启用 CHAP 认证——明文密码的致命陷阱/iscsi/iqn.2024-03.com.example:storage01/tpg1/acls/iqn.1994-04.com.redhat:rhel7-client set auth useridstorage_user /iscsi/iqn.2024-03.com.example:storage01/tpg1/acls/iqn.1994-04.com.redhat:rhel7-client set auth passwordStrongPassw0rd!CHAPChallenge-Handshake Authentication Protocol是 iSCSI 唯一可靠的认证方式。userid和password会以 MD5 哈希形式存储在内核中不会明文暴露。但注意password字段最大长度为 16 字符超长会被截断——我曾因密码含 20 位 UUID 导致认证失败排查半天才发现是截断问题。启用 CHAP 后必须在发起端配置匹配的认证# 在发起端执行 sudo iscsiadm -m node -T iqn.2024-03.com.example:storage01 -p 192.0.2.100 --opupdate -n node.session.auth.authmethod -v CHAP sudo iscsiadm -m node -T iqn.2024-03.com.example:storage01 -p 192.0.2.100 --opupdate -n node.session.auth.username -v storage_user sudo iscsiadm -m node -T iqn.2024-03.com.example:storage01 -p 192.0.2.100 --opupdate -n node.session.auth.password -v StrongPassw0rd!3.7 步骤七保存配置并验证——saveconfig的真实作用/ saveconfigsaveconfig并非简单写入文件。它将当前configfs树结构序列化为/etc/target/saveconfig.json并在systemd服务启动时由target服务自动加载。这意味着重启后配置自动恢复手动修改/etc/target/saveconfig.json会导致target服务启动失败JSON 格式错误saveconfig必须在target服务运行时执行否则无效果。验证 Target 是否就绪# 查看监听状态 sudo ss -tlnp | grep :3260 # 应输出类似LISTEN 0 128 *:3260 *:* users:((tgtd,pid1234,fd6)) # 注意若用 targetcli-fb进程名是 target不是 tgtd # 查看 LUN 映射 sudo targetcli ls # 输出应包含已创建的 Target、LUN、ACL4. 发起端open-iscsi的深度调优——为什么默认配置在生产中必然失败Ubuntu 20.04 Server 自带open-iscsi包但默认/etc/iscsi/iscsid.conf是为桌面环境设计的。直接iscsiadm -m discovery后挂载在生产环境 100% 出现connection timeout、session recovery failed、read error on device。原因在于默认参数针对单次短连接优化而存储 LUN 要求持续会话保活。4.1 关键参数调优清单必须修改编辑/etc/iscsi/iscsid.conf以下参数需按生产环境调整参数默认值生产推荐值原理说明node.session.timeo.replacement_timeout160会话中断后发起端等待重连的最大秒数。设为 1 会导致网络抖动立即丢 sessionDB 事务中断。设为 60 允许链路短暂恢复。node.conn[0].timeo.noop_out_interval030每隔多少秒发送 NOPNo Operation心跳包。0 表示禁用必须启用以维持 TCP 连接活跃。node.conn[0].timeo.noop_out_timeout05NOP 包发出后等待响应的超时秒数。超过则断开连接重试。node.session.iscsi.InitialR2TYesNo是否启用初始 R2TReady To Transfer。设为 No 可减少握手延迟提升小包写入性能。node.session.iscsi.ImmediateDataYesYes是否允许立即数据传输。保持 Yes但需配合InitialR2TNo使用。修改后重启服务sudo systemctl restart open-iscsi sudo systemctl enable open-iscsi4.2 发起端发现与登录全流程含错误处理# 1. 发现 Target-t st 表示 SendTargets-p 指定 IP sudo iscsiadm -m discovery -t st -p 192.0.2.100 # 2. 查看发现结果会生成 /var/lib/iscsi/nodes/ 下的配置目录 sudo iscsiadm -m node # 3. 登录 Target-T 指定 Target IQN-p 指定 IP:Port sudo iscsiadm -m node -T iqn.2024-03.com.example:storage01 -p 192.0.2.100 --login # 4. 验证登录状态 sudo iscsiadm -m session -P 3 # 输出应显示 State: logged in 和 Attached scsi disk sdb若登录失败常见原因及排查命令CHAP 认证失败检查/var/log/syslog中iscsid日志搜索authentication failure确认发起端username/password与 Target 端完全一致大小写敏感Target 未启用在 Target 端执行sudo targetcli ls确认enable值为 1防火墙拦截Ubuntu 20.04 默认启用ufw需放行 3260 端口sudo ufw allow 3260MTU 不匹配若网络经过交换机确保所有设备 MTU ≥ 1500否则 SCSI 命令分片失败。4.3 设备持久化与 multipath 配置——避免重启后设备名漂移登录后LUN 会出现在/dev/sdX但设备名不固定如本次是sdb重启后可能变sdc。必须用 WWIDWorld Wide Identifier绑定# 获取 LUN 的 WWID sudo scsi_id -g -u -d /dev/sdb # 编辑 /etc/udev/rules.d/99-iscsi-persistent.rules echo KERNELsd*, SUBSYSTEMblock, PROGRAM/lib/udev/scsi_id --whitelisted --replace-whitespace --device/dev/\$name, RESULT14f0014f0014f0014, SYMLINKdisk/by-wwid/\$result | sudo tee /etc/udev/rules.d/99-iscsi-persistent.rules # 重载 udev 规则 sudo udevadm control --reload-rules sudo udevadm trigger此时/dev/disk/by-wwid/14f0014f0014f0014永远指向该 LUN无论sdX如何变化。若有多条路径如双网卡接入必须配置multipath-toolssudo apt install -y multipath-tools sudo cp /usr/share/doc/multipath-tools/examples/multipath.conf.synthetic /etc/multipath.conf sudo systemctl enable multipathd sudo systemctl start multipathd编辑/etc/multipath.conf添加defaults { user_friendly_names yes } devices { device { vendor LIO-ORG product IBLOCK path_grouping_policy multibus getuid_callout /lib/udev/scsi_id --whitelisted --replace-whitespace --device/dev/%n } }重启后sudo multipath -ll应显示mpatha设备聚合多条路径。5. 故障诊断从dmesg到tcpdump的四级排查法iSCSI 故障最怕“黑盒式”排查。我总结了一套四级定位法按耗时从短到长排列覆盖 95% 的生产问题5.1 第一级dmesg内核日志——看 SCSI 层是否初始化成功# 在 Target 端执行 sudo dmesg | grep -i scsi\|target\|iblock # 关键成功信号 # [ 1234.567890] target_core_mod: module loaded # [ 1234.567891] iblock: registered # [ 1234.567892] target: Registered IBLOCK fabric module # 在发起端执行 sudo dmesg | grep -i iscsi\|scsi # 关键成功信号 # [ 5678.901234] scsi host2: iSCSI Initiator over TCP/IP # [ 5678.901235] scsi 2:0:0:0: Direct-Access LIO-ORG IBLOCK 4.0 PQ: 0 ANSI: 5若无Direct-Access行说明 Target 未正确绑定 LUN 或 ACL 未生效。5.2 第二级ss与netstat——确认网络层连通性# Target 端确认监听 sudo ss -tlnp | grep :3260 # 应输出LISTEN 0 128 *:3260 *:* users:((target,pid1234,fd6)) # 发起端确认连接状态 sudo ss -tnp | grep :3260 # 成功登录后应有 ESTABLISHED 状态连接若 Target 端无监听检查systemctl status target若发起端无连接检查防火墙或网络路由。5.3 第三级iscsiadm -m session -P 3——分析会话层状态这是最核心的诊断命令。输出中重点关注State:应为logged in若为failed看Error:字段I_T nexus:应显示I_T nexus: 0x12345678若为0x0表示未建立 SCSI 会话Attached scsi disk:应显示设备名若为空说明 LUN 未映射成功Interface:应为default若为transport说明使用了非标准传输。常见错误码解读Error: 0x06Target 不支持该 SCSI 命令如发起端发了 UNMAPTarget 未启用Error: 0x10Authentication failedCHAP 密码错误Error: 0x11ISCSI_LOGIN_FAILED_TO_STARTTarget 未启用或 ACL 未匹配。5.4 第四级tcpdump抓包分析——协议层终极验证当以上三级均正常但 I/O 仍失败时必须抓包# 在 Target 端抓包过滤 iSCSI 流量 sudo tcpdump -i any -w iscsi-target.pcap port 3260 and host 192.0.2.200 # 在发起端抓包 sudo tcpdump -i any -w iscsi-initiator.pcap port 3260 and host 192.0.2.100用 Wireshark 打开过滤iscsi观察是否有Login Request/Response交换Text Request/Response中是否包含AuthMethodCHAPSCSI Command是否被SCSI Response正确响应是否出现RejectPDU表示协议错误。我曾遇到一个案例发起端发送READ(10)命令后Target 返回Reject原因是发起端FirstBurstLength设置过大1MB而 TargetMaxRecvDataSegmentLength为 262144。通过抓包定位后在发起端iscsid.conf中添加node.session.iscsi.FirstBurstLength 65536 node.session.iscsi.MaxBurstLength 262144问题解决。6. 生产加固防火墙、监控、备份的三道防线部署完成不等于稳定运行。Ubuntu 20.04 Server 环境下必须构建三层防护6.1 防火墙策略——最小权限原则Ubuntu 默认ufw但 iSCSI 需精细控制# 仅允许指定子网访问如 192.0.2.0/24 sudo ufw allow from 192.0.2.0/24 to any port 3260 proto tcp # 禁用 ICMP 重定向防止中间人攻击 echo net.ipv4.conf.all.send_redirects0 | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 启用 conntrack 限制防 SYN Flood echo net.netfilter.nf_conntrack_max65536 | sudo tee -a /etc/sysctl.conf sudo sysctl -p6.2 监控集成——用prometheusnode_exporter监控关键指标iSCSI 健康度不能只看ping需监控Target 端/sys/kernel/config/target/iscsi/*/tpg1/portals/*/enable端口启用状态发起端/sys/class/scsi_host/host*/device/session*/state会话状态全局/proc/scsi/scsi中 Attached devices 数量。我编写了一个 exporter 脚本每 30 秒采集# 获取活跃会话数 SESSIONS$(sudo iscsiadm -m session 2/dev/null | grep tcp: | wc -l) # 获取 LUN I/O 统计需 root IOSTAT$(sudo cat /sys/class/scsi_device/*/device/stat 2/dev/null | awk {sum$1} END {print sum0}) echo iscsi_sessions $SESSIONS /tmp/iscsi.prom echo iscsi_io_requests $IOSTAT /tmp/iscsi.promPrometheus 抓取/tmp/iscsi.prom设置告警规则iscsi_sessions 0或rate(iscsi_io_requests[5m]) 0。6.3 备份与回滚——targetcli配置的版本化管理/etc/target/saveconfig.json是唯一配置源但手动编辑风险高。我采用 Git 版本化# 初始化配置仓库 sudo mkdir -p /etc/target/config-backup sudo git -C /etc/target/config-backup init sudo git -C /etc/target/config-backup add /etc/target/saveconfig.json sudo git -C /etc/target/config-backup commit -m Initial config # 每次修改后提交 sudo cp /etc/target/saveconfig.json /etc/target/config-backup/ sudo git -C /etc/target/config-backup add /etc/target/config-backup/saveconfig.json sudo git -C /etc/target/config-backup commit -m Update LUN disk1 size回滚只需sudo git -C /etc/target/config-backup checkout HEAD~1 -- /etc/target/config-backup/saveconfig.json sudo cp /etc/target/config-backup/saveconfig.json /etc/target/saveconfig.json sudo systemctl restart target这套方法已在 12 个客户环境中验证平均故障恢复时间从 45 分钟降至 3 分钟。最后分享一个血泪教训某次升级内核后targetcli报configfs not mounted。查/proc/mounts发现/sys/kernel/config未挂载。原来 Ubuntu 20.04 的initramfs默认不加载configfs模块。解决方案是在/etc/initramfs-tools/modules中添加configfs然后sudo update-initramfs -u。这个细节文档里从不提但线上事故里天天见。
返回列表