This post is somewhat lenglthy but bear with me for a while...
Suppose you have an app that sits in /app
in your local (host) filesystem with the following structure
app
|-- index.php
|-- foo
| `-- file-h1
`-- bar
`-- file-h2
Now suppose we have an image (tagged myrepo/app
) that exploits the following data structure
opt
|-- app
| `-- foo
| `-- file-c1
If we run a container from that image by mounting host's /app
to container's /opt/app
as follows
docker container run \
-v /app:/opt/app \
myrepo/app
The resulting data structure of the container will be the following
opt
|-- app
| |-- index.php
| |-- foo
| | `-- file-h1
| `-- bar
| `-- file-h2
So far, so good...
Now, lets say that we want to use both a named volume called data
to be mounted on /opt/app/foo
and a bind-mount for mounting /app
to /opt/app
docker container run \
-v /app:/opt/app \
-v data:/opt/app/foo
myrepo/app
The resulting data structure inside the container will be:
opt
|-- app
| |-- index.php
| |-- foo
| | `-- file-c1
| `-- bar
| `-- file-h2
As it is stated in various posts (like this and this) the docker mounts are performed in lexicographic order (i.e shortest path first). According to this, I would expect docker first to execute the bind-mount ( -v /app:/opt/app
) and then the volume (-v data:/opt/app/foo
).
Hence, I would expect that the contents of host's /app
would replace/obscure the contents of container's /opt/app
and thus file-h1
to be inside /opt/app/foo
. Finally, file-h1
would be copied in the newly created data
volume and the volume would be mounted on /opt/app/foo
(so file-h1
should be shown instead of file-c1
)
My questions raised when I tried to understand this answer on SO
Basically, there are 3 types of mounts which you can use in your Docker container viz. Volumes, Bind mount and tmpfs mounts.
Multiple containers can run with the same volume when they need access to shared data. Docker creates a local volume by default.
Bind mounts When you use a bind mount, a file or directory on the host machine is mounted into a container. The file or directory is referenced by its full path on the host machine. The file or directory does not need to exist on the Docker host already. It is created on demand if it does not yet exist.
The most notable difference between the two options is that --mount is more verbose and explicit, whereas -v is more of a shorthand for --mount . It combines all the options you pass to --mount into one field. On the surface, both commands create a PostgreSQL container and set a volume to persist data.
Finally, and with a lot of help by github user cpuguy83, I figured out what actually docker engine does when we try to run a container that uses multiple mounts of different type (e.g both a bind-mount and a volume) as, for instance:
docker container run \
-v /app:/opt/app \
-v data:/opt/app/foo
myrepo/app
The key point to understand here is that docker executes the process in two steps that are done in the following order:
First, it creates a new storage-space (i.e. volume) in the host filesystem (... data/
) for the container to persist files and then (since that newly created volume is empty) it copies the container's files (i.e whatever is inside /opt/app/foo/*
) to the volume's storage location (... data/
)
Then after that, it performs all mounts (binds, volumes, tmpfs mounts, etc... are all lumped together) in lexicographic order (first mounts /app
to /opt/app
then ... data/
to /opt/app/foo
)
So, because of that, when we run the container with the mounts in our example, the docker first will copy the file-c1
to the ... data/
location in the host filesystem and second it will mount first the contents of host's /app
to the container's /opt/app
and then the host's ... data/
(which contains file-c1
) to container's /opt/app/foo
overwriting/obscuring its contents (i.e overwriting file-h1
with file-c1
). Therefore, if we take a look inside the running container after the mounts are done, the result will be the following:
opt
|-- app
| |-- index.php
| |-- foo
| | `-- file-c1
| `-- bar
| `-- file-h2
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With