Fix Ownership of Files in a Mounted Volume
February 1, 2022
The file system of a docker container is ephemeral: it will disappear as soon as the container is destroyed.
To prevent data losses you can mount a folder of the host into the container that will survive the destroy of the container.
But it is not uncommon to find issues with the ownership and permissions of the shared files.
The file system of the host represents who is the owner of each file with an user and a group numbers.
Plain numbers.
Humans, on the other hand, think in terms of user names: “this is the file of Alice; this other is of Bob”.
The mapping between the numbers that the file system uses and the names that the humans understand is stored in /etc/passwd
and /etc/groups
.
And here we have a problem.
These two files, /etc/passwd
and /etc/groups
, live in the host’s file system and they are used to map the files’ numbers to names when you are seeing the files from the host.
When you enter into the docker container (or run a command inside), the shared files, mounted with -v
, will have the same file numbers.
But, an here is the twist, inside the container you will be using for the mapping the /etc/passwd
and /etc/groups
files of the container and not of the host.
Same file numbers, different mappings.
UID/GID
Imagine the following folder in the host:
(host) $ ls -lah /home/alice/blog
drwxr-xr-x 12 alice devel 4.0K Jan 30 21:28 .
drwxr-xr-x 63 alice devel 4.0K Jan 30 21:25 ..
drwxr-xr-x 2 alice devel 4.0K Jan 30 20:35 docker
drwxr-xr-x 8 alice devel 4.0K Jan 31 02:40 .git
-rw-r--r-- 1 alice devel 52 Jan 22 14:23 .gitignore
-rw-r--r-- 1 alice devel 1.9K Jan 30 21:10 Makefile
drwxr-xr-x 26 alice devel 4.0K Jan 31 02:22 posts
All those files and folders belong to the user alice
and the group develop
.
But that’s with the host’s mapping.
We can see the file numbers behind running:
(host) $ ls -lah --numeric-uid-gid /home/alice/blog
drwxr-xr-x 12 1001 1024 4.0K Jan 30 21:28 .
drwxr-xr-x 63 1001 1024 4.0K Jan 30 21:25 ..
drwxr-xr-x 2 1001 1024 4.0K Jan 30 20:35 docker
drwxr-xr-x 8 1001 1024 4.0K Jan 31 02:43 .git
-rw-r--r-- 1 1001 1024 52 Jan 22 14:23 .gitignore
-rw-r--r-- 1 1001 1024 1.9K Jan 30 21:10 Makefile
drwxr-xr-x 26 1001 1024 4.0K Jan 31 02:22 posts
So, for the host user alice
maps to the UID 1001
; the same goes for the group develop
and the GID 1024
.
Now, imagine that we run a docker container and mount that folder above
(host) $ docker run -it -v /home/alice/blog:/wd ubuntu bash
The host’s /home/alice/blog
is mounted in /wd
inside the container.
If we list the files from inside the container we will see the same UIDs and GIDs
(container) $ ls -lah --numeric-uid-gid /wd
drwxr-xr-x 12 1001 1024 4.0K Jan 30 21:28 .
drwxr-xr-x 63 1001 1024 4.0K Jan 30 21:25 ..
drwxr-xr-x 2 1001 1024 4.0K Jan 30 20:35 docker
drwxr-xr-x 8 1001 1024 4.0K Jan 31 02:43 .git
-rw-r--r-- 1 1001 1024 52 Jan 22 14:23 .gitignore
-rw-r--r-- 1 1001 1024 1.9K Jan 30 21:10 Makefile
drwxr-xr-x 26 1001 1024 4.0K Jan 31 02:22 posts
But not necessary we will see the same mapping.
Incorrect mapping: two scenarios
There are 2 cases.
Scenario 1: there is no user/group with those IDs in the container so you will see this:
(container) $ ls -lah /wd
drwxr-xr-x 12 1001 1024 4.0K Jan 30 21:28 .
drwxr-xr-x 63 1001 1024 4.0K Jan 30 21:25 ..
drwxr-xr-x 2 1001 1024 4.0K Jan 30 20:35 docker
drwxr-xr-x 8 1001 1024 4.0K Jan 31 02:43 .git
-rw-r--r-- 1 1001 1024 52 Jan 22 14:23 .gitignore
-rw-r--r-- 1 1001 1024 1.9K Jan 30 21:10 Makefile
drwxr-xr-x 26 1001 1024 4.0K Jan 31 02:22 posts
Scenario 2: there is user/group in the container assigned to those IDs but they are mapped, of course, to something different than alice
/develop
:
(container) $ ls -lah /wd
drwxr-xr-x 12 apt sys 4.0K Jan 30 21:28 .
drwxr-xr-x 63 apt sys 4.0K Jan 30 21:25 ..
drwxr-xr-x 2 apt sys 4.0K Jan 30 20:35 docker
drwxr-xr-x 8 apt sys 4.0K Jan 31 02:43 .git
-rw-r--r-- 1 apt sys 52 Jan 22 14:23 .gitignore
-rw-r--r-- 1 apt sys 1.9K Jan 30 21:10 Makefile
drwxr-xr-x 26 apt sys 4.0K Jan 31 02:22 posts
How to fix this?
We need a common user and group in the host and container with the same UID and GID in both worlds.
In the scenario 1 we need to create an user and a group inside the container with the same UID/GID that the one from the host (1001
and 1024
respectively)
In the scenario 1 we are lucky: the UID/GID 1001
/1024
are not assigned to any user/group so we can create the user alice
and the group develop
in the container and that’s it.
The scenario 2 is more complex because the UID/GID are already assigned. We will have to create a totally new user/group, both in the host and the container, to fix this.
Because the scenario 1 is a special subset of the scenario 1, I will describe how to fix the scenario 2.
First, pick a UID/GID that is not used either in the host nor in the container.
I’m using different numbers to make it easier to read but it is not necessary. You could use the same number for the UID and the GID without problems.
You can skip this step for the scenario 1 and use the original UID/GID 1001
/1024
For example, let’s pick 1201
for the UID and 1224
for the group.
We can check this running grep
and getting a 0 response that means that the id was not found (so it is not used)
(host) $ grep -c 1201 /etc/passwd
0
(host) $ grep -c 1224 /etc/group
0
(container) $ grep -c 1201 /etc/passwd
0
(container) $ grep -c 1224 /etc/group
0
With a free UID/GID we need to create a group and an user with those ids
(container) $ sudo groupadd -g 1224 devel2
(container) $ sudo useradd -s /bin/bash -u 1201 -M -g 1224 alice2
These creates a group named devel2
with GID of 1224
and an user named alice2
with UID of 1201
. Yes, I’m not very creative with the names.
The -M
says that you don’t want a home folder and -s
sets the user’s shell to /bin/bash
.
You can skip this step for the scenario 1 as you can use alice
and devel
Now we do the same in the host
(host) $ sudo groupadd -g 1224 devel2
(host) $ sudo useradd -s /bin/bash -u 1201 -M -g 1224 alice2
Finally change the ownership of the shared files running
(host) $ sudo chown -R 1201:1224 /home/user/blog
Now before working with the files you need to log in as alice2
(host) $ sudo su alice2
(container) $ sudo su alice2
This applies to both the host and container.
Once logged in it may be convenient to set your HOME
.
(host) $ export HOME=/home/alice
(container) $ export HOME=/wd
Why a simplest chown
/chmod
does not work?
On internet the solution to the “permission problem” is to run chmod
.
You run chmod
in the container to add a read-write-exec permissions ot everyone. Indeed any user, from the host or container, will be able to work with those files.
But what happen if you add a new shared file? That will have the user ownership and default permissions and you will not be able to use it in the host/container.
Not a stable fix, and 0777
looks suspicious.
Running chown
to change the ownership is even more messier because you may change and set the “correct” user/group inside the container but you will be scrubbing the scenario in the host.
The ownership is not the problem. The permission are not the problem. Who to interpret the UID/GID is the problem.
(bonus track) To be a sudoer
$ sudo groupadd admin
$ sudo echo '%admin ALL=(ALL) NOPASSWD:ALL' > /etc/sudoers.d/admin
$ sudo chmod 0400 /etc/sudoers.d/admin
$ sudo usermod -aG admin alice2
$ sudo usermod -aG sudo alice2
Related tags: docker