Eric Radman : a Journal

iSCSI Volume Claims

Persistent Volumes provide a means of connecting a service with storage. Local SSDs will, of course be uncontested in terms of latency, but iSCSI allows a container to be scheduled on any compute node.

Local Disk iSCSI NFSv3
Volume Claim Required yes yes no
Authenticated yes no
Schedule on any Node no yes yes
Concurrent Access yes no yes
Native Linux File System yes yes no
Uses Buffer Cache yes yes no

Target

Using ZFS, create a vdev for each target/lun

zfs create -o canmount=off zpool2/iscsi
zfs create -V 100G -o volmode=dev zpool2/iscsi/t0-lun0
zfs create -V 100G -o volmode=dev zpool2/iscsi/t0-lun1

Following the FreeBSD Network Services guide

# /etc/ctl.conf
auth-group ag0 {
    chap postgresql ************
}

portal-group pg0 {
    discovery-auth-group no-authentication
    listen 192.168.0.9
}

target iqn.2026-04.lan.fs1:target0 {
    auth-group ag0
    portal-group pg0

    lun 0 {
        path /dev/zvol/zpool2/iscsi/t0-lun0
        blocksize 4096
        size 100G
    }

    lun 1 {
        path /dev/zvol/zpool2/iscsi/t0-lun1
        blocksize 4096
        size 100G
    }
}

Initiator

Kubernetes needs the initiator service running on each node:

dnf -qy install iscsi-initiator-utils
systemctl enable --now iscsid

The volume claim will exect a device formatted with a file system without GPT or MBR patitions

---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: iscsi0
spec:
  capacity:
    storage: 100Gi
  accessModes:
  - ReadWriteOnce
  iscsi:
    targetPortal: 192.168.0.9:3260
    iqn: iqn.2026-04.lan.fs1:target0
    lun: 0
    fsType: ext4
    readOnly: false
    chapAuthSession: true
    secretRef:
      name: postgresql-data
  storageClassName: fs-vdev
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pg2-pvc
spec:
  accessModes:
  - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
  storageClassName: fs-vdev

Authentication is provided using a specialized secret provider

---
apiVersion: v1
kind: Secret
metadata:
  name: postgresql-data
type: "kubernetes.io/iscsi-chap"
stringData:
  node.session.auth.username: postgresql
  node.session.auth.password: ************

Testing

Initial connection test without authentication

t="iqn.2026-04.lan.fs1:target0"
p="fs1.lan:3260"
iscsiadm -m node --targetname $t --portal $p -o new     # add connection
iscsiadm -m node -L all                                 # log in
iscsiadm -m node                                        # list
iscsiadm -m node --targetname $t --portal $p -u         # log out
iscsiadm -m node --targetname $t --portal $p -o delete  # remove connection