In this tutorial, we’ll look at the ownership of mounted files and folders within the Docker container. Particularly, we’ll be looking at how file ownership changes when we mount files from the host onto the container.
2. Files Ownership Discrepancy Between Host and Container
When we mount a directory into a Docker container, the owner of the files and directory within would sometimes appear to be owned by another user. For example, for a given directory, the owner could be user baeldung on the host. However, the same files and folder, when mounted, might appear to be owned by a different user within the container. One exception to this observation is files and folders owned by root will always continue to be owned by the root user within the container.
Let’s demonstrate the problem by mounting a folder consisting of files and directories into a Docker container. First, we’ll create a directory to serve as a mount point on the host:
$ mkdir container-mount
Subsequently, we’ll create files and directories and place them into the container-mount folder. Finally, we’ll run the following command to get their ownership information:
$ ls -l container-mount total 4 drwxrwxr-x 2 baeldung baeldung 4096 Dec 27 08:48 inner-dir -rw-rw-r-- 1 baeldung baeldung 0 Dec 27 08:48 log1.txt -rw-rw-r-- 1 baeldung baeldung 0 Dec 27 08:48 log2.txt
From the host perspective, we can see that every file and folder within the container-mount belongs to the baeldung user, which is the user that created those files and folders.
Then, we start a Docker container running Ubuntu image, mounting the container-mount folder to the /opt/mount path:
$ sudo docker run -it -v /home/baeldung/container-mount:/opt/mount ubuntu:latest sh / #
From within the container, we can check the owner information of the mounted files and folder using the same command:
/ # ls -l /opt/mount total 4 drwxrwxr-x 2 1000 1000 4096 Dec 27 07:48 inner-dir -rw-rw-r-- 1 1000 1000 0 Dec 27 07:48 log1.txt -rw-rw-r-- 1 1000 1000 0 Dec 27 07:48 log2.txt
Interestingly, the owner of the same files and folders are now user 1000 instead of baeldung like in the host.
3. Understanding How User ID Works in Linux
In Linux, all the users have a user id (uid) associated with them. For instance, the root user has a uid value of 0. To check the uid of a user, we can run the command:
$ id -u baeldung 1000
When Linux stores the owner information of files and directories, they are storing the uid of the user internally.
To display the username when we invoke the ls -l command, a lookup is performed on the /etc/passwd to map the uid to a username. Similarly, when we change the owner of files using chown, the command consults the /etc/passwd to obtain the uid of a given username. Interestingly, because the username is redundant from the perspective of file ownership, we can change the owner of files to uid that doesn’t own by any users in the /etc/passwd file.
For example, we could chown the file to uid 2888, which doesn’t belong to any user in the system:
$ id -nu 2888 id: ‘2888’: no such user $ sudo chown 2888:2888 container-mount $ ls -l total 4 drwxrwxr-x 3 2888 2888 4096 Dec 27 08:48 container-mount
On the contrary, changing files or folders to non-existence usernames will not work. That’s because the username will not map to any valid uid, thereby preventing Linux from setting the permissions bits on the files:
$ sudo chown bob:bob container-mount chown: invalid user: ‘bob:bob’
To explain the discrepancy of mounted files, we simply have to recognize that the Docker container maintains an independent copy of /etc/passwd. In other words, the uid 1000 on the host doesn’t translate to the same username within the container. In fact, the username that exists on the host does not exist inside the Docker container unless explicitly created. This is why we see the files as owned by uid 1000 instead of baeldung because baeldung doesn’t exist in the /etc/passwd inside the container.
A straightforward way to handle this issue is to make sure the same user is also appearing in the /etc/passwd file of the container with the same uid.
4.1. Creating a User With Same UID in Container
From within the container, we can create a user with a specific uid using the useradd command with the flag -u. For example, while inside the container, we could create a user baeldung with uid 1000.
/ # useradd baeldung -u 1000
Once we’ve created the user, the mounted files and folders will now show baeldung as the owner:
/ # ls -l /opt/mount total 4 drwxrwxr-x 2 baeldung baeldung 4096 Dec 27 07:48 inner-dir -rw-rw-r-- 1 baeldung baeldung 0 Dec 27 07:48 log1.txt -rw-rw-r-- 1 baeldung baeldung 0 Dec 27 07:48 log2.txt
One caveat to this solution is that upon recreating the container, we’ll need to rerun the command.
4.2. Customize Image With Dockerfile
We could put the script into a Dockerfile and bake it into the image itself. For instance, we could put the command that creates user baeldung with uid 1000 into the Dockerfile:
FROM ubuntu:latest RUN useradd baeldung -u 1000
Alternatively, we could parameterize the uid value using an environment variable using the ARG Dockerfile directive. During build time, we’ll then pass the value using the –build-arg flag. To do that, we simply change the value 1000 to an environment variable:
FROM ubuntu:latest ARG HOST_UID RUN useradd baeldung -u $HOST_UID
Using the ARG directive, we can define a variable that we’ll pass during build time. Then, we could run the docker build command while specifying the –build-arg flag:
$ sudo docker build --build-arg HOST_UID=$(id -u) --tag ubuntu-custom:latest .
The id -u command simply returns the current user uid, and then the value is set to the build argument HOST_UID.
In this tutorial, we’ve quickly looked at the issue of ownership for mounted files. Particularly, we’ve seen how files that are mounted will have their owner changed. Then, we’ve explained the mapping relationship between username and uid through /etc/passwd file. Finally, we’ve demonstrated workarounds to resolve this discrepancy.