Docker containers are always run as root user by default. As a result all running processes, shared volumes, folders, files will be owned by root user. It becomes real problem when we need to modify files and folder in shared folders within host OS or docker container.

In order to solve such issue, we need to match host OS and docker container user's UIDs. The root user's UID is always 0. Running docker as root user is also considered as a bad security practice.


Host filesystem


Current user's information.


ubuntu@linux:~$ echo $HOME
/home/ubuntu

ubuntu@linux:~$ pwd
/home/ubuntu

ubuntu@linux:~$ id
uid=1000(ubuntu) gid=1000(ubuntu) groups=1000(ubuntu)

Data folder


ubuntu@linux:~$ mkdir data

Dockerfile


ubuntu@linux:~$ nano Dockerfile

FROM ubuntu:16.04

ENV GOSU_URL https://github.com/tianon/gosu/releases/download/1.4/gosu

COPY entrypoint.sh /usr/local/bin/entrypoint.sh

RUN apt-get update \
&& apt-get -y install \
ca-certificates \
curl \
&& gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
&& curl -o /usr/local/bin/gosu -SL "$GOSU_URL-$(dpkg --print-architecture)" \
&& curl -o /usr/local/bin/gosu.asc -SL "$GOSU_URL-$(dpkg --print-architecture).asc" \
&& gpg --verify /usr/local/bin/gosu.asc \
&& rm /usr/local/bin/gosu.asc \
&& rm -rf /var/lib/apt/lists/* \
&& chmod +x /usr/local/bin/gosu \
&& chmod +x /usr/local/bin/entrypoint.sh

ENTRYPOINT ["/usr/local/bin/entrypoint.sh"]

Entrypoint.sh


If you read the comments below, you'll see what it does.


ubuntu@linux:~$ nano entrypoint.sh

#!/bin/bash
set -e

# If "-e uid={custom/local user id}" flag is not set for "docker run" command, use 9999 as default
CURRENT_UID=${uid:-9999}

# Notify user about the UID selected
echo "Current UID : $CURRENT_UID"
# Create user called "docker" with selected UID
useradd --shell /bin/bash -u $CURRENT_UID -o -c "" -m docker
# Set "HOME" ENV variable for user's home directory
export HOME=/home/docker

# Execute process
exec /usr/local/bin/gosu docker "$@"

Create image


ubuntu@linux:~$ docker build -t app_img .

Sending build context to Docker daemon 3.584kB
Step 1/5 : FROM ubuntu:16.04
---> dd6f76d9cc90
Step 2/5 : ENV GOSU_URL https://github.com/tianon/gosu/releases/download/1.4/gosu
---> Running in 127ef4efcb80
---> 10d786ca796c
Removing intermediate container 127ef4efcb80
Step 3/5 : COPY entrypoint.sh /usr/local/bin/entrypoint.sh
---> 2756497869e5
Step 4/5 : RUN apt-get update && apt-get -y install ca-certificates curl && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && curl -o /usr/local/bin/gosu -SL "$GOSU_URL-$(dpkg --print-architecture)" && curl -o /usr/local/bin/gosu.asc -SL "$GOSU_URL-$(dpkg --print-architecture).asc" && gpg --verify /usr/local/bin/gosu.asc && rm /usr/local/bin/gosu.asc && chmod +x /usr/local/bin/gosu && chmod +x /usr/local/bin/entrypoint.sh
---> Running in 2aacad96c07c
---> 939ec3165391
Removing intermediate container 2aacad96c07c
Step 5/5 : ENTRYPOINT /usr/local/bin/entrypoint.sh
---> Running in e01eef5a0659
---> c042ca8f6891
Removing intermediate container e01eef5a0659
Successfully built 8d88aea7ed50
Successfully tagged app_img:latest

Create container - Version 1


We tell container to use local user's UID and link local data folder to container's /var/log folder.


ubuntu@linux:~$ docker run -i -t -v $(pwd)/data:/var/log -e uid=$UID --name app_con app_img /bin/bash

Current UID : 1000
docker@3afdd4887dc5:/$

Test


Check current user's UID.


docker@3afdd4887dc5:/$ id
uid=1000(docker) gid=1000(docker) groups=1000(docker)

Create file in container.


touch /var/log/guest.log && echo "Written in container" >> /var/log/guest.log

docker@3afdd4887dc5:/$ ls -l /var/log
-rw-r--r-- 1 docker docker 21 Jan 21 19:36 guest.log

docker@3afdd4887dc5:/$ cat /var/log/guest.log
Written in container

Create file in local OS and check existing files.


ubuntu@linux:~$ ls -l
drwxrwxr-x 2 ubuntu ubuntu 4096 Jan 21 19:36 data

ubuntu@linux:~$ touch data/host.log && echo "Written in host" >> data/host.log

ubuntu@linux:~$ ls -l data/
-rw-r--r-- 1 ubuntu ubuntu 37 Jan 21 19:40 guest.log
-rw-rw-r-- 1 ubuntu ubuntu 16 Jan 21 19:41 host.log

ubuntu@linux:~$ cat data/guest.log
Written in container
Written in host

ubuntu@linux:~$ cat data/host.log
Written in host

Check files in container again.


ubuntu@linux:~$ docker run -i -t -v $(pwd)/data:/var/log -e uid=$UID --name app_con_1 app_img /bin/bash
Current UID : 1000

docker@51952cf6bb61:/$ ls -l /var/log/
-rw-r--r-- 1 docker docker 37 Jan 21 19:40 guest.log
-rw-rw-r-- 1 docker docker 16 Jan 21 19:41 host.log

Create container - Version 2


As opposed "version 1" above, we will not tell container to use local user's UID. Instead, it will use 9999 as default value.


ubuntu@linux:~$ docker run -i -t -v $(pwd)/data:/var/log --name app_con_2 app_img /bin/bash
Current UID : 9999

docker@a997362050f4:/$ id
uid=9999(docker) gid=9999(docker) groups=9999(docker)

The test results above would be same for this version too.