There are actually three types of volumes:
- Host Volume: what you refer to as a mount in a container, the more common term is a bind mount.
- Named Volume: any volume managed by docker which you give a name.
- Anonymous Volume: any volume without a source, docker will create this as a local volume with a long unique id, and it behaves as a named volume.
Volumes have a source and a target. The source identifies the type of volume, so a path (including the leading slash) to a file/directory results in a host volume. If you do not provide a source, you get the anonymous volumes. If you define a volume inside a Dockerfile, you cannot specify a source there, so by default docker will create anonymous volumes unless you direct it otherwise at runtime.
For each type, here are the pros/cons:
- Pro: easy to access the underlying files from the host
- Con: uid/gid permission issues occur when container user's uid does not match the host gid
- Con: data is not initialized
- Pro: easy to create an reuse between different containers/images. If you only give it a name with no other settings, the local driver will default to storing your data in /var/lib/docker/volumes which should only be accessible by root from outside of docker.
- Pro: initializes content to the image contents when it is empty/new and the container is created. This initialization includes file owners and permissions from the image, which can resolve most uid/gid issues.
- Pro: Can connect to anything that a mount command can, including a bind mount or NFS mount, with a local driver. Other drivers let you reference data in even more locations (e.g. cloud providers).
- Con: managing content should be done via a container.
- Pro: requires no planning to use
- Con: data typically goes here to be lost since there is no mapping from the volume back to the container/image that created it. This is the worst way to store volumes in my opinion, and the reason that no one should ever define a volume inside their Dockerfile.
When possible, I use a named volume. The initialization of data and better handling of uid/gid issues trump the convenience of a host volume. If I really need access outside of docker directly to the data, then I try to use a named volume that points to a bind mount instead of the default local driver settings. A simple example of this is:
$ docker volume create --driver local \
--opt type=none \
--opt device=/home/user/test \
--opt o=bind \
For defining my volumes, since you do not want to do this in a Dockerfile, I use a docker-compose.yml and define my volumes in there. If it's deployed with swarm mode, I'll point to a NFS server with a named volume to allow the data to be reached as the containers migrate to different hosts. Otherwise it's a local named volume that can be easily used with docker-compose.