why doesn't chown work in Dockerfile?
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.
Solution 1:
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.
Solution 2:
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.
Solution 3:
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.
Solution 4:
In my experience, chown
does not work when mounting to root (VOLUME /test
). Use a non-root location (VOLUME /var/test
).