iSCSI provides block-level shared storage over standard TCP/IP networks, making it a solid choice for KVM environments that need SAN-like performance without Fibre Channel hardware. Unlike NFS, which shares files, iSCSI exports raw block devices (LUNs) that the KVM host accesses as local disks. This guide covers setting up an iSCSI target using targetcli, configuring the initiator on the KVM host, discovering and logging into targets, defining an iSCSI pool in libvirt, and attaching LUNs to virtual machines.
How iSCSI Works with KVM
In an iSCSI setup, the storage server runs as the “target” and the KVM host connects as the “initiator.” The target exports block devices called LUNs (Logical Unit Numbers) over the network. The KVM host discovers these LUNs, logs in, and sees them as local SCSI disks. You can then either pass them through to VMs directly or manage them through a libvirt storage pool.
Prerequisites
- A storage server for the iSCSI target (RHEL 10 or Ubuntu 24.04)
- A KVM host running RHEL 10 or Ubuntu 24.04
- A dedicated disk or LVM volume on the storage server for iSCSI LUNs
- Network connectivity between the servers (ideally a dedicated storage network)
- Root or sudo access on both machines
Part 1 – Configure the iSCSI Target
Step 1 – Install targetcli
Install targetcli on the storage server. This is the standard Linux tool for managing iSCSI targets.
# Ubuntu 24.04
sudo apt update
sudo apt install -y targetcli-fb
# RHEL 10
sudo dnf install -y targetcli
Enable and start the target service.
sudo systemctl enable --now target
Verify it is running.
systemctl status target
Step 2 – Create a Backstorage Device
Launch targetcli and create a block-based backstorage. This example uses a dedicated disk /dev/sdb. You can also use an LVM logical volume or a file-based backstorage.
sudo targetcli
Inside the targetcli shell, run the following commands.
/> cd /backstores/block
/backstores/block> create name=kvm_lun0 dev=/dev/sdb
/backstores/block> cd /
For a file-based backstorage (useful for testing), use this instead.
/backstores/fileio> create name=kvm_lun0 file_or_dev=/srv/iscsi/lun0.img size=50G
Step 3 – Create the iSCSI Target
Create an iSCSI target with an IQN (iSCSI Qualified Name). The naming convention is iqn.YYYY-MM.reversed.domain:identifier.
/> cd /iscsi
/iscsi> create iqn.2024-01.com.example:kvm-storage
Step 4 – Configure the LUN and ACL
Map the backstorage to a LUN within the target portal group (TPG).
/iscsi> cd iqn.2024-01.com.example:kvm-storage/tpg1/luns
/iscsi/.../luns> create /backstores/block/kvm_lun0
Create an ACL entry that allows the KVM host to connect. You need the IQN of the initiator (the KVM host). Check it on the KVM host first.
# Run this on the KVM host to get its initiator name
cat /etc/iscsi/initiatorname.iscsi
Back in targetcli on the storage server, create the ACL.
/iscsi/.../luns> cd ../acls
/iscsi/.../acls> create iqn.2024-01.com.example:kvm-host1
Optionally set CHAP authentication for additional security.
/iscsi/.../acls/iqn.2024-01.com.example:kvm-host1> set auth userid=kvmuser
/iscsi/.../acls/iqn.2024-01.com.example:kvm-host1> set auth password=SecurePass123
Save and exit.
/> saveconfig
/> exit
Step 5 – Configure the Firewall on the Target
Open port 3260 for iSCSI traffic.
# RHEL 10
sudo firewall-cmd --permanent --add-port=3260/tcp
sudo firewall-cmd --reload
# Ubuntu 24.04
sudo ufw allow 3260/tcp
Part 2 – Configure the iSCSI Initiator on the KVM Host
Step 6 – Install the iSCSI Initiator
# Ubuntu 24.04
sudo apt install -y open-iscsi
# RHEL 10
sudo dnf install -y iscsi-initiator-utils
Set the initiator name to match what you configured in the ACL on the target. Edit /etc/iscsi/initiatorname.iscsi.
echo "InitiatorName=iqn.2024-01.com.example:kvm-host1" | sudo tee /etc/iscsi/initiatorname.iscsi
If you configured CHAP authentication, add the credentials to /etc/iscsi/iscsid.conf.
sudo sed -i 's/^#node.session.auth.authmethod.*/node.session.auth.authmethod = CHAP/' /etc/iscsi/iscsid.conf
sudo sed -i 's/^#node.session.auth.username.*/node.session.auth.username = kvmuser/' /etc/iscsi/iscsid.conf
sudo sed -i 's/^#node.session.auth.password.*/node.session.auth.password = SecurePass123/' /etc/iscsi/iscsid.conf
Enable and restart the iSCSI service.
sudo systemctl enable --now iscsid
sudo systemctl restart iscsid
Step 7 – Discover and Log Into the Target
Discover available targets on the storage server. Replace 192.168.1.50 with your storage server IP.
sudo iscsiadm -m discovery -t sendtargets -p 192.168.1.50
Expected output:
192.168.1.50:3260,1 iqn.2024-01.com.example:kvm-storage
Log into the target.
sudo iscsiadm -m node -T iqn.2024-01.com.example:kvm-storage -p 192.168.1.50 --login
Verify the session is established.
sudo iscsiadm -m session -o show
Check that the LUN appears as a local disk.
lsblk
sudo fdisk -l | grep -i iscsi
You should see a new disk device, typically /dev/sdc or similar.
Set the login to persist across reboots.
sudo iscsiadm -m node -T iqn.2024-01.com.example:kvm-storage -p 192.168.1.50 --op update -n node.startup -v automatic
Step 8 – Define the iSCSI Storage Pool in libvirt
Define an iSCSI-type storage pool in libvirt that points to the target.
virsh pool-define-as iscsi-pool iscsi \
--source-host 192.168.1.50 \
--source-dev iqn.2024-01.com.example:kvm-storage \
--target /dev/disk/by-path
Start and auto-start the pool.
virsh pool-start iscsi-pool
virsh pool-autostart iscsi-pool
Verify the pool and list available volumes (LUNs).
virsh pool-list --all
virsh vol-list iscsi-pool
Step 9 – Attach iSCSI LUNs to Virtual Machines
You can attach an iSCSI LUN to a VM in two ways.
Option 1 – Use the libvirt pool volume path. Get the volume path first.
virsh vol-list iscsi-pool --details
Then use it in virt-install.
virt-install \
--name iscsi-vm \
--ram 4096 \
--vcpus 2 \
--disk vol=iscsi-pool/unit:0:0:0,bus=virtio \
--os-variant rhel10 \
--network bridge=br0 \
--cdrom /var/lib/libvirt/images/rhel-10.iso
Option 2 – Use the device path directly for an existing VM.
virsh attach-disk myvm /dev/disk/by-path/ip-192.168.1.50:3260-iscsi-iqn.2024-01.com.example:kvm-storage-lun-0 vdb \
--driver qemu --subdriver raw --persistent
Verify the attachment.
virsh domblklist myvm
Monitoring and Troubleshooting
Check active iSCSI sessions.
sudo iscsiadm -m session -P 3
If a session drops, try re-logging in.
sudo iscsiadm -m node -T iqn.2024-01.com.example:kvm-storage -p 192.168.1.50 --login
Check target-side sessions from the storage server.
sudo targetcli
/> ls /iscsi/iqn.2024-01.com.example:kvm-storage/tpg1/acls
For performance issues, check network throughput between the hosts and consider jumbo frames (MTU 9000) on the dedicated storage network.
Summary
iSCSI gives KVM hosts block-level access to remote storage over standard Ethernet, bridging the gap between simple NFS shares and expensive Fibre Channel SANs. The setup involves two sides – configuring the target with targetcli to export LUNs, and configuring the initiator on the KVM host to discover and log into those targets. Once connected, the LUNs appear as local block devices that you can manage through libvirt storage pools or attach directly to VMs. For production use, dedicate a network interface to iSCSI traffic and enable CHAP authentication to keep the storage path secure and performant.