Running a Docker container as a non-root user

Image for post
Image for post
Containerbow” by Michael Phillips Photography

The Problem: Docker writes files as root

Sometimes, when we run builds in Docker containers, the build creates files in a folder that’s mounted into the container from the host (e.g. the source code directory). This can cause us pain, because those files will be owned by the root user. When an ordinary user tries to clean those files up when preparing for the next build (for example by using git clean), they get an error and our build fails.

  • We could tell Git to ignore the affected files, but that carries the risk that they’ll hang around in the file system and have an effect on future builds. We’ve encountered that problem in the past at Redbubble, so we are wary about letting that happen again.
  • We could clean up the files at the end of the build, while we’re still running our Dockerised process. But that would require us to implement lots of error trapping logic to ensure the cleanup happens, but still exit the build with the correct result.

Time to be someone else

Fortunately, docker run gives us a way to do this: the --user parameter. We're going to use it to specify the user ID (UID) and group ID (GID) that Docker should use. This works because Docker containers all share the same kernel, and therefore the same list of UIDs and GIDs, even if the associated usernames are not known to the containers (more on that later).

docker container run --rm -it \
-v $(app):/app \ # Mount the source code
--workdir /app \ # Set the working dir
--user 1000:1000 \ # Run as the given user
my-docker/my-build-environment:latest \ # Our build env image
make assets # ... and the command!

But I just want to be me!

But what if we don’t know the current user’s ID? Is there some way to automatically discover that?

docker-compose

We often like to run our tests and things using docker-compose, so that we can spin up any required services as needed - databases and so on. So wouldn't it be nice if we could do this with docker-compose as well?

# This is an abbreviated example docker-compose.yml
version: '3.3'
services:
rspec:
image: my-docker/my-build-environment:latest
environment:
- RAILS_ENV=test
command: ["make", "assets"]
# THIS BIT!!!1!
user: ${CURRENT_UID}
volumes:
- .:/app

Gotchas

Your user will be $HOME-less

What we’re actually doing here is asking our Docker container to do things using the ID of a user it knows nothing about, and that creates some complications. Namely, it means that the user is missing some of the things we’ve learned to simply expect users to have — things like a home directory. This can be troublesome, because it means that all the things that live in $HOME — temporary files, application settings, package caches — now have nowhere to live. The containerised process just has no way to know where to put them.

Your user will be nameless, too

It also turns out that we can’t easily share usernames between a Docker host and its containers. That’s why we can’t just use docker run --user=$(whoami) — the container doesn't know about your username. It can only find out about your user by its UID.

Wrapping up

We now have a way to use docker run and docker-compose to create files, without having to use sudo to clean them up!

Redbubble

Creating the worlds largest marketplace for independent artists & bringing more creativity to all

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store