1. iSCSI 核心概念(必读)
在配置 Kubernetes 存储之前,理解 iSCSI 的层级关系至关重要。这有助于理解 YAML 文件中 iqn 和 lun 参数的含义。
1.1 核心组件
- Initiator (发起端):即你的 Kubernetes 节点。它是客户端,负责去“连接”存储。
- Target (目标):即你的 Fons 存储服务端的一个访问点。
- 通俗理解:你可以把 Target 想象成一个 “用户账户” 或 “USB 集线器”。
- 它是连接的入口,拥有全球唯一的名称(IQN)。
- Kubernetes 必须先登录这个 Target,才能看到里面的磁盘。
- LUN (逻辑单元号):即 实际的存储空间/磁盘卷。
- 通俗理解:LUN 就是插在“USB 集线器”上的 U盘。
- Target 只是门,LUN 才是真正存数据的房间。
1.2 Target 与 LUN 的绑定关系
一个 Target 可以绑定多个 LUN。这就是为什么在 YAML 中 iqn 和 lun 是分开配置的。
- 一对一 (One-to-One):这是最简单、最推荐给 K8s 使用的模式。一个 Target 只挂载一个 LUN。
- 此时,该 LUN 的编号永远是 0。
- 一对多 (One-to-Many):一个 Target 挂载了多个磁盘卷。
- 编号逻辑:LUN 的 ID 通常取决于绑定顺序(在 Fons/Linux LIO 等系统中常见)。
- 第 1 个绑定的卷 -> LUN 0
- 第 2 个绑定的卷 -> LUN 1
- 第 3 个绑定的卷 -> LUN 2
⚠️ 之前的故障复盘:
你之前在 Fons 上创建了一个名为 target-2 的目标,但它是你创建的第 3 个 Target。
你在 K8s YAML 中填了 lun: 2,以为名字带 "2" 就是 LUN 2。
这是错误的。 因为在这个 target-2 内部,你只挂载了一块盘。根据顺序逻辑,这块唯一的盘就是 LUN 0。
所以,绝大多数情况下,除非你在同一个 Target 下挂了多块盘,否则 YAML 里的 lun 永远填 0。
2. 节点准备工作(所有节点)
必须在所有 K8s Worker 节点执行以下操作,否则 Pod 无法挂载磁盘。
2.1 安装 iSCSI 客户端工具
# Ubuntu / Debian
sudo apt-get update
sudo apt-get install -y open-iscsi
sudo systemctl enable --now iscsid
# CentOS / RHEL
sudo yum install -y iscsi-initiator-utils
sudo systemctl enable --now iscsid
3. 磁盘初始化(关键步骤)
为了规避 Kubernetes 在自动挂载时可能发生的 mkfs.ext4: Input/Output error 或超时错误,我们需要在 Linux 层面手动提前格式化磁盘。
请找任意一台安装了上述工具的节点执行:
3.1 格式化 PostgreSQL 磁盘 (8Gi)
假设这是你分配给 Target-2 的盘。
# 1. 发现 Target
sudo iscsiadm -m discovery -t sendtargets -p 192.168.6.157:3260
# 2. 登录 Target-2
# 登录也就是“插上 USB 集线器”
sudo iscsiadm -m node -T iqn.2025-11.com.fnnas:target-2.um5v1y55fuww -p 192.168.6.157:3260 -l
# 3. 确认磁盘设备
# 既然是 Target 下的第一块盘,它就是 LUN 0。系统会识别为一个 sdX 设备。
lsblk
# (找到 8Gi 的那个盘,假设是 /dev/sdb)
# 4. 格式化为 ext4 (警告:数据会清空)
sudo mkfs.ext4 /dev/sdb
# 5. 【重要】注销连接 (防止设备占用)
# 格式化完必须“拔掉”,否则 K8s 稍后会认为设备正忙。
sudo iscsiadm -m node -T iqn.2025-11.com.fnnas:target-2.um5v1y55fuww -p 192.168.6.157:3260 -u
3.2 格式化 Halo 磁盘 (10Gi)
假设这是你分配给 Target-3 的盘。
# 1. 登录 Target-3
sudo iscsiadm -m node -T iqn.2025-11.com.fnnas:target-3.ta85oymzy6vq -p 192.168.6.157:3260 -l
# 2. 确认磁盘设备 (找 10Gi 的盘)
lsblk
# 3. 格式化
sudo mkfs.ext4 /dev/sdb
# 4. 【重要】注销连接
sudo iscsiadm -m node -T iqn.2025-11.com.fnnas:target-3.ta85oymzy6vq -p 192.168.6.157:3260 -u
4. Kubernetes 资源部署
4.1 PV 与 PVC 的使用逻辑
- PV (PersistentVolume):是对底层存储(Fons iSCSI)的描述。我们需要在这里告诉 K8s:去连哪个 Target (IQN),找第几个 LUN (通常是 0)。
- PVC (PersistentVolumeClaim):是 Pod 对存储的申请书。
- 绑定:我们通过
claimRef字段,强行把这两个东西绑在一起,防止 K8s 乱点鸳鸯谱。
4.2 创建 PersistentVolume (PV)
将以下内容保存为 pv.yaml 并应用。
apiVersion: v1
kind: PersistentVolume
metadata:
name: halo-postgresql-iscsi-pv
spec:
capacity:
storage: 8Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: "" # 必须留空,因为我们手动管理
claimRef: # 【关键】强制绑定到指定的 PVC
name: data-halo-postgresql-0
namespace: halo
iscsi:
targetPortal: 192.168.6.157:3260
iqn: iqn.2025-11.com.fnnas:target-2.um5v1y55fuww
# 【重点】这里填 0,因为这块 8G 盘是你在这个 Target 下绑定的第一块盘
lun: 0
fsType: ext4
readOnly: false
---
apiVersion: v1
kind: PersistentVolume
metadata:
name: halo-iscsi-pv
spec:
capacity:
storage: 10Gi
accessModes:
- ReadWriteOnce
persistentVolumeReclaimPolicy: Retain
storageClassName: ""
claimRef:
name: halo
namespace: halo
iscsi:
targetPortal: 192.168.6.157:3260
iqn: iqn.2025-11.com.fnnas:target-3.ta85oymzy6vq
lun: 0
fsType: ext4
readOnly: false
4.3 创建 PersistentVolumeClaim (PVC)
将以下内容保存为 pvc.yaml 并应用。
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: data-halo-postgresql-0 # 名字必须与 StatefulSet 要求的一致
namespace: halo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 8Gi
storageClassName: "" # 必须为空
volumeName: halo-postgresql-iscsi-pv # 反向指定 PV,确保双向绑定
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: halo
namespace: halo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 10Gi
storageClassName: ""
volumeName: halo-iscsi-pv
5. 常见问题排查 (Troubleshooting)
| 现象 | 原因 | 解决方案 |
|---|---|---|
Pending, executable file not found | 节点未安装 iSCSI 工具 | 在所有 Node 执行 apt/yum install open-iscsi。 |
Timed out waiting for device | LUN ID 错误 | 检查 YAML 中的 lun。如果你每个 Target 只给了一块盘,lun 必须填 0,无论 Target 叫什么名字。 |
mkfs.ext4: Input/Output error | 网络波动或自动格式化失败 | 按照本文第 3 节,手动在节点上 mkfs,然后重启 Pod。 |
iscsiadm: No records found | 未执行发现操作 | 执行 sudo iscsiadm -m discovery -t sendtargets -p <IP>。 |
session already present | 之前的连接未断开 | 执行 sudo iscsiadm -m node -u 强制注销。 |
| 删除 PVC 后 PV 显示 Released | Retain 策略的保护机制 | kubectl edit pv xxx,删除 claimRef 字段下的所有内容,保存后 PV 会变为 Available。 |