A Docker volume plugin that provisions iSCSI LUNs as Docker volumes. Implements the Docker Volume Plugin protocol over a Unix socket, designed to run as a systemd service alongside Docker.
This lets you use iSCSI LUNs from any target (NAS, SAN, software target, etc.) as persistent Docker volumes in single-node and Docker Swarm deployments, with automatic login/logout lifecycle management and ref-counted mounts. The author uses this with a Synology NAS as the iSCSI target.
Status: This project was written for personal use and is currently deployed in a limited capacity where it works well. It was heavily vibe-coded and has not been audited for production hardiness. Before using it in a critical environment, review the code for correctness, error handling, and security — there are known rough edges (see open issues).
- A Docker volume is created with
driver: iscsianddriver_optsspecifying the iSCSI target (portal + IQN). - On first use, the plugin logs in to the iSCSI target, resolves the block device, formats it if unformatted, and mounts it.
- The LUN's filesystem root is the volume mountpoint — multiple Docker volumes pointing at the same portal+IQN share the same mount.
- Reference counting tracks active mounts; the LUN is unmounted and the iSCSI session logged out only when the last consumer releases it.
open-iscsiinstalled and running on the hostiscsi_tcpkernel module loaded (modprobe iscsi_tcp)- Filesystem tools:
blkid,findmnt,mkfs.ext4/mkfs.btrfs/mkfs.xfs - Docker (the plugin registers via
/run/docker/plugins/iscsi.sock)
# Native build
go build -ldflags="-s -w" -o docker-iscsi-plugin .
# Cross-compile for ARM64 (e.g. Raspberry Pi)
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o docker-iscsi-plugin-arm64 .-
Copy the binary to the target host:
scp docker-iscsi-plugin-arm64 <user>@<host>:/usr/local/bin/docker-iscsi-plugin
-
Install the systemd service:
cp systemd/docker-iscsi-plugin.service /etc/systemd/system/ systemctl daemon-reload systemctl enable --now docker-iscsi-plugin -
Verify Docker sees the plugin:
docker volume create --driver iscsi \ -o portal=<TARGET_IP>:3260 \ -o iqn=iqn.2000-01.com.example:<Target>.<LUN> \ -o fs_type=btrfs \ test-vol docker volume ls
volumes:
my-data:
driver: iscsi
driver_opts:
portal: <TARGET_IP>:3260
iqn: iqn.2000-01.com.example:<Target>.<LUN>
fs_type: btrfs
services:
app:
image: myapp:latest
volumes:
- my-data:/data
deploy:
placement:
constraints:
- node.hostname == <SWARM_NODE>| Option | Required | Default | Description |
|---|---|---|---|
portal |
yes | — | iSCSI target portal (host:port) |
iqn |
yes | — | iSCSI target IQN |
fs_type |
no | ext4 |
Filesystem type (ext4, btrfs, xfs) |
Note: iSCSI LUNs are not cluster filesystems. Do not mount the same LUN read-write on multiple nodes simultaneously — this will corrupt the filesystem. Use
placementconstraints to pin workloads to a single node.
Docker daemon
└─ Unix socket: /run/docker/plugins/iscsi.sock
└─ docker-iscsi-plugin (systemd service)
├─ plugin.go — Volume plugin protocol handlers
├─ state.go — Persistent volume/LUN state (JSON)
├─ mount.go — Mount/unmount, filesystem detection
├─ iscsi.go — iscsiadm wrapper (login/logout/discover)
└─ main.go — Entrypoint, reconciliation, signal handling
State is persisted to /var/run/docker-iscsi-plugin/state.json and contains:
- LUNs: Active iSCSI sessions with device path, mount point, and ref count
- Volumes: Docker volume name → LUN mapping (portal, IQN, fs_type)
On startup, the plugin reconciles state against the actual system — removing entries for sessions that no longer exist and resetting ref counts for unmounted LUNs.
# Unit tests
go test -v ./...
# Local integration test (requires iscsiadm, root)
sudo ./test-local.sh
# Swarm stack test
docker stack deploy -c docker-compose-test.yml iscsi-test
docker service logs iscsi-test_test-app -f| File | Purpose |
|---|---|
main.go |
Entrypoint, HTTP server, state reconcile |
plugin.go |
Docker volume plugin protocol handlers |
state.go |
State persistence and locking |
mount.go |
LUN mount/unmount, mkfs, device detection |
iscsi.go |
iscsiadm operations |
plugin_test.go |
Unit tests |
systemd/docker-iscsi-plugin.service |
Systemd service file |
docker-compose-test.yml |
Swarm test stack |
test-local.sh |
Local integration test script |
Dockerfile |
For Docker managed plugin packaging |
plugin-rootfs/config.json |
Docker managed plugin metadata |
Bug reports and pull requests are welcome at github.com/glacial-engineering/docker-iscsi-plugin.
Please open an issue before submitting a large change so we can discuss the approach.
MIT — see LICENSE.