One of the most important properties of containers is their volatility. Any modifications that a container applies to its underlying image will vanish after removing the container. If you want to persist data generated by a container, share data between a container and its host and make the data independent of the container's lifecycle, you have to choose between three mechanisms offered by Docker: volumes, bind mounts and tmpfs mounts.
Usage of Bind Mounts
When using a bind mount, a directory or file on the host system is directly mounted into the desired container. There are a couple of scenarios where this makes sense, developing a PHP application that runs inside a container being one of them.
The following command runs a container based on the official php:7.3-apache
image that uses Apache as web server:
$ docker container run -d \ -p 80:80 \ --name app \ -v $(pwd)/html-data:/var/www/html \ php:7.3-apache
This example uses the --volume
(or short -v
) option to create a bind mount. The PHP source code is located in the
local directory $(pwd)/html-data
, which is mounted into the container at /var/www/html
since this is Apache's
document root. Therefore, the syntax for -v
always is -v <source on the host>:<target in the container>
.
Decoupling the source code from the development container perfectly makes sense here, because re-building the image and
copying the entire project into the image filesystem for every code change would be ridiculous. The bind mount solves
this problem: As soon as a file in the local html-data
directory changes, that change automatically becomes visible
for the container and Apache will always deliver the latest version of the file.
Keep in mind that all paths have to be specified as absolute paths. On Linux, this can be done using $(pwd)/html-data
or even /home/dominik/my-blog/html-data
. On Windows using Docker Desktop, you can use paths like
/c/users/dominik/my-blog/html-data
.
Better Readability Using --mount
Strictly speaking, the abovementioned syntax wasn't complete yet: The -v
option even takes an optional third argument
for mount options. For example, we could mount the source code directory as a read-only mount using
-v $(pwd)/html-data:/var/www/html:ro
.
This syntax may get quite confusing, especially for people new to Docker. For that reason, Docker 17.06 introduced the
--mount
option for standalone containers, providing a self-explanatory syntax and better readability. It simply
consists of multiple key-value pairs.
$ docker container run -d \ -p 80:80 \ --name app \ --mount type=bind,source=$(pwd)/html-data,destination=/var/www/html \ php:7.3-apache
Yes, this option is a bit longer - but its explicit nature dramatically increases the readability and avoids possible
misconceptions. In contrast to -v
, the order of arguments doesn't matter anymore. Verifying that the bind mount has
been created works as follows:
$ docker container inspect -f "{{.Mounts}}" app
More Possibilities Using --mount
Besides these advantages, --mount
is also the more powerful option. Not only does it allow to specify bind mounts, but
also to create other mount types like volumes. Here's a quick overview of
all valid keys for --mount
:
- type: Defines the mount type. I'm using
bind
in this article, butvolume
andtmpfs
are valid values as well. - source: Can also be shortened to
src
and defines the source directory or file on the host system. - destination: Can also defined as
target
or shortened todst
and defines the target in the container. - readonly: This key doesn't have a value and grants the container read-only access to source.
- Platform-specific parameters: bind-propagation (Linux) and consistency (macOS), I'll leave those out here because the average user doesn't need them.
Disadvantages of Bind Mounts
Bind mounts are a good fit for environments where a developer changes files in a working directory frequently, but they're just one way to decouple data from containers. The biggest drawback you'll face with bind mounts is that they depend on the directory structure on the host system, which limits the overall portability. Also, multiple users and processes may access the host directory, causing strange and avoidable side effects.
That is why Docker introduced an alternative to bind mounts which is preferable in most other cases: volumes.