Why does Docker mount volume as root, not as user which has run command docker run? Can this be changed by setting some parameters/arguments, etc.?

MWE:

$ ls -ladrwxr-xr-x 2 ubuntu ubuntu 4096 Aug 22 18:09 shinylog$ docker run -v $(pwd)/test_dir/:/home/ --name nginx -d nginxbf340face11485a81ee7c208d490f11abbdc84089ffe9c01d71ffcf8b9ffc27d$ ls -ladrwxr-xr-x 2 ubuntu ubuntu 4096 Aug 22 18:09 shinylogdrwxr-xr-x 2 root root 4096 Aug 22 18:33 test_dir$ echo $USERubuntu

EDIT:After installing docker I encountered error:

Got permission denied while trying to connect to the Docker daemon socket at unix:///var/run/docker.sock: Get http://%2Fvar%2Frun%2Fdocker.sock/v1.38/containers/json: dial unix /var/run/docker.sock: connect: permission denied

and performed:

sudo usermod -a -G docker $USER

Maybe that's the problem?

2

Best Answer


The docker command is an interface to the rest API of the dockerd daemon. This daemon is what is configuring volumes and performing the tasks to run the container. And in most installs today, this daemon is running as root.

With the host volumes, they are Linux bind mount with an extra feature. Normally with a bind mount, the source directory must already exist. But to improve usability, docker will create this directory for you if it doesn't already exist. It does that from the daemon, that's running as root.

While it may be useful to configure that folder as your current user, there are several challenges. First, the daemon doesn't necessarily know that uid/gid, it's not part of the rest API. Also the daemon isn't necessarily running on your local host, it may be an API call to a remote host. And the user on your host doesn't necessarily match the user in the container.

The ideal solution is to create the directory in advance with the needed permissions and ownership. Or you can switch to named volumes, which have a convenient feature where docker will copy the contents of the image at that location to initialize the volume, including ownership and permissions (this happens when the volume is empty and the container is being created, so it does not receive updates when you have a new image). One last option is to start your container as root, but fix the permissions with an entrypoint script, and then use a command like gosu to change to a non-root user to run the app.

The process running nginx is running under root so it is writing the files using the UID of root.

Solution

export UID && docker run -v $(pwd)/test_dir/:/home/ -u=$UID:$UID --name nginx -d nginx

This will run the nginx process with your local UID and thus write the files with the same user. I have not tested under mac but this is a common solution/setup on linux so it will work for you.

How can you verify if this is working?

Run the nginx with a sleep to make it run for a long time, even if the configuration is wrong.

export UID && docker run -v $(pwd)/test_dir/:/home/ -u $UID:$UID --name nginx -d nginx sleep 3000000000000

Now exec in the container and run whoami to verify the uid of the user. For instance on my machine

docker exec -it nginx /bin/bashI have no name!@f12fa9c368e6:/$ whoamiwhoami: cannot find name for user ID 501