Docker vs Host user

Written on

By default when we run a process inside a docker container, it is run as root user, and that’s all right, after all we are talking about insider the container, but as far as the host machine is concerned what user is running the process? Spoiler alert: It is the same root user as on the host.


Let’s take a step back and try to understand what’s happening. So I created a fresh VM server and installed docker. Now let’s create a user called host1 in the host machine and let’s add this user to sudo group and docker group, so that we can use docker commands without sudo everytime



root@aki:~# adduser host1
root@aki:~# usermod -aG sudo host1
root@aki:~# usermod -aG docker host1
root@aki:~# mkhomedir_helper host1
root@aki:~# su host1
host1@aki:/root$

Now we have two users on the host that we care about, we can get those two with cat /etc/passwd | grep -E "root|host1"



root@aki:~# cat /etc/passwd | grep -E "root|host1"
root:x:0:0:root:/root:/bin/bash
host1:x:1000:1000:,,,:/home/host1:/bin/bash

Now let’s try to run a simple ubuntu docker container and log into it, to keep it simple we are not going to create a docker compose file this applies to that as well


host1@aki:~# docker run -it ubuntu:latest bash
Unable to find image 'ubuntu:latest' locally
latest: Pulling from library/ubuntu
49b384cc7b4a: Pull complete
Digest: sha256:3f85b7caad41a95462cf5b787d8a04604c8262cdcdf9a472b8c52ef83375fe15
Status: Downloaded newer image for ubuntu:latest
root@ca368628bddf:/#

Now that we are inside docker let’s try to find our id with id command


root@ca368628bddf:/# id
uid=0(root) gid=0(root) groups=0(root)
root@ca368628bddf:/# sleep 500

We are root user, that’s cool, we are inside the container, now let’s try to run a process, maybe sleep 500. Now let’s open another terminal and try to grep the sleep process in the host.


host1@aki:/root$ ps aux | grep sleep
root        7319  0.0  0.1   2688  1044 pts/0    S+   13:19   0:00 sleep 500
host1       6845  0.0  0.0   6432   724 pts/2    S+   13:26   0:00 grep --color=auto sleep

We can see the actual sleep process is under root user and I(as host1) will not be able to kill this process either, even though I started the container. Well one way to kill the process is try it with sudo. This goes to show that the process running inside the container is perceived by the host as actual root process.


host1@aki:/root$ kill -9 7319
bash: kill: (7319) - Operation not permitted
host1@aki:/root$ sudo !!
sudo kill -9 7319
host1@aki:/root$ ps aux | grep sleep
host1       7325  0.0  0.0   6432   656 pts/2    S+   13:30   0:00 grep --color=auto sleep
host1@aki:/root$

Okay, but what about files? Let’s switch to the other terminal where we had executed the docker sleep command and exit this container and create a folder in the host and map this folder to the container and then start it.


host1@aki:~/experiment$ ls -larth containerMapped/
total 8.0K
drwxrwxr-x 3 host1 host1 4.0K May 26 13:34 ..
drwxrwxr-x 2 host1 host1 4.0K May 26 13:34 .
host1@aki:~/experiment$ docker run -v /home/host1/experiment/containerMapped:/container/data -it ubuntu bash

Now that we have mapped a volume let’s try to create some folders in this location, and for testing let’s create two new users inside the docker and try to create directories with them as well


root@c45aebb50fd4:/# cd /container/data/
root@c45aebb50fd4:/container/data# useradd container1
root@c45aebb50fd4:/container/data# useradd container2
root@c45aebb50fd4:/container/data# mkdir ascontainer1
root@c45aebb50fd4:/container/data# mkdir ascontainer2
root@c45aebb50fd4:/container/data# chown container1 ascontainer1/
root@c45aebb50fd4:/container/data# chown container2 ascontainer2
root@c45aebb50fd4:/container/data# ls -larth
total 20K
drwxr-xr-x 3 root       root   4.0K May 26 14:00 ..
drwxr-xr-x 2 root       root   4.0K May 26 14:00 asroot
drwxr-xr-x 2 container1 root   4.0K May 26 14:03 ascontainer1
drwxr-xr-x 2 container2 root   4.0K May 26 14:04 ascontainer2
drwxrwxr-x 5 ubuntu     ubuntu 4.0K May 26 14:04 .
root@c45aebb50fd4:/container/data#

So far it seems good, but now let’s exit out of the container and check it from the host machine’s perspective.


host1@aki:~/experiment/containerMapped$ ls -larth
total 20K
drwxrwxr-x 3 host1 host1 4.0K May 26 14:00 ..
drwxr-xr-x 2 root  root  4.0K May 26 14:00 asroot
drwxr-xr-x 2  1001 root  4.0K May 26 14:03 ascontainer1
drwxr-xr-x 2  1002 root  4.0K May 26 14:04 ascontainer2
drwxrwxr-x 5 host1 host1 4.0K May 26 14:04 .
host1@aki:~/experiment/containerMapped$

Okay, fine it seems like there are two directories in the host machine which doesn’t seem to have proper userID associated with it, because 1001 and 1002 were not resolved properly. Now let’s try to create a couple more users in the host machine host2 and host3


root@aki:/home/host1/experiment/containerMapped# adduser host2
root@aki:/home/host1/experiment/containerMapped# adduser host3
root@aki:/home/host1/experiment/containerMapped# ls -larth
total 20K
drwxrwxr-x 3 host1 host1 4.0K May 26 14:00 ..
drwxr-xr-x 2 root  root  4.0K May 26 14:00 asroot
drwxr-xr-x 2 host2 root  4.0K May 26 14:03 ascontainer1
drwxr-xr-x 2 host3 root  4.0K May 26 14:04 ascontainer2
drwxrwxr-x 5 host1 host1 4.0K May 26 14:04 .
root@aki:/home/host1/experiment/containerMapped#

Now those invalid IDs seem to have become owned by host2 and host3 but in original they are owned by container2 and container3.

This goes to show that the users are managed by IDs in container and host, and as long as the ID of the user is the same in both the container and the host, they will be identified as the same user. This is because when we take a look at the /etc/passwd file it becomes little clearer.


root@aki:~# tail -n3 /etc/passwd
host1:x:1000:1000:,,,:/home/host1:/bin/bash
host2:x:1001:1001:,,,:/home/host2:/bin/bash
host3:x:1002:1002:,,,:/home/host3:/bin/bash

We can see that the two new users that we created got the userID 1001 and 1002, so when ls was trying to look for user 1001 it was available as host2. And the root user inside the container is the same root user as in the host machine because both of them has the id 0.


It is due to these reasons that when we create a docker containers it’s a good idea to explicitly mention the userId and groupId both in docker run and docker compose files. In the following command 1000:1000 represent the userId and the groupId with which we want to run the process.


docker run --user 1000:1000 ubuntu:latest tail -f /dev/null


version: '3.8'

services:
  app:
    build: .
    container_name: ubuntu_container
    volumes:
      - ./host_data:/container_data
    user: "1000:1000"

We have discussed mostly about userId here, but this is the same case with groups as well.




Tags · Tech, Linux