111

My Dockerfile creates a directory, chown's it, and then lists the directory afterwards. The directory is still owned by root. Why is that?

Here is the Dockerfile:

FROM ubuntu:precise
RUN useradd -d /home/testuser -m -s /bin/bash testuser
RUN mkdir -p /var/local/testrunner/logs
VOLUME ["/var/local/testrunner/logs"]
RUN grep testuser /etc/passwd
RUN grep root /etc/passwd
RUN chown -R testuser:testuser /var/local/testrunner/logs
RUN ls -ld /var/local/testrunner/logs 

Here is the output from "docker build":

Sending build context to Docker daemon 10.24 kB
Sending build context to Docker daemon 
Step 0 : FROM ubuntu:precise
 ---> ab8e2728644c
Step 1 : RUN useradd -d /home/testuser -m -s /bin/bash testuser
 ---> Using cache
 ---> 640f12671c86
Step 2 : RUN mkdir -p /var/local/testrunner/logs
 ---> Using cache
 ---> bf7756fd5b1f
Step 3 : VOLUME ["/var/local/testrunner/logs"]
 ---> Using cache
 ---> 65c73ee76c20
Step 4 : RUN grep testuser /etc/passwd
 ---> Using cache
 ---> db72fff0b965
Step 5 : RUN grep root /etc/passwd
 ---> Running in ebff78df7a9a
root:x:0:0:root:/root:/bin/bash
 ---> ead0ff704a59
Removing intermediate container ebff78df7a9a
Step 6 : RUN chown -R testuser:testuser /var/local/testrunner/logs
 ---> Running in c925f67b2ab4
 ---> 253132be935e
Removing intermediate container c925f67b2ab4
Step 7 : RUN ls -ld /var/local/testrunner/logs
 ---> Running in 978bc66aa47e
drwxr-xr-x 2 root staff 4096 Oct  1 15:15 /var/local/testrunner/logs

Docker version 1.2.0, build fa7b24f

The host runs Ubuntu 12.04, but with a 3.13.0-36-generic kernel.

user100464
  • 17,331
  • 7
  • 32
  • 40

6 Answers6

162

Answering my own question: it's declared to be a volume. If you take out the VOLUME instruction, the chown takes effect.

What's more, if you declare the volume after running chown, the chown settings remain in effect.

user100464
  • 17,331
  • 7
  • 32
  • 40
  • 24
    "If you declare the volume after running chown, the chown settings remain in effect" This just answered something that's had me stumped for two days. Thank you! – CashIsClay Dec 03 '14 at 04:52
  • 1
    @user100464 I wonder if there is a reasonable explanation for this quite odd behavior. It seems you only figured this out by trial & error. Or is this documented somewhere? – Michael Härtl Feb 11 '15 at 12:09
  • 2
    Answering myself: The explanation here made sense to me http://container-solutions.com/2014/12/understanding-volumes-docker/ – Michael Härtl Feb 11 '15 at 14:48
  • 1
    If I mount volume to container, perm switch back to `root:root`. I use `CMD chown -R user:user /path/to/dir && gosu user command` to solve this problem. – kev Jun 11 '15 at 11:40
  • 5
    An important point from that article above: "[When `VOLUME` is specified after a `RUN` command that modifies the volume], docker is clever enough to copy any files that exist in the image under the volume mount into the volume and set the ownership correctly. **This won’t happen if you specify a host directory for the volume (so that host files aren’t accidentally overwritten).**" – Gezim Feb 27 '16 at 17:49
  • Thanks for answering your own question and saving some of my hair – MauricioOtta Apr 11 '16 at 08:11
  • 5
    Updated URL for explanation linked by @MichaelHärtl is: https://blog.container-solutions.com/understanding-volumes-docker – Kamafeather Jan 22 '20 at 10:16
  • Tremendous! A double answer! – jouell Feb 23 '20 at 15:55
  • 10
    I don't declare any VOLUME on my dockerfile and still have this issue... :-( – fccoelho Mar 01 '20 at 19:57
  • @fccoelho - found any solution? – Nihal Sharma Apr 06 '20 at 18:03
10

This blog http://container42.com/2014/11/03/docker-indepth-volumes/ explains this behaviour in detail.

Each instruction in the Dockerfile creates a new container. The instruction make some changes to this container and becomes a new layer. The changes made to "/var/local/testrunner/logs" before VOLUME instruction were made to the actual container filesystem. However, after VOLUME instruction, the directory "/var/local/testrunner/logs" is the mounted directory. The changes made to this directory after VOLUME instruction will apply on the mounted directory and not the actual container filesystem.

hobgoblin
  • 865
  • 1
  • 10
  • 18
8

For anyone experiencing this issue without volumes, I found a convoluted work around.

Problem:

With a simple Dockerfile as follows:

FROM ubuntu:16.04
RUN useradd -m -d /home/new_user new_user
COPY test_file.txt /home/new_user
RUN chown -R new_user:new_user /home/new_user
CMD ls -RFlag /home

After running:

echo "A file to test permissions." > test_file.txt
docker build -t chown-test -f Dockerfile .
docker run --rm -it chown-test

The output was:

/home:
total 12
drwxr-xr-x 1 root 4096 Jun 15 21:37 ./
drwxr-xr-x 1 root 4096 Jun 15 21:39 ../
drwxr-xr-x 1 root 4096 Jun 15 21:39 new_user/

/home/new_user:
total 24
drwxr-xr-x 1 root 4096 Jun 15 21:39 ./
drwxr-xr-x 1 root 4096 Jun 15 21:37 ../
-rw-r--r-- 1 root  220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 root 3771 Aug 31  2015 .bashrc
-rw-r--r-- 1 root  655 Jul 12  2019 .profile
-rw-r--r-- 1 root   28 Jun 11 19:48 test_file.txt

As you can see the file ownership (e.g. test_file.txt) is still associated with user root.

Solution:

I found that if I used a numeric UID in the chown command, I could change the ownership, but only if the UID was not 1000. So I added 1 to the UID of new_user and then changed the ownership.

FROM ubuntu:16.04
RUN useradd -m -d /home/new_user new_user
# change the uid of new_user to ensure it has whatever it was assigned plus 1 (e.g. if UID was 1000, now it'll be 1001)
RUN id -u new_user | awk '{print $1+1}' | xargs -I{} usermod -u {} new_user
COPY test_file.txt /home/new_user
RUN id -u new_user | xargs -I{} chown -R {}:{} /home/new_user
CMD ls -RFlag /home

After running:

echo "A file to test permissions." > test_file.txt
docker build -t chown-test -f Dockerfile .
docker run --rm -it chown-test

The output was:

/home:
total 12
drwxr-xr-x 1 root 4096 Jun 15 21:37 ./
drwxr-xr-x 1 root 4096 Jun 15 21:37 ../
drwxr-xr-x 1 1001 4096 Jun 15 21:37 new_user/

/home/new_user:
total 24
drwxr-xr-x 1 1001 4096 Jun 15 21:37 ./
drwxr-xr-x 1 root 4096 Jun 15 21:37 ../
-rw-r--r-- 1 1001  220 Aug 31  2015 .bash_logout
-rw-r--r-- 1 1001 3771 Aug 31  2015 .bashrc
-rw-r--r-- 1 1001  655 Jul 12  2019 .profile
-rw-r--r-- 1 1001   28 Jun 11 19:48 test_file.txt

I'm not sure why I was having this issue in the first place. However, since it appears others have had this issue, I thought I'd post my workaround. My use case was creating a docker container that served a jupyter notebook. I created a non-root user to serve the notebook.

Hari S. Khalsa
  • 121
  • 1
  • 4
  • 2
    Manually modifying the UID with `usermod` file is an ugly hack. You can specify the UID at creation with `useradd -u 1001` – tripleee Apr 22 '22 at 03:55
  • You're right, it is a "hack", which is one of the reasons why I described this as "convoluted" in the first place. The reason, I used `usermod` was because I couldn't be certain that 1001 would always be available. Imagine if the author of the Dockerfile was adding multiple new users. This may avoid the problem altogether, but I didn't do enough testing to be sure. I'd be careful bandying about the term "ugly", it feels less constructive and more like a violation of the [be nice principle](https://stackoverflow.com/help/behavior). – Hari S. Khalsa Dec 15 '22 at 17:53
  • The same basically holds for the user name; what if `new_user` already exists? But you have explained it well enough that any competent reader should probably be able to sort out these corner cases. – tripleee Dec 17 '22 at 11:30
  • 1
    @tripleee I thought about editing the answer in response to your initial comment, but didn't because I settled on the same opinion as you, i.e. "any competent reader should probably be able to sort out these corner cases." I figured, between the hack I offered and your comment, readers would have two options. Thanks again. I just wish I could offer a deeper explanation for why `chown` wasn't working in the first place. – Hari S. Khalsa Dec 19 '22 at 05:12
  • 1
    If you have also been losing your hair over this recently (Aug 2023), take a look at this: https://bugs.launchpad.net/ubuntu/+source/docker.io-app/+bug/2029523 – Damien Aug 16 '23 at 18:08
  • Thank you very much, @Damien. We stumbled across this bug when we made another change to our build pipeline and it caused us a tremendous amount of issues in the past week. (I even reset my password just to upvote your comment) – ercpe Aug 22 '23 at 15:18
3

In my experience, chown does not work when mounting to root (VOLUME /test). Use a non-root location (VOLUME /var/test).

Mike
  • 843
  • 7
  • 13
1

if you are using volumen, you can set permission after running, like this:

docker exec -u 0 my-container chmod -R 700 /my/path
docker exec -u 0 my-container chown -R my-non-user-root /my/path
Adán Escobar
  • 1,729
  • 9
  • 15
0

For Alpine Linux users, I had to do chown -R root . in the workspace I was trying to own. This had to be done in the CMD of the dockerfile, as I believe the volume mounts may overwrite files when mounting

mateos
  • 1,405
  • 1
  • 17
  • 26