Docker 28 🐳 Volume Drivers and Storage Plugins: Local, NFS, and Cloud-Native Storage
A volume driver is the mechanism that determines where a volume’s data actually lives. The default driver stores it on the local host filesystem. Other drivers store it on an NFS server, a cloud block device, or a distributed storage cluster. The driver is specified when the volume is created, and it determines the volume’s behavior: whether it can be shared across hosts, what its performance characteristics are, and how it integrates with the rest of the infrastructure.
This chapter covers the volume driver system in full. You will learn the built-in local driver and its options, the NFS and CIFS configurations that use it, the third-party plugins for cloud and distributed storage, and the trade-offs that determine which driver fits which workload.
Key point: The local driver is built into Docker and stores volumes on the host filesystem. It can be configured with driver options to mount NFS, CIFS, or bind-mount a specific host path. Third-party volume plugins, installed with docker plugin install, extend Docker to cloud block storage (AWS EBS, Azure Disk) and distributed filesystems (Ceph, GlusterFS, Portworx). The driver is specified at volume creation with --driver, and the options are passed with --opt.
Why volume drivers exist
The single-host problem. The default local driver stores data on the Docker host. If the host fails, the data is lost. If a container is rescheduled to a different host, the volume does not follow. For stateful workloads that need to survive host failure or move between hosts, a storage backend that exists outside the host is required. A volume driver provides that backend.
The shared-storage problem. Multiple containers on multiple hosts may need to access the same data. A local volume on one host is not visible to another host. An NFS volume, mounted from a shared server, is visible to every host that mounts it. The driver determines whether the volume is local or shared.
The cloud-integration problem. A Docker host running on AWS has access to EBS volumes. A Docker host on Azure has access to Azure Disks. A Docker host on Google Cloud has access to Persistent Disks. A volume driver plugin integrates Docker with the cloud provider’s block storage API, so a docker volume create provisions an EBS volume, attaches it to the instance, and mounts it into the container.
The performance problem. Different storage backends have different performance characteristics. A local SSD is fast but not shared. An NFS server over gigabit Ethernet has higher latency but is shareable. A cloud block device’s performance depends on the volume type and the instance’s network. The driver choice is a performance choice.
The portability problem. A volume that is local to a host cannot be moved to another host. A volume backed by a shared NFS server, or by a cloud block device that can be detached and reattached, can move. The driver determines whether the volume can “float” with the container when the container is rescheduled.
a. The local driver and its options
The local driver is the default. With no options, it stores the volume’s data under /var/lib/docker/volumes/<name>/_data on the host . This is the simplest form of persistence and works for single-host deployments.
docker volume create mydata
docker volume inspect mydata
# "Mountpoint": "/var/lib/docker/volumes/mydata/_data"
The local driver accepts driver options that change what it mounts. The type, o, and device options are passed through to the underlying mount command . This is how the local driver is used to mount NFS, CIFS, or a bind-mounted host path.
NFS. The local driver can mount an NFS share as a volume. The type is nfs, the device is the NFS server and export path, and o contains the mount options.
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.10,rw,nfsvers=4 \
--opt device=:/exports/data \
nfs_data
The volume nfs_data is backed by the NFS export at 192.168.1.10:/exports/data. Any container that mounts nfs_data sees the NFS share . This works without any third-party plugin because the local driver is passing the options to the kernel’s NFS mount.
CIFS/SMB. The same pattern works for Windows file shares.
docker volume create --driver local \
--opt type=cifs \
--opt o=addr=server,username=user,password=pass,vers=3.0 \
--opt device=//server/share \
cifs_data
Bind-mount-backed volume. A named volume that maps to a specific host path uses the local driver with type=none and o=bind.
docker volume create --driver local \
--opt type=none \
--opt o=bind \
--opt device=/srv/app-data \
app_data
The volume app_data has a stable name but maps to /srv/app-data on the host. This is useful when a Compose file needs a named volume that points to a known host directory .
The local driver’s NFS support is the most common way to share data between Docker hosts without installing a plugin. It performs a DNS lookup on the NFS hostname, which the standard mount command does not . The main pitfall is NFS’s root_squash setting, which maps root on the client to nobody on the server and can cause permission errors when a container runs as root .
b. Cloud-native storage plugins
For cloud block storage and distributed filesystems, a third-party volume plugin is required. The plugin is installed with docker plugin install, and it registers itself as a volume driver. Once installed, volumes are created with --driver <plugin-name>.
AWS EBS. The REX-Ray EBS plugin provides access to Amazon Elastic Block Store. The plugin is installed with the AWS credentials and region.
docker plugin install --grant-all-permissions rexray/ebs:latest \
EBS_ACCESSKEY=AKIAXXXXXXXX \
EBS_SECRETKEY=xxxxxxxxxx \
EBS_REGION=us-east-1
A volume is created with the driver and options for size and type.
docker volume create -d rexray/ebs --opt size=50 --opt volumetype=gp3 mydata
The plugin provisions a 50 GB gp3 EBS volume, attaches it to the instance, and mounts it. The volume can be detached and reattached to a different instance, which is what allows it to follow a container when the container is rescheduled .
Azure Disk. The REX-Ray Azure plugin is configured with the Azure credentials and subscription details.
docker plugin install --grant-all-permissions rexray/azureud:latest \
AZUREUD_CLIENTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
AZUREUD_CLIENTSECRET=xxxxxxxxxx \
AZUREUD_RESOURCEGROUP=my-resource-group \
AZUREUD_STORAGEACCESSKEY=xxxxxxxxxx \
AZUREUD_STORAGEACCOUNT=mystorageaccount \
AZUREUD_SUBSCRIPTIONID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx \
AZUREUD_TENANTID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
NetApp Trident. Trident is a plugin for NetApp’s ONTAP and SolidFire storage platforms. It supports volume creation, cloning, and snapshot-based provisioning . The plugin is installed with a configuration file that points to the NetApp management interface.
docker plugin install --grant-all-permissions --alias netapp \
netapp/trident-plugin:<version> config=myConfigFile.json
Volumes are created with the driver name.
docker volume create -d netapp --name firstVolume
docker volume create -d netapp --name my_vol --opt size=20G
Trident supports cloning from existing volumes and from snapshots, using the from and fromSnapshot options .
Distributed filesystems. Plugins exist for Ceph, GlusterFS, Portworx, and other distributed storage systems. The GlusterFS plugin is installed with docker plugin install --alias glusterfs --grant-all-permissions trajano/glusterfs-volume-plugin:v2.0.3 . Portworx provides a container-native storage layer that replicates data across the cluster, so a volume can be mounted on any node . These plugins are used when the storage must be highly available and accessible from multiple hosts.
c. Choosing a driver
The choice of driver depends on three questions: where the data should live, whether it must be shared, and how much operational complexity is acceptable.
| Driver | Data Location | Shared Across Hosts | Plugin Required |
|---|---|---|---|
local | Host filesystem | No | No |
local + NFS | NFS server | Yes | No |
local + CIFS | SMB server | Yes | No |
| REX-Ray EBS | AWS EBS | Yes (detach/attach) | Yes |
| REX-Ray Azure | Azure Disk | Yes (detach/attach) | Yes |
| NetApp Trident | NetApp ONTAP | Yes | Yes |
| Portworx | Cluster-replicated | Yes | Yes |
| GlusterFS | Gluster cluster | Yes | Yes |
The local driver with no options is for single-host deployments where the data does not need to move. The local driver with NFS options is for multi-host deployments where the data must be shared and an NFS server is available. The cloud plugins are for cloud deployments where the block storage is provided by the cloud provider. The distributed filesystem plugins are for on-premises or hybrid deployments where high availability and multi-host access are required.
A performance consideration: local storage is the fastest but least portable. NFS has higher latency but is shareable. Cloud block storage performance depends on the volume type and the instance’s network. Distributed filesystems trade some performance for replication and availability .
A consistency consideration: block storage (EBS, Azure Disk) is typically limited to a single node at a time. It can be detached and reattached, but it cannot be mounted on two nodes simultaneously. File storage (NFS, EFS, GlusterFS) can be mounted on multiple nodes, but the application must handle concurrent access correctly .
A complexity consideration: the local driver with NFS options requires no plugin installation, only an NFS server. Cloud plugins require credentials and region configuration. Distributed filesystem plugins require the storage cluster to be running. The simplest option that meets the requirement is usually the right one.
Complete Example Session
# ============================================
# PART 1: LOCAL DRIVER (DEFAULT)
# ============================================
docker volume create mydata
docker volume inspect mydata
# Mountpoint: /var/lib/docker/volumes/mydata/_data
# ============================================
# PART 2: LOCAL DRIVER WITH NFS
# ============================================
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=192.168.1.10,rw,nfsvers=4 \
--opt device=:/exports/data \
nfs_data
# ============================================
# PART 3: USE NFS VOLUME IN A CONTAINER
# ============================================
docker run -d --name app -v nfs_data:/data alpine sleep 3600
docker exec app ls /data
# ============================================
# PART 4: LOCAL DRIVER WITH BIND
# ============================================
docker volume create --driver local \
--opt type=none \
--opt o=bind \
--opt device=/srv/app-data \
app_data
# ============================================
# PART 5: INSTALL AWS EBS PLUGIN
# ============================================
docker plugin install --grant-all-permissions rexray/ebs:latest \
EBS_ACCESSKEY=AKIAXXXXXXXX \
EBS_SECRETKEY=xxxxxxxxxx \
EBS_REGION=us-east-1
docker plugin ls
# ============================================
# PART 6: CREATE EBS VOLUME
# ============================================
docker volume create -d rexray/ebs \
--opt size=50 \
--opt volumetype=gp3 \
ebs_data
# ============================================
# PART 7: INSTALL NETAPP TRIDENT
# ============================================
docker plugin install --grant-all-permissions --alias netapp \
netapp/trident-plugin:25.10 config=myConfigFile.json
# ============================================
# PART 8: CREATE TRIDENT VOLUME
# ============================================
docker volume create -d netapp --name firstVolume
docker volume create -d netapp --name my_vol --opt size=20G
# ============================================
# PART 9: CLONE A TRIDENT VOLUME
# ============================================
docker volume create -d netapp --name clonedVolume -o from=firstVolume
# ============================================
# PART 10: CLEAN UP
# ============================================
docker volume rm nfs_data app_data ebs_data firstVolume my_vol clonedVolume
docker plugin rm rexray/ebs netapp
The ten parts covered the default local driver, NFS configuration, using an NFS volume, bind-mount configuration, installing the AWS EBS plugin, creating an EBS volume, installing NetApp Trident, creating a Trident volume, cloning a Trident volume, and cleanup.
Quick Reference
Built-in Drivers
| Driver | Storage Location | Options |
|---|---|---|
local | Host filesystem | None (default) |
local + NFS | NFS server | type=nfs, o=addr=...,rw, device=:/path |
local + CIFS | SMB server | type=cifs, o=addr=...,username=..., device=//server/share |
local + bind | Host path | type=none, o=bind, device=/host/path |
Third-Party Plugins
| Plugin | Backend | Install Command |
|---|---|---|
| REX-Ray EBS | AWS EBS | docker plugin install rexray/ebs:latest |
| REX-Ray Azure | Azure Disk | docker plugin install rexray/azureud:latest |
| NetApp Trident | NetApp ONTAP | docker plugin install netapp/trident-plugin |
| GlusterFS | Gluster cluster | docker plugin install trajano/glusterfs-volume-plugin |
| Portworx | Cluster-replicated | Vendor-specific |
Driver Options
| Option | Meaning |
|---|---|
type | Filesystem or mount type (nfs, cifs, none) |
o | Mount options (addr=, rw, nfsvers=4) |
device | Source (:/export, //server/share, /host/path) |
size | Volume size (plugin-specific) |
volumetype | Volume type (plugin-specific) |
Creating a Volume with a Driver
| Command | Purpose |
|---|---|
docker volume create --driver local --opt ... name | Local driver with options |
docker volume create -d rexray/ebs --opt size=50 name | Cloud plugin |
docker volume create -d netapp --name name --opt size=20G | NetApp Trident |
Best Practices
✅ Do This:
# Use the local driver with NFS for multi-host sharing
docker volume create --driver local --opt type=nfs \
--opt o=addr=192.168.1.10,rw,nfsvers=4 \
--opt device=:/exports/data nfs_data # ✅
# Use a bind-backed named volume for stable host paths
docker volume create --driver local --opt type=none \
--opt o=bind --opt device=/srv/app-data app_data # ✅
# Install the plugin before creating the volume
docker plugin install rexray/ebs:latest # ✅
# Verify the plugin is installed
docker plugin ls # ✅
# Check the volume's mountpoint after creation
docker volume inspect mydata # ✅
# Use the local driver when a single host is sufficient
docker volume create mydata # ✅
❌ Don’t Do This:
# Don't use the local driver for shared storage without NFS options
docker volume create shared_data # local to one host # ❌
# Don't use block storage on two nodes simultaneously
docker run -v ebs_data:/data node1
docker run -v ebs_data:/data node2 # cannot both mount # ⚠️
# Don't forget the plugin's credentials
docker plugin install rexray/ebs:latest # missing EBS_ACCESSKEY # ❌
# Don't use a cloud plugin outside its cloud
docker volume create -d rexray/ebs ... # on-prem host # ❌
# Don't ignore NFS root_squash
# Container running as root may fail to write # ⚠️
# Don't expect local volumes to move between hosts
docker volume create local_data # stays on this host # ❌
# Don't mix driver options between drivers
docker volume create -d netapp --opt size=20G --opt type=nfs # ⚠️
Common Pitfalls
| Pitfall | Why It Happens | Fix |
|---|---|---|
| NFS volume not mounting | Server path or address wrong | Check addr, device |
| Permission denied on NFS | root_squash on server | Adjust server exports or container UID |
| Plugin not found | Not installed | docker plugin install |
| Volume not shared | Used local driver without NFS | Use NFS options |
| EBS volume not attaching | Missing credentials or wrong AZ | Check plugin config |
| Driver options ignored | Wrong syntax | Use --opt key=value |
| Volume cannot move | Local driver | Use shared or cloud storage |
Real-World Examples
1. Local Volume
docker volume create app_data
2. NFS Volume
docker volume create --driver local \
--opt type=nfs \
--opt o=addr=10.0.0.10,rw,nfsvers=4 \
--opt device=:/exports/app \
nfs_app
3. CIFS Volume
docker volume create --driver local \
--opt type=cifs \
--opt o=addr=fileserver,username=user,password=pass,vers=3.0 \
--opt device=//fileserver/share \
cifs_share
4. Bind-Backed Volume
docker volume create --driver local \
--opt type=none --opt o=bind --opt device=/srv/data \
host_data
5. AWS EBS Plugin
docker plugin install rexray/ebs:latest \
EBS_ACCESSKEY=xxx EBS_SECRETKEY=xxx EBS_REGION=us-east-1
6. AWS EBS Volume
docker volume create -d rexray/ebs --opt size=50 --opt volumetype=gp3 ebs_db
7. Azure Disk Plugin
docker plugin install rexray/azureud:latest \
AZUREUD_CLIENTID=xxx AZUREUD_CLIENTSECRET=xxx \
AZUREUD_RESOURCEGROUP=my-rg
8. NetApp Trident
docker plugin install --alias netapp netapp/trident-plugin:25.10 config=config.json
docker volume create -d netapp --name firstVolume
9. Trident Clone
docker volume create -d netapp --name clone -o from=firstVolume
10. List Plugins
docker plugin ls
Visual
Volume Driver Architecture
┌─────────────────────────────────────────────────────────────┐
│ DOCKER DAEMON │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Volume Driver Interface │ │
│ └───────────┬─────────────────────┬───────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ local driver │ │ plugin driver │ │
│ │ (built-in) │ │ (installed) │ │
│ │ │ │ │ │
│ │ /var/lib/docker/ │ │ REX-Ray, Trident, │ │
│ │ volumes/ │ │ GlusterFS, etc. │ │
│ └─────────┬───────────┘ └─────────┬───────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────┐ ┌─────────────────────┐ │
│ │ Host filesystem │ │ External storage │ │
│ │ (local disk) │ │ (NFS, EBS, Ceph) │ │
│ └─────────────────────┘ └─────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
Local Driver Options
┌─────────────────────────────────────────────────────────────┐
│ local (no options) │
│ /var/lib/docker/volumes/<name>/_data │
│ Single host. No sharing. │
│ │
│ local + NFS │
│ type=nfs, o=addr=..., device=:/export │
│ Shared across hosts. No plugin. │
│ │
│ local + CIFS │
│ type=cifs, o=addr=...,username=... │
│ Shared across hosts. No plugin. │
│ │
│ local + bind │
│ type=none, o=bind, device=/host/path │
│ Named volume mapped to host path. │
│ │
└─────────────────────────────────────────────────────────────┘
Cloud Plugin Flow
┌─────────────────────────────────────────────────────────────┐
│ 1. Install plugin │
│ docker plugin install rexray/ebs:latest │
│ │
│ 2. Create volume │
│ docker volume create -d rexray/ebs --opt size=50 ebs │
│ │
│ 3. Plugin provisions EBS volume │
│ Creates 50 GB EBS volume in AWS │
│ │
│ 4. Plugin attaches to instance │
│ /dev/xvdf attached to the Docker host │
│ │
│ 5. Plugin mounts into container │
│ Docker bind-mounts the device into the container │
│ │
│ 6. Volume follows the container │
│ Detach from old host, attach to new host │
│ │
└─────────────────────────────────────────────────────────────┘
Driver Decision Tree
┌─────────────────────────────────────────────────────────────┐
│ Does the data need to be shared across hosts? │
│ │ │
│ ├── NO ──▶ local driver (default) │
│ │ │
│ └── YES │
│ │ │
│ ▼ │
│ Is an NFS/CIFS server available? │
│ │ │
│ ├── YES ──▶ local driver with NFS/CIFS options │
│ │ (no plugin required) │
│ │ │
│ └── NO ──▶ Is it a cloud environment? │
│ │ │
│ ├── YES ──▶ Cloud plugin (REX-Ray EBS/Azure) │
│ │ │
│ └── NO ──▶ Distributed plugin (Ceph, etc.) │
│ │
└─────────────────────────────────────────────────────────────┘
Summary
| Item | Value |
|---|---|
| Default driver | local |
| Local storage path | /var/lib/docker/volumes/ |
| NFS options | type=nfs, o=addr=...,rw, device=:/path |
| CIFS options | type=cifs, o=addr=...,username=... |
| Bind options | type=none, o=bind, device=/host/path |
| AWS plugin | rexray/ebs |
| Azure plugin | rexray/azureud |
| NetApp plugin | netapp/trident-plugin |
| Plugin install | docker plugin install |
| Driver flag | --driver |
| Option flag | --opt |
Key takeaways:
- The
localdriver is built into Docker and stores volumes on the host filesystem. With no options, it stores data under/var/lib/docker/volumes/. It is the default and requires no plugin. - The
localdriver can be configured to mount NFS, CIFS, or a bind-mounted host path. Thetype,o, anddeviceoptions are passed to the underlying mount command. This is the simplest way to share volumes across hosts without installing a plugin . - NFS is the most common shared storage for Docker hosts. It requires no plugin, only an NFS server. The
root_squashsetting on the server can cause permission issues when containers run as root . - Cloud block storage requires a third-party plugin. REX-Ray provides plugins for AWS EBS and Azure Disk. The plugin is installed with
docker plugin install, configured with cloud credentials, and used with--driver. - NetApp Trident integrates Docker with NetApp storage. It supports volume creation, cloning, and snapshot-based provisioning. Multiple Trident instances can run on the same host to connect to different storage systems .
- Distributed filesystem plugins (Ceph, GlusterFS, Portworx) provide multi-host volumes. They are used when storage must be highly available and accessible from every node. They trade some performance for replication and availability.
- The driver choice determines whether a volume can move. A local volume stays on the host. An NFS volume is visible to every host that mounts it. A cloud block device can be detached and reattached. The choice depends on where the container might run.
Remember: A volume driver is the mechanism that connects Docker to the storage backend. The local driver is the default and is sufficient for single-host deployments. The local driver with NFS or CIFS options is the simplest way to share data across hosts without a plugin. Cloud and distributed storage require a plugin, which extends Docker to the provider’s block storage or filesystem. The driver is specified at volume creation, and it determines where the data lives, whether it is shared, and whether it can move with the container. Choose the driver that matches the workload’s availability, sharing, and performance requirements, and verify the volume’s mountpoint with docker volume inspect.
Stop using slow, ad-bloated tool sites! 🤮
🔎 Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)
⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free
🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!