Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overlapping bind-mounts and permissions in docker on linux

Overlapping bind mounts on a linux host seems to create ghost files on the host machine owned by root. Is this intended? Here's an example:

# Create a file to mount in the container
touch hostfile
# Create a temporary directory to mount in the container
mkdir tempdir
# Run bash in the container and mount the file and directory
docker run --rm --volume=`pwd`/tempdir:/home --volume=`pwd`/hostfile:/home/hostfile ubuntu bash

After running the command, the hostfile can be found in the tempdir but is owned by root.

Note that

  • running the same bash script on an OS X host results in the hostfile being owned by the user who started the container,
  • specifying the user and group id of the user on the host machine as part of the docker run call does not change anything.
like image 543
Till Hoffmann Avatar asked May 08 '18 16:05

Till Hoffmann


People also ask

What is a bind mount Docker?

Bind mounts have been around since the early days of Docker. Bind mounts have limited functionality compared to volumes. 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 absolute path on the host machine.

What are bind mounts in Linux?

Bind mounts in Linux® enable you to mount an already-mounted file system to another location within the file system. Generally, bind mounts are used when restricting the access of specified users to designated parts of a website by replicating the website's directory into a jailed user's home directory.

When dealing with the official Jenkins Docker image Why should you bind mount in a volume?

If you bind mount in a volume - you can simply back up that directory (which is jenkins_home) at any time. This is highly recommended. Treat the jenkins_home directory as you would a database - in Docker you would generally put a database on a volume.

What is an ideal use case for Docker's bind mount storage?

Good use cases for bind mounts Bind mounts are appropriate for the following types of use case: Sharing configuration files from the host machine to containers. This is how Docker provides DNS resolution to containers by default, by mounting /etc/resolv. conf from the host machine into each container.


1 Answers

This behavior is the intended one. Let's try to understand what happens and perform the same mounts manually.

We create the hostfile, the "host" directory and the target "container" directory at some location (say, it is /home/qazer/dockx on my machine):

# the host file
$ touch hostfile

# the "host"-side dir
$ mkdir hostdir

# the "container"-side dir
$ mkdir contdir

Then we perform the mounts:

# the first mount: "host" dir to "container" dir
$ sudo mount --bind hostdir contdir

# success!

# the second mount: host file to the container file
$ sudo mount --bind hostfile contdir/hostfile
mount: contdir/hostfile: mount point does not exist.

Yay, the bind mount failed because the target file does not exist! Consulting the manpage for mount(2) system call reveals that this call would fail if some of the paths provided points to nonexistent file:

ENOENT A pathname was empty or had a nonexistent component.

So, what Docker actually does is the following:

$ sudo strace -f -p $(pidof containerd) \
              -e trace=%file,mount -yy |& grep -e hostfile -e home
...
[pid 23945] newfstatat(AT_FDCWD, "/var/lib/docker/overlay2/b2c32423952d49f21e7a9c1addec6201c7f036c8dba1da975bac6a34d5abbe11/merged/home/hostfile", 0xc00016ce08, 0) = -1 ENOENT (No such file or directory)
...
[pid 23945] openat(AT_FDCWD, "/var/lib/docker/overlay2/b2c32423952d49f21e7a9c1addec6201c7f036c8dba1da975bac6a34d5abbe11/merged/home/hostfile", O_RDONLY|O_CREAT|O_CLOEXEC, 0755) = 7</var/lib/docker/overlay2/b2c32423952d49f21e7a9c1addec6201c7f036c8dba1da975bac6a34d5abbe11/merged/home/hostfile>
[pid 23945] mount("/home/qazer/dockx/hostfile", "/var/lib/docker/overlay2/b2c32423952d49f21e7a9c1addec6201c7f036c8dba1da975bac6a34d5abbe11/merged/home/hostfile", 0xc00013bb00, MS_BIND|MS_REC, NULL) = 0

First, the existence of the /home/hostfile file is checked in the container file system (the newfstat() call). This file is not present (ENOENT), so Docker creates it to avoid the error we've seen before (the openat(O_CREAT) call), and only after this the container engine performs the actual bind mount of hostfile to the container file system (the mount() call).

At the time of writing, the /home directory is already bind-mounted from the host (the first mount), so this write goes to this host directory. Finally, when the container stops, the file written by Docker stays in the host directory, and this is what you see.

As to the file ownership in case of Mac OS host — I think that the reason is the same as in this your question.

like image 111
Danila Kiver Avatar answered Nov 03 '22 01:11

Danila Kiver