iraklisg
iraklisg

Reputation: 5799

How docker handles multiple mount types?

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...

Running container with multiple mounts (both bind-mounts and volumes)

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

Upvotes: 21

Views: 4842

Answers (1)

iraklisg
iraklisg

Reputation: 5799

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:

  1. 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/)

  2. 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

Upvotes: 31

Related Questions