Telling Docker Who You Are

by Christoph Schiessl on DevOps and Docker

Did you ever notice that if you create files on a Docker bind mount from within a container, they all belong to root on the host system? This behavior can lead to permission problems if, for instance, you depend on Docker to automate parts of your build pipeline.

Let me start with some background information about user management on Linux. Internally, Linux maps user names to user IDs (aka UIDs) and group names to group IDs (aka GIDs). ID 0 is special for users and groups because it identifies the root user and the root group. This is hard-coded in the kernel and is true on all Linux systems - even inside Docker containers.

With id, it's straightforward to find the UID/GID of a given user:

$ echo "My UID is $(id -u), and my GID is $(id -g)."
My UID is 1000, and my GID is 1000.
$ echo "root's UID is $(id -u root), and root's GID is $(id -g root)."
root's UID is 0, and root's GID is 0.

Similarly, you can use stat to find the owner of files and directories:

$ touch first-experiment
$ stat --format="Owner UID is %u, and owner GID is %g." first-experiment
Owner UID is 1000, and owner GID is 1000.

Alright, that's all the background information you need to know. Now, let's create a simple Docker image and run our first experiment:

FROM alpine:latest

WORKDIR /work
VOLUME /work

ENTRYPOINT ["sh", "-c"]
$ echo "My UID is $(id -u), and my GID is $(id -g)."
My UID is 1000, and my GID is 1000.
$ docker build -t bugfactory/permission-test .
[[[ ... output removed ... ]]]
$ docker run --volume $(pwd):/work \
             bugfactory/permission-test \
             "touch second-experiment"
$ stat --format="Owner UID is %u, and owner GID is %g." second-experiment
Owner UID is 0, and owner GID is 0.

Our command successfully created the file second-experiment, but the file belongs to root as indicated by the UID/GID in the output's last line. As it turns out, Docker runs commands as root by default. To tell Docker to use a different UID/GID, we can use its --user UID:GID flag. On the man page for docker run, this is documented as follows:

-u, --user=""
   Sets the username or UID used and optionally the groupname or GID for the specified command.

Knowing about --user and id, we can compose an option such that Docker always runs commands as the user who invoked docker run on the host system: --user $(id -u):$(id -g). Let's try this:

$ echo "My UID is $(id -u), and my GID is $(id -g)."
My UID is 1000, and my GID is 1000.
$ docker run --volume $(pwd):/work \
             --user $(id -u):$(id -g) \
             bugfactory/permission-test \
             "touch third-experiment"
$ stat --format="File owner UID is %u, and owner GID is %g." third-experiment
File owner UID is 1000, and owner GID is 1000.

As before, the command successfully created the file third-experiment, but this time, it belongs to our UID/GID, as proven by the output's last line. Problem solved!

Web App Reverse Checklist

Ready to Build Your Next Web App?

Get my Web App Reverse Checklist first ...


Software Engineering is often driven by fashion, but swimming with the current is rarely the best choice. In addition to knowing what to do, it's equally important to know what not to do. And this is precisely what my free Web App Reverse Checklist will help you with.

Subscribe below to get your free copy of my Reverse Checklist delivered to your inbox. Afterward, you can expect one weekly email on building resilient Web Applications using Python, JavaScript, and PostgreSQL.

By the way, it goes without saying that I'm not sharing your email address with anyone, and you're free to unsubscribe at any time. No spam. No commitments. No questions asked.

Continue Reading?

Here are a few more Articles for you ...


How to Find the First/Last Day of a Year from a given Date

Learn how to find the first and last day of a year with Python's datetime module. This article explains step by step what you need to know.

By Christoph Schiessl on Python

How to Avoid Conflicts and Let Your OS Select a Random Port

Learn how to have your OS randomly select a port number for your web server to get around the issue of hard-coded ports during development.

By Christoph Schiessl on Python, FastAPI, and DevOps

Portability via Static Linking of libpq

Learn how to remove LDAP support from PostgreSQL packages to remove indirect dependencies, thereby making your programs more portable across systems.

By Christoph Schiessl on DevOps, PostgreSQL, and Docker

Christoph Schiessl

Hi, I'm Christoph Schiessl.

I help you build robust and fast Web Applications.


I'm available for hire as a freelance web developer, so you can take advantage of my more than a decade of experience working on many projects across several industries. Most of my clients are building web-based SaaS applications in a B2B context and depend on my expertise in various capacities.

More often than not, my involvement includes hands-on development work using technologies like Python, JavaScript, and PostgreSQL. Furthermore, if you already have an established team, I can support you as a technical product manager with a passion for simplifying complex processes. Lastly, I'm an avid writer and educator who takes pride in breaking technical concepts down into the simplest possible terms.