Access "outer space"
Volumes are the preferred mechanism for persisting data generated by and used by Docker containers.
While bind mounts are dependent on the directory structure and OS of the host machine, volumes are completely managed by Docker.
Volumes have several advantages over bind mounts:
-
Volumes are easier to back up or migrate than bind mounts.
-
You can manage volumes using the Docker CLI commands or the Docker API.
-
Volumes work on both Linux and Windows containers.
-
Volumes can be more safely shared among multiple containers.
-
Volume drivers let you store volumes on remote hosts or cloud providers, to encrypt the contents of volumes, or to add other functionality.
-
New volumes can have their content pre-populated by container.
-
Volumes on the Docker Desktop have much higher performance than bind mounts from Mac and Windows hosts.
In addition, volumes are often a better choice than persisting data in a container’s writable layer, because a volume does not increase the size of the containers using it, and the volume’s contents exist outside the lifecycle of a given container.
If your container generates non-persistent state data, consider using a tmpfs mount to avoid storing the data anywhere permanently, and to increase the container’s performance by avoiding writing into the container’s writable layer.
Volumes use rprivate bind propagation
, and bind propagation
is not configurable for volumes.
In general, --mount is more explicit and verbose. The biggest difference is that the -v syntax
combines all the options together in one field, while the --mount syntax
separates them.
Here is a comparison of the syntax for each flag.
If you need to specify a volume driver options
, you must use --mount
.
-
-v or --volume: Consists of three fields, separated by colon characters (:). The fields must be in the correct order, and the meaning of each field is not immediately obvious.
- The
first field
is thename
of the volume, in the case ofnamed volumes
, and is unique on a given host machine. Thefirst field
isomitted
foranonymous volumes
, . - The
second field
is thepath
where the file or directory are mounted in the container. - The
third field
is optional, and is a comma-separated list of options, such as ro. These options are discussed below.
- The
-
--mount: Consists of multiple key-value pairs, separated by commas and each consisting of a = tuple. The --mount syntax is more verbose than -v or --volume, but the order of the keys is not significant, and the value of the flag is easier to understand.
- The
type
of the mount, which can bebind
,volume
, ortmpfs
. This topic discusses volumes, so the type is always volume. - The
source
of the mount. Fornamed volumes
, this is the name of the volume. Foranonymous volumes
, this field is omitted. May be specified assource
orsrc
. - The
destination
takes as its value the path where the file or directory is mounted in the container. May be specified asdestination
,dst
, ortarget
. - The
readonly
option, if present, causes the bind mount to be mounted into the container as read-only. - The
volume-opt
option, which can be specified more than once, takes a key-value pair consisting of the option name and its value.
- The
Escape values from outer CSV parser
If your volume driver accepts a comma-separated list as an option, you must escape the value from the outer CSV parser. To escape avolume-opt
, surround it with double quotes"
and surround the entire mount parameter with single quotes'
.
For example, the local
driver accepts mount options as a comma-separated list in the o
parameter. This example shows the correct way to escape the list.
$ docker service create \
--mount 'type=volume,src=<VOLUME-NAME>,dst=<CONTAINER-PATH>,volume-driver=local,volume-opt=type=nfs,volume-opt=device=<nfs-server>:<nfs-path>,"volume-opt=o=addr=<nfs-address>,vers=4,soft,timeo=180,bg,tcp,rw"'
--name myservice \
<IMAGE>
The examples
below show both the --mount
and -v
syntax where possible, and --mount is presented first.
As opposed to bind mounts
, all options for volumes
are available for both --mount
and -v
flags.
When using volumes with services
, only --mount
is supported.
Unlike bind mount
,
you can create and manage volumes
outside the scope of any container.
$
docker volume create kate.vol
$
docker volume ls
$
docker volume inspect kate.vol
[
{
"CreatedAt": "2020-12-23T17:11:40+01:00",
"Driver": "local",
"Labels": {},
"Mountpoint": "/var/lib/docker/volumes/kate.vol/_data",
"Name": "kate.vol",
"Options": {},
"Scope": "local"
}
]
$
docker volume rm kate.vol
If you start a container with a volume
that does not yet exist,
Docker creates the volume for you.
The following example
mounts the volume kate.vol
into /app/
in the container.
The -v
and --mount
examples below
produce the same result.
You can’t run them both
unless you remove the devtest
container
and the kate.vol
volume
after running the first one.
$ docker run -d \
--name devtest \
--mount source=kate.vol,target=/app \
nginx:latest
$ docker run -d \
--name devtest \
-v kate.vol:/app \
nginx:latest
Use docker inspect devtest
to verify that the volume was created
and mounted correctly.
Look for the Mounts section:
"Mounts": [
{
"Type": "volume",
"Name": "kate.vol",
"Source": "/var/lib/docker/volumes/kate.>vol/_data",
"Destination": "/app",
"Driver": "local",
"Mode": "z",
"RW": true,
"Propagation": ""
}
],
This shows that the mount is a volume
,
it shows the correct source
and destination
,
and that the mount is read-write
.
Stop the container and remove the volume.
Note that volume removal is a separate step.
$ docker container stop devtest
$ docker container rm devtest
$ docker volume rm kate.vol
A single docker compose service with a volume looks like this:
version: "3.9"
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
On the first invocation of docker-compose up
the volume will be created.
The same volume will be reused on further invocations.
A volume may be created directly outside of compose
with docker volume create
and then referenced inside
docker-compose.yml
as follows:
version: "3.9"
services:
frontend:
image: node:lts
volumes:
- myapp:/home/node/app
volumes:
myapp:
external: true
For more information about using volumes with compose
refer to the compose reference.
When you start a service and define a volume,
each service container
uses its own local volume
.
None of the containers can share this data
if you use the local volume driver
,
but some volume drivers
do support shared storage
.
Docker for AWS
and Docker for Azure
both support persistent storage
using the Cloudstor plug-in.
The following example
starts an nginx service with four replicas,
each of which uses a local volume
called myvol2:
$ docker service create -d \
--replicas=4 \
--name devtest-service \
--mount source=myvol2,target=/app \
nginx:latest
Use docker service ps devtest-service
to verify that the service is running:
$ docker service ps devtest-service
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS 4d7oz1j85wwn devtest-service.1 nginx:latest moby Running Running 14 seconds ago
Remove the service, which stops all its tasks:
$ docker service rm devtest-service
Removing the service
does not remove any volumes created by the service.
Volume removal is a separate step.
The docker service create
command
does not support the -v
or --volume
flag.
When mounting a volume into a service’s containers,
you must use the --mount
flag.
If you start a container,
which creates a new volume, as above,
and the container has files or directories
in the directory to be mounted,
such as /app/ above,
the directory’s contents are copied into the volume.
The container then mounts and uses the volume,
and other containers, which use the volume
also have access to the pre-populated content.
To illustrate this,
this example starts an nginx container
and populates the new volume nginx-vol
with the contents of the container’s
/usr/share/nginx/html directory
,
which is where Nginx stores its default HTML content.
The --mount
and -v
examples have the same end result.
$ docker run -dp 8080:80 \
--name=nginxtest \
--mount source=nginx-vol,destination=/usr/share/nginx/html \
nginx:latest
After running either of these examples,
run the following commands to clean up the containers and volumes.
$ docker run -dp 8080:80 \
--name=nginxtest \
-v nginx-vol:/usr/share/nginx/html \
nginx:latest
Note:
Volume removal is a separate step.
After running either of these examples,
run the following commands
to clean up the containers and volumes.
Note:
Volume removal is a separate step.
$ docker container stop nginxtest
$ docker container rm nginxtest
$ docker volume rm nginx-vol
For some development applications,
the container needs to write into the bind mount
so that changes are propagated back to the Docker host.
At other times, the container only needs read access to the data
.
Remember that multiple containers
can mount the same volume,
and it can be mounted read-write
for some of them
and read-only
for others, at the same time.
This example
modifies the example above,
but mounts the directory as a read-only
volume,
by adding ro
to the empty by default list of options,
after the mount point within the container.
If multiple options are present,
separate them by commas.
The --mount
and -v
examples have the same result.
Name the container nginx.test
: --name parameter
Mount an external volume read-only
holding the data of /usr/share/nginx/html.
Run the nginx:latest
image as a container.
$ docker run -dp 8080:80 \
--name=nginx.test \
--mount source=nginx-vol,destination=/usr/share/nginx/html,readonly \
nginx:latest
$ docker run -dp 8080:80 \
--name=nginx.test \
-v nginx.vol:/usr/share/nginx/html:ro \
nginx:latest
Use docker inspect nginx.test
to verify that the read-only
mount was created correctly.
Look for the Mounts section:
"Mounts": [
{
"Type": "volume",
"Name": "nginx.vol",
"Source": "/var/lib/docker/volumes/nginx.vol/_data",
"Destination": "/usr/share/nginx/html",
"Driver": "local",
"Mode": "ro",
"RW": false,
"Propagation": ""
}
],
Stop and remove the container,
and remove the volume.
Note:
Volume removal is a separate step.
$ docker container stop nginx.test
$ docker container rm nginx.test
$ docker volume rm nginx.vol
When building fault-tolerant applications
,
you might need to configure multiple replicas
of the same service to have access to the same files.
There are several ways to achieve this
when developing your applications.
One is to add logic to your application
to store files on a cloud object storage system
such as Amazon S3
.
Another is to create volumes with a driver
that supports writing files to an external storage system
such as NFS
or Amazon S3
.
Volume drivers allow you
to abstract the underlying storage system
from the application logic.
For example
,
if your services use a volume with an NFS driver
,
you can update the services to use a different driver,
as an example to store data in the cloud,
without changing the application logic.
When you create a volume using docker volume create
,
or when you start a container,
which uses a not-yet-created volume,
you can specify a volume driver.
The following examples
use the vieux
/ sshfs
volume driver,
first when creating a stand-alone volume,
and then when starting a container,
which creates a new volume.
This example assumes
that you have two nodes,
the first of which is a Docker host
and can connect to the second using SSH.
On the Docker host, install the vieux
/ sshfs
plug-in:
$ docker plugin install --grant-all-permissions vieux/sshfs
This example specifies an SSH password,
but if the two hosts have shared keys configured,
you can omit the password.
Each volume driver may have zero or more configurable options,
each of which is specified using an -o flag.
$ docker volume create --driver vieux/sshfs \
-o sshcmd=test@node2:/home/test \
-o password=testpassword \
sshvolume
sshfs ewan@Acer-Old:/media/ewan/ScanDisk/RED/EE/development /mnt/dev-acer-old