Velvet Star Monitor

Standout celebrity highlights with iconic style.

updates

why doesn't chown work in Dockerfile? [closed]

Writer Sebastian Wright

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.

1

6 Answers

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.

10

This blog 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.

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.

1

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

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

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