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
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 } }
Initial connection test on Linux (without authentication)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>~/www/eradman.com/Untitled.xhtml</title> <meta name="Generator" content="Vim/9.2" /> <meta name="plugin-version" content="vim9.2_v1" /> <meta name="syntax" content="nginx" /> <meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" /> <meta name="colorscheme" content="default" /> <style type="text/css"> pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; } body { font-family: monospace; color: #000000; background-color: #ffffff; } * { font-size: 1em; } a { color: inherit; } .Comment { color: #0000c0; } .Constant { color: #c00000; } .Special { color: #c000c0; } .Type { color: #008000; } </style> </head> <body> <pre id='vimCodeElement'> 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 <span class="Comment"># /etc/ctl.conf</span> auth-group ag0 { chap postgresql <span class="Special">*</span>*********** } portal-group pg0 { discovery-auth-group no-authentication <span class="Type">listen</span> <span class="Special">192.168.0.9</span> } target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 { auth-group ag0 portal-group pg0 lun <span class="Constant">0</span> { path /dev/zvol/zpool2/iscsi/t0-lun0 blocksize 4096 size 100G } lun <span class="Constant">1</span> { path /dev/zvol/zpool2/iscsi/t0-lun1 blocksize 4096 size 100G } } </pre> </body> </html> <!-- vim: set foldmethod=manual : -->
Initiator
Kubernetes needs the initiator service running on each node:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>~/www/eradman.com/Untitled.xhtml</title>
<meta name="Generator" content="Vim/9.2" />
<meta name="plugin-version" content="vim9.2_v1" />
<meta name="syntax" content="nginx" />
<meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" />
<meta name="colorscheme" content="default" />
<style type="text/css">
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; }
body { font-family: monospace; color: #000000; background-color: #ffffff; }
* { font-size: 1em; }
a { color: inherit; }
.Comment { color: #0000c0; }
.Constant { color: #c00000; }
.Special { color: #c000c0; }
.Type { color: #008000; }
</style>
</head>
<body>
<pre>
dnf -qy install iscsi-initiator-utils
systemctl enable --now iscsid
<span class="Comment"># /etc/ctl.conf</span>
auth-group ag0 {
chap postgresql <span class="Special">*</span>***********
}
portal-group pg0 {
discovery-auth-group no-authentication
<span class="Type">listen</span> <span class="Special">192.168.0.9</span>
}
target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 {
auth-group ag0
portal-group pg0
lun <span class="Constant">0</span> {
path /dev/zvol/zpool2/iscsi/t0-lun0
blocksize 4096
size 100G
}
lun <span class="Constant">1</span> {
path /dev/zvol/zpool2/iscsi/t0-lun1
blocksize 4096
size 100G
}
}
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
The volume claim will exect a device formatted with a file system without GPT or MBR patitions. Since the iSCSI device is connected on the kubernetes node it will appear as local device
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>~/www/eradman.com/Untitled.xhtml</title>
<meta name="Generator" content="Vim/9.2" />
<meta name="plugin-version" content="vim9.2_v1" />
<meta name="syntax" content="nginx" />
<meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" />
<meta name="colorscheme" content="default" />
<style type="text/css">
pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; }
body { font-family: monospace; color: #000000; background-color: #ffffff; }
* { font-size: 1em; }
a { color: inherit; }
.Comment { color: #0000c0; }
.Constant { color: #c00000; }
.Special { color: #c000c0; }
.Type { color: #008000; }
</style>
</head>
<body>
<pre>
$ mount | grep sda
/dev/sda on /var/lib/kubelet/plugins/kubernetes.io/iscsi/iface-default/192.168.0.9:3260-iqn.2026-04.lan.fs1:target0-lun-0 type ext4 (rw,relatime,stripe=4)
/dev/sda on /var/lib/kubelet/pods/bb8a3569-ceb8-4ee3-a6d6-308194f07ff8/volumes/kubernetes.io~iscsi/iscsi0 type ext4 (rw,relatime,stripe=4)
<span class="Comment"># /etc/ctl.conf</span>
auth-group ag0 {
chap postgresql <span class="Special">*</span>***********
}
portal-group pg0 {
discovery-auth-group no-authentication
<span class="Type">listen</span> <span class="Special">192.168.0.9</span>
}
target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 {
auth-group ag0
portal-group pg0
lun <span class="Constant">0</span> {
path /dev/zvol/zpool2/iscsi/t0-lun0
blocksize 4096
size 100G
}
lun <span class="Constant">1</span> {
path /dev/zvol/zpool2/iscsi/t0-lun1
blocksize 4096
size 100G
}
}
</pre>
</body>
</html>
<!-- vim: set foldmethod=manual : -->
Volume Claims
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>~/www/eradman.com/Untitled.xhtml</title> <meta name="Generator" content="Vim/9.2" /> <meta name="plugin-version" content="vim9.2_v1" /> <meta name="syntax" content="nginx" /> <meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" /> <meta name="colorscheme" content="default" /> <style type="text/css"> pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; } body { font-family: monospace; color: #000000; background-color: #ffffff; } * { font-size: 1em; } a { color: inherit; } .Comment { color: #0000c0; } .Constant { color: #c00000; } .Special { color: #c000c0; } .Type { color: #008000; } </style> </head> <body> <pre> --- 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 claimRef: namespace: default name: pg2-pvc storageClassName: fs-vdev <span class="Comment"># /etc/ctl.conf</span> auth-group ag0 { chap postgresql <span class="Special">*</span>*********** } portal-group pg0 { discovery-auth-group no-authentication <span class="Type">listen</span> <span class="Special">192.168.0.9</span> } target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 { auth-group ag0 portal-group pg0 lun <span class="Constant">0</span> { path /dev/zvol/zpool2/iscsi/t0-lun0 blocksize 4096 size 100G } lun <span class="Constant">1</span> { path /dev/zvol/zpool2/iscsi/t0-lun1 blocksize 4096 size 100G } } </pre> </body> </html> <!-- vim: set foldmethod=manual : -->
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>~/www/eradman.com/Untitled.xhtml</title> <meta name="Generator" content="Vim/9.2" /> <meta name="plugin-version" content="vim9.2_v1" /> <meta name="syntax" content="nginx" /> <meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" /> <meta name="colorscheme" content="default" /> <style type="text/css"> pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; } body { font-family: monospace; color: #000000; background-color: #ffffff; } * { font-size: 1em; } a { color: inherit; } .Comment { color: #0000c0; } .Constant { color: #c00000; } .Special { color: #c000c0; } .Type { color: #008000; } </style> </head> <body> <pre> --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: pg2-pvc spec: accessModes: - ReadWriteOnce resources: requests: storage: 100Gi storageClassName: fs-vdev <span class="Comment"># /etc/ctl.conf</span> auth-group ag0 { chap postgresql <span class="Special">*</span>*********** } portal-group pg0 { discovery-auth-group no-authentication <span class="Type">listen</span> <span class="Special">192.168.0.9</span> } target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 { auth-group ag0 portal-group pg0 lun <span class="Constant">0</span> { path /dev/zvol/zpool2/iscsi/t0-lun0 blocksize 4096 size 100G } lun <span class="Constant">1</span> { path /dev/zvol/zpool2/iscsi/t0-lun1 blocksize 4096 size 100G } } </pre> </body> </html> <!-- vim: set foldmethod=manual : -->
If
claimRef
is not specified, a
PersistentVolumeClaim
will be assigned to a
PersistantVolume
dynamically. This may appear to be correct, but will likely result in a
confused state in the future.
Authentication is provided using a
Secret
provider
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>~/www/eradman.com/Untitled.xhtml</title> <meta name="Generator" content="Vim/9.2" /> <meta name="plugin-version" content="vim9.2_v1" /> <meta name="syntax" content="nginx" /> <meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" /> <meta name="colorscheme" content="default" /> <style type="text/css"> pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; } body { font-family: monospace; color: #000000; background-color: #ffffff; } * { font-size: 1em; } a { color: inherit; } .Comment { color: #0000c0; } .Constant { color: #c00000; } .Special { color: #c000c0; } .Type { color: #008000; } </style> </head> <body> <pre> --- apiVersion: v1 kind: Secret metadata: name: postgresql-data type: "kubernetes.io/iscsi-chap" stringData: node.session.auth.username: postgresql node.session.auth.password: ************ <span class="Comment"># /etc/ctl.conf</span> auth-group ag0 { chap postgresql <span class="Special">*</span>*********** } portal-group pg0 { discovery-auth-group no-authentication <span class="Type">listen</span> <span class="Special">192.168.0.9</span> } target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 { auth-group ag0 portal-group pg0 lun <span class="Constant">0</span> { path /dev/zvol/zpool2/iscsi/t0-lun0 blocksize 4096 size 100G } lun <span class="Constant">1</span> { path /dev/zvol/zpool2/iscsi/t0-lun1 blocksize 4096 size 100G } } </pre> </body> </html> <!-- vim: set foldmethod=manual : -->
Example Application
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>~/www/eradman.com/Untitled.xhtml</title> <meta name="Generator" content="Vim/9.2" /> <meta name="plugin-version" content="vim9.2_v1" /> <meta name="syntax" content="nginx" /> <meta name="settings" content="no_progress,use_xhtml,use_css,no_foldcolumn,expand_tabs,pre_wrap,prevent_copy=,use_input_for_pc=none" /> <meta name="colorscheme" content="default" /> <style type="text/css"> pre { white-space: pre-wrap; font-family: monospace; color: #000000; background-color: #ffffff; } body { font-family: monospace; color: #000000; background-color: #ffffff; } * { font-size: 1em; } a { color: inherit; } .Comment { color: #0000c0; } .Constant { color: #c00000; } .Special { color: #c000c0; } .Type { color: #008000; } </style> </head> <body> <pre> --- apiVersion: v1 kind: Service metadata: name: pg2 spec: clusterIP: None ports: - name: psql protocol: TCP port: 5432 targetPort: 8123 selector: app: pg2 --- apiVersion: apps/v1 kind: Deployment metadata: name: pg2 spec: replicas: 1 selector: matchLabels: app: pg2 template: metadata: labels: app: pg2 spec: containers: - name: pg2 image: docker.io/postgres:18-alpine ports: - containerPort: 5432 volumeMounts: - name: pg2-data mountPath: "/var/lib/postgresql" volumes: - name: pg2-data persistentVolumeClaim: claimName: pg2-pvc <span class="Comment"># /etc/ctl.conf</span> auth-group ag0 { chap postgresql <span class="Special">*</span>*********** } portal-group pg0 { discovery-auth-group no-authentication <span class="Type">listen</span> <span class="Special">192.168.0.9</span> } target iqn.<span class="Constant">2026</span>-<span class="Constant">04</span>.lan.fs1:target0 { auth-group ag0 portal-group pg0 lun <span class="Constant">0</span> { path /dev/zvol/zpool2/iscsi/t0-lun0 blocksize 4096 size 100G } lun <span class="Constant">1</span> { path /dev/zvol/zpool2/iscsi/t0-lun1 blocksize 4096 size 100G } } </pre> </body> </html> <!-- vim: set foldmethod=manual : -->