I have read the some documents before asking this question:
And I am confused about the following two parts:
Their behavior is completely opposite:
For bind mounts:
If you bind-mount into a non-empty directory on the container, the directory’s existing contents are obscured by the bind mount.
For named volume and anonymous volumes:
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.
My question is, if I use a VOLUME
command in dockerfile to create a named volume anonymous volumes, and at the same time, use a bind mount to mount a non exist path into the container, what goes on behind the scenes?
For example:
# in docker file
VOLUME /path/in/container
# when run container
docker run -v /not-exist-dir/in/host:/path/in/container ... /< image >
I have do some test and the result is:
/var/lib/docker/volumes/
So,
what happened behind this scenario?
Let me give a more specific example:
Here is the dockerfile of the openfrontier/gerrit image, we can see at the end of the docker file, there is a VOLUME command:
VOLUME $GERRIT_SITE
which will actually create an anonymous volumes on the host and mount it to /var/gerrit/review_site
(value of GERRIT_SITE) in the container when any container is created from this image like this:
docker run -dit --name gerrit openfrontier/gerrit:2.15.3
after that, I can see the anonymous volumes under /var/lib/docker/volumes/
and I can use docker volume ls
to see its name be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00
, and also with docker inspect gerrit
command, we can see:
"Mounts": [
{
"Type": "volume",
"Name": "be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00",
"Source": "/var/lib/docker/volumes/be4538dbf3a51da463391c6eca9714fb6dd0c11379f1e2918f74c33d56633f00/_data",
"Destination": "/var/gerrit/review_site",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
],
and there are some file under these two folder, which are created by the container after it running.
Till now, this is a normal example for create an anonymous volumes by using VOLUME command.
However, if I run this container with the following command:
docker run -dit --name gerrit -v /home/test:/var/gerrit/review_site openfrontier/gerrit:2.15.3
where /home/test
is not exist on the host, then no anonymous volumes is created, instead, /home/test
folder is created and it is not empty!!!, the mount info is as follows:
"Mounts": [
{
"Type": "bind",
"Source": "/home/test",
"Destination": "/var/gerrit/review_site",
"Mode": "",
"RW": true,
"Propagation": "rprivate"
}
],
I think bind mounts is take effects here but I just do not understand why the path on the host is not empty(since bind-mount into a non-empty directory on the container, the directory’s existing contents are obscured by the bind mount.)
I also test mounting a not empty folder to the container by put some file under "/home/test" before I use docker run
to start a container, the result is the original file was kept and new files was added too.
I know the examples above are not good practice to use docker volume, But I just wondering what happened behind.
The volume declaration in the Dockerfile sets a bit of metadata on the image that tells docker run
to define an anonymous volume at that location any time a container is made from that image. This is not a named volume or host mount, but it has a lot in common with both (they are all bind mounts by default, and anonymous volumes are listed in docker volume ls
along with named volumes).
However, when you specify a host mount to the same container directory, that takes precedence (two volume mounts to the same directory inside the container will not happen). Any modifications to that directory by the commands running inside the container will be visible on the host, but the directory itself will not be initialized by the image contents.
If you want to initialize a host directory with image contents, you can use a named volume that performs a bind mount. There are a few differences in behaviour from the host mount. Mainly the directory must exist in advance, and inside a compose file you must use absolute paths instead of relative ones. I've got the syntax for that in my presentation here:
https://sudo-bmitch.github.io/presentations/dc2018eu/tips-and-tricks-of-the-captains.html#48