Avoiding Permission Issues With Docker-Created Files

Permission denied
-rw-r--r-- 1 root root ...

Is this what you see when accessing files that were created from within your Docker container?

The user of the container (root in the worst case) is completely different than the one on the host. The file permissions and ownership are all wrong.

One frequent solution, is to “chown” your shared folder again and again. It’s tedious and there is a better way: read on to learn learn how to build, configure and run your Docker containers correctly, so you don’t have to fight permission errors and access your files easily.

First, let’s look at a “quick fix” which gets tedious quickly, before introducing better alternatives you want to use instead.

The “chown” method

Taking ownership of the files from your shared folder can be done with chown. Here is a simple example of creating a new file with wrong permissions:

$ docker run -it --rm \
  --mount "type=bind,src=$(pwd)/shared,dst=/opt/shared" \
  --workdir /opt/shared \
  ubuntu bash

# now we're root in the new container:
$ touch newfile

NOTE: if you’re using something like docker on mac, you won’t run into those permission issues, as the file sharing is done through NFS and your local files will have the right user.

We work on the shared folder, and create a file newfile from within a temporary container. As the container ran with the “root” user by default, we won’t be able to use those files from the host. One way to fix them temporarily, is to take ownership of them again and again and again:

$ chown -R hostuser:hostuser shared
...
$ chown -R hostuser:hostuser shared
...
$ chown -R hostuser:hostuser shared

If you want to write shared data from within your Docker container and use it from your host regularly, this can get tedious really fast. In addition, this approach can break the dockerized program for future runs, especially if the container’s user does not have root permissions.

You can do better.

Set the Docker user when running your container

You can run the ubuntu image with an explicit user id and group id.

$ docker run -it --rm \
  --mount "type=bind,src=$(pwd)/shared,dst=/opt/shared" \
  --workdir /opt/shared \
  --user "$(id -u):$(id -g)" \
  ubuntu bash

The difference is ‘–user “$(id -u):$(id -g)”’ - they tell the container to run with the current user id and group id which are obtained dynamically through bash command substitution by running the “id -u” and “id -g” and passing on their values.

This can be good enough already. The problem here is, that the user and group don’t really exist in the container. This approach works for the terminal command, but the session looks broken and you’ll see some ugly error messages like:

"groups: cannot find name for group ID"
"I have no name!"
  - your container, complaining

While bash works, some apps might refuse to run if those configs look fishy.

Build the right image

Now it gets more interesting. Here is how you can build, configure and run your Docker containers correctly, so you don’t have to fight permission errors and access your files easily.

As you should create a non-root user in your Dockerfile in any case, this is a nice thing to do. While we’re at it, we might as well set the user id and group id explicitly.

Here is a minimal Dockerfile which expects to receive build-time arguments, and creates a new user called “user”:

FROM ubuntu

ARG USER_ID
ARG GROUP_ID

RUN addgroup --gid $GROUP_ID user
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user
USER user

(check out https://stackoverflow.com/questions/27701930/add-user-to-docker-container for more info on adduser)

We can use this Dockerfile, to build a fresh image with the host uid and gid. This image, needs to be built specifically for each machine it will run on to make sure everything is in order.

Then, we can run use this image for our command. The user id and group id are correct without having to specify them when running the container.

$ docker build -t myimage \
  --build-arg USER_ID=$(id -u) \
  --build-arg GROUP_ID=$(id -g) .
$ docker run -it --rm \
  --mount "type=bind,src=$(pwd)/shared,dst=/opt/shared" \
  --workdir /opt/shared \
  myimage bash

No need to use “chown”, and no annoying permission errors anymore!

In Conclusion

In this article, we have looked at a few methods how to write files with correct permissions from Docker containers to your local host.

Instead of using chown over and over, you can either build a correctly configured image, or specify fitting user and group ids when running your Docker containers.

I hope these instructions have helped you to see what options you have so you won’t have problems to work on files which were generated from within your Docker containers in the future.

Subscribe to my newsletter!
You'll get notified via e-mail when new articles are published. I mostly write about Docker, Kubernetes, automation and building stuff on the web. Sometimes other topics sneak in as well.

Your e-mail address will be used to send out summary emails about new articles, at most weekly. You can unsubscribe from the newsletter at any time.

Für den Versand unserer Newsletter nutzen wir rapidmail. Mit Ihrer Anmeldung stimmen Sie zu, dass die eingegebenen Daten an rapidmail übermittelt werden. Beachten Sie bitte auch die AGB und Datenschutzbestimmungen .

vsupalov.com

© 2024 vsupalov.com. All rights reserved.