Avoid Docker root ownership
On Linux, the docker daemon typically runs as root. This is troublesome when using
Docker to generate files to place on the host system using a bind mount. I ran
into this issue generating .deb
packages to deploy a server binary. I
generated the .deb
packages in a Docker file using FPM and then placed them
onto the host machine. Since Docker runs as root, the generated .deb
files are
also owned by root, which means I can't delete them as a normal user without
sudo
. As a quick example:
docker run --rm\ --mount 'type=bind,source=/tmp,destination=/tmp' \ alpine \ /bin/sh -c 'echo "docker owned" > /tmp/docker-owned.txt'
The resulting file permissions show the Docker container created file is indeed owned by root:
$ ls -alh /tmp/docker-owned.txt -rw-r--r-- 1 root root 13 Oct 3 00:30 /tmp/docker-owned.txt
Luckily, we can control the user ID (UID) and group ID (GID) that docker uses in the Docker image by creating the user in the Dockerfile with a user ID that matches the host user. Docker shares the same user ID space as the host machine, so if we run a Docker container with the same user ID as the current user, any files created by the container will be owned by the current user. To start, we need a Dockerfile to create the user with the a UID that matches the current host user's UID.
FROM alpine # Default to root if build args aren't set. ARG USER_ID=0ARG GROUP_ID=0ARG USER_NAME=root# Create the user matching the build arg USER_ID. RUN set -eux;\ if [ $USER_ID != 0 ];then \ adduser --disabled-password --gecos '' --uid $USER_ID $USER_NAME;\ fi ;# Run this image using the user name associated with the same USER_ID passed # via a build arg variable. USER $USER_NAME
We'll create the image by passing in the current user ID, group ID, and user name into the Docker build command:
docker build\ --build-arg USER_ID= " $( id -u) " \ --build-arg GROUP_ID= " $( id -g) " \ --build-arg USER_NAME= "user" \ --tag tmp-docker-root-ownership - < /tmp/nonroot.Dockerfile
Finally, verify that the files created in the container are owned by the current user:
docker run --rm\ --mount'type=bind,source=/tmp,destination=/tmp' \ tmp-docker-root-ownership \ /bin/sh -c 'echo "docker owned" > /tmp/docker-owned-new.txt' ls -alh /tmp/docker-owned-new.txt -rw-r--r-- 1 joe joe 13 Oct 3 00:51 /tmp/docker-owned-new.txt
Debian setup¶
The Debian setup is similar to Alpine with some added niceties for sudo taken from StackOverflow: How to use sudo in a non-root Docker container
FROM debian # Default to root if build args aren't set. ARG USER_ID=0ARG GROUP_ID=0ARG USER_NAME=root# Create the user, granting sudo permisions. RUN set -eux;\ if [ $USER_ID != 0 ];then \ addgroup --gid $GROUP_ID $USER_NAME; \ adduser --disabled-password --gecos '' --uid $USER_ID\ --gid $GROUP_ID $USER_NAME; \ adduser $USER_NAME sudo; \ echo '%sudo ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers;\ fi ;# Run this image using the user name associated with the same USER_ID passed # via a build arg variable. USER $USER_NAME
docker build\ --build-arg USER_ID= " $( id -u) " \ --build-arg GROUP_ID= " $( id -g) " \ --build-arg USER_NAME= "user" \ --tag tmp-debian-docker-root-ownership - \ < /tmp/debian-non-root.Dockerfile docker run --rm \ --mount'type=bind,source=/tmp,destination=/tmp' \ tmp-debian-docker-root-ownership \ /bin/sh -c 'echo "docker owned" > /tmp/docker-owned-debian.txt' ls -alh /tmp/docker-owned-new-debian.txt -rw-r--r-- 1 joe joe 13 Oct 3 00:59 /tmp/docker-owned-debian.txt