It can be interesting to see how uids between the docker host and docker containers are mapped. For example, for security concerns.
As a reminder, docker containers are based on two linux kernel features: linux namespaces and cgroups.
Basically, linux namespaces provide isolation for running processes and cgroups allows you to isolate resource usage.
Let’s first run a docker container. Here, we will run a mariadb docker in background with -d option
[docker@docker1 ~]$ docker run -d -e MYSQL_ROOT_PASSWORD=test123 mariadb 5c4450939d71814070945f86f9712ba78893417e2342fb48aafced8160cd0d15
Now the container mariadb is running. Let’s see what is happening on a host level.
[docker@docker1 ~]$ ps -ef UID PID PPID C STIME TTY TIME CMD polkitd 1729 1718 0 08:14 ? 00:00:00 mysqld
On a container level:
root@5c4450939d71:~# ps -ef UID PID PPID C STIME TTY TIME CMD mysql 1 0 0 06:14 ? 00:00:00 mysqld root 174 0 0 06:22 pts/0 00:00:00 bash
On the host level the mysqld process is running by polkitd and on a container level the process is running by mysql. Any ideas?
This is because the user id (UID) of the mysql user created in mariadb container corresponds to the same UID of the polkitd user on the host.
Let’s see what is the userid of the mysql user in the mariadb container
root@5c4450939d71:~# id mysql uid=999(mysql) gid=999(mysql) groups=999(mysql)
The UID of mysql is 999. On the host:
[docker@docker1 ~]$ cat /etc/passwd | grep 999 polkitd:x:999:997:User for polkitd:/:/sbin/nologin
We can see that 999 corresponds to the polkitd user id.
How to change this?
Well, this could be a problem because we don’t want to run docker containers with a system user that we don’t know.
One solution could be to create a mysql user with a certain UID on the host:
[root@docker1 ~]# useradd -g mysql -u 1099 -m -r mysql
Then, we modify the user id inside the docker image. To do so, we need to rebuild a new mariadb image 🙂
Let’s first clone the docker mariadb project
[docker@docker1 ~]$ git clone https://github.com/docker-library/mariadb.git Cloning into 'mariadb'... remote: Counting objects: 751, done. remote: Compressing objects: 100% (15/15), done. remote: Total 751 (delta 9), reused 18 (delta 8), pack-reused 728 Receiving objects: 100% (751/751), 152.38 KiB | 0 bytes/s, done. Resolving deltas: 100% (338/338), done.
We enter the directory of the mariadb version 10.3
[docker@docker1 ~]$ cd mariadb/10.3/
We need to modify the Dockerfile where all instructions are described
[docker@docker1 10.3]$ vi Dockerfile
Change this line
# vim:set ft=dockerfile: FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -r mysql && useradd -r -g mysql mysql
To this line
# vim:set ft=dockerfile: FROM debian:jessie # add our user and group first to make sure their IDs get assigned consistently, regardless of whatever dependencies get added RUN groupadd -g 1099 -r mysql && useradd -u 1099 -r -g mysql mysql
We rebuild a new image, let’s call it mariadbcustom
[docker@docker1 10.3]$ docker build -t mariadbcustom:latest . Sending build context to Docker daemon 13.31kB Step 1/19 : FROM debian:jessie ---> 5dd74d62fab8 Step 2/19 : RUN groupadd -g 1099 -r mysql && useradd -u 1099 -r -g mysql mysql ---> Using cache ---> a285892faa45 Step 3/19 : ENV GOSU_VERSION 1.10 ---> Using cache ---> 069252945f7a Step 4/19 : RUN set -ex; fetchDeps=' ca-certificates wget '; apt-get update; apt-get install -y --no-install-recommends $fetchDeps; rm -rf /var/lib/apt/lists/*; dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')"; wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch"; wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc"; export GNUPGHOME="$(mktemp -d)"; gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4; gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu; rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc; chmod +x /usr/local/bin/gosu; gosu nobody true; apt-get purge -y --auto-remove $fetchDeps ---> Using cache ---> c82d4738b781 Step 5/19 : RUN mkdir /docker-entrypoint-initdb.d ---> Using cache ---> 08acd0843256 Step 6/19 : RUN apt-get update && apt-get install -y --no-install-recommends apt-transport-https ca-certificates pwgen && rm -rf /var/lib/apt/lists/* ---> Using cache ---> 3ed44a5e3cf5 Step 7/19 : ENV GPG_KEYS 199369E5404BD5FC7D2FE43BCBCB082A1BB943DB 430BDF5C56E7C94E848EE60C1C4CBDCDCD2EFD2A 4D1BB29D63D98E422B2113B19334A25F8507EFA5 ---> Using cache ---> b30af869afbb Step 8/19 : RUN set -ex; export GNUPGHOME="$(mktemp -d)"; for key in $GPG_KEYS; do gpg --keyserver ha.pool.sks-keyservers.net --recv-keys "$key"; done; gpg --export $GPG_KEYS > /etc/apt/trusted.gpg.d/mariadb.gpg; rm -r "$GNUPGHOME"; apt-key list ---> Using cache ---> 7a6e03190271 Step 9/19 : RUN echo "deb https://repo.percona.com/apt jessie main" > /etc/apt/sources.list.d/percona.list &> /etc/apt/preferences.d/percona ---> Using cache ---> e55705d326a2 Step 10/19 : ENV MARIADB_MAJOR 10.3 ---> Using cache ---> bb3bc4adcf42 Step 11/19 : ENV MARIADB_VERSION 1:10.3.6+maria~jessie ---> Using cache ---> 05bb1dc686c8 Step 12/19 : RUN echo "deb http://ftp.osuosl.org/pub/mariadb/repo/$MARIADB_MAJOR/debian jessie main" > /etc/apt/sources.list.d/mariadb.list &> /etc/apt/preferences.d/mariadb ---> Using cache ---> 3626c50c8d83 Step 13/19 : RUN { echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password password 'unused'; echo "mariadb-server-$MARIADB_MAJOR" mysql-server/root_password_again password 'unused'; } | debconf-set-selections && apt-get update && apt-get install -y "mariadb-server=$MARIADB_VERSION" percona-xtrabackup-24 socat && rm -rf /var/lib/apt/lists/* && sed -ri 's/^users/#&/' /etc/mysql/my.cnf /etc/mysql/conf.d/* && rm -rf /var/lib/mysql && mkdir -p /var/lib/mysql /var/run/mysqld && chown -R mysql:mysql /var/lib/mysql /var/run/mysqld && chmod 777 /var/run/mysqld && find /etc/mysql/ -name '*.cnf' -print0 | xargs -0 grep -lZE '^(bind-address|log)' | xargs -rt -0 sed -Ei 's/^(bind-address|log)/#&/' && echo '[mysqld]nskip-host-cachenskip-name-resolve' > /etc/mysql/conf.d/docker.cnf ---> Using cache ---> 7d3d52632798 Step 14/19 : VOLUME /var/lib/mysql ---> Using cache ---> 3880f6c65676 Step 15/19 : COPY docker-entrypoint.sh /usr/local/bin/ ---> Using cache ---> 98aa1e3161c4 Step 16/19 : RUN ln -s usr/local/bin/docker-entrypoint.sh / # backwards compat ---> Using cache ---> a5394275c2b2 Step 17/19 : ENTRYPOINT ["docker-entrypoint.sh"] ---> Using cache ---> c456c7b34697 Step 18/19 : EXPOSE 3306 ---> Using cache ---> 05068b456523 Step 19/19 : CMD ["mysqld"] ---> Using cache ---> 5973a27bfd43 Successfully built 5973a27bfd43 Successfully tagged mariadbcustom:latest
Let’s check our image is here
[docker@docker1 10.3]$ docker images REPOSITORY TAG IMAGE ID CREATED SIZE mariadbcustom latest 5973a27bfd43 8 days ago 403MB
we run a docker container with our new customized image
[docker@docker1 10.3]$ docker run -d -e MYSQL_ROOT_PASSWORD=test123 mariadbcustom 7e344d87c4bc2a9c62298b9ec97aa4a331d8311cb1f077f47fcb673f1b3d8fa7
Let’s check if the user id was properly initialized to the mysql user
[docker@docker1 10.3]$ docker ps CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 7e344d87c4bc mariadbcustom "docker-entrypoint.s…" 6 minutes ago Up 6 minutes 3306/tcp hungry_heisenberg
[docker@docker1 10.3]$ docker exec -it hungry_heisenberg /bin/bash
root@7e344d87c4bc:~# id mysql uid=1099(mysql) gid=1099(mysql) groups=1099(mysql)
We check also that the mysqld process run on the host as mysql user
[docker@docker1 10.3]$ ps -ef UID PID PPID C STIME TTY TIME CMD mysql 2727 2716 2 14:05 ? 00:00:00 mysqld
On the host, we can see that the mysqld process runs as mysql user. Why? Because now the user id of the mysql user existing on the docker container corresponds to the one existing on the host. In this case, the user id is 1099.
Conclusion:
In some use cases you might want to use a specific user to run some process and not using root or whatever user.However, in order to do that you sometimes need to change the Dockerfile or add a specific user on the host.