Docker with '-User' Can Not Write to Volume with Different Ownership

Docker with '--user' can not write to volume with different ownership

docker's --user parameter changes just id not a group id within a docker. So, within a docker I have:

id
uid=1002 gid=0(root) groups=0(root)

and it is not like in original system where I have groups=1000(users)

So, one workaround might be mapping passwd and group files into a docker.

-v /etc/docker/passwd:/etc/passwd:ro -v /etc/docker/group:/etc/group:ro

The other idea is to map a tmp directory owned by running --user and when docker's work is complete copy files to a final location

 TMPFILE=`mktemp`; docker run -v $TMPFILE:/working_dir/ --user=$(id -u); cp $TMPDIR $NEWDIR

This discussion Understanding user file ownership in docker: how to avoid changing permissions of linked volumes brings some light to my question.

docker can not write on mounted volume with non-root user

Most propably the UID on your host for myuser does not match the UID for myuser inside the Container.

Solution

If you want to write from within your container into a directory of your host machine you must first create a myuser User on your host and check its UID via

$ sudo su - myuser -c "id"
uid=1000(myuser) gid=100(users) Gruppen=100(users)

In this example UID=1000 and GID=100.

Now you will need to create a Folder ~/log/nginx with owner/group of myuser on your host.

$ sudo mkdir ~/log/nginx
$ sudo chown myuser ~/log/nginx
$ sudo chmod -R 0700 ~/log/nginx/

Afterwards you can create a Dockerfile and your user with the same UID/GID.

RUN useradd myuser -u 1000 -g 100 -m -s /bin/bash
USER myuser

Now you should be able to write to your mounted volume with the specified user. You can check this via:

docker run -v $(pwd)/log/nginx:/var/log/nginx --rm -it mynginx:v1 /bin/bash

if you can now write to /var/log/nginx

Docker: non-root user does not have writing permissions when using volumes

You can run the container as the user ID matching the host user ID owning the directory. Often this is the current user:

 docker run -u $(id -u) -v /host/path:/container/path ...

For this to work, your image needs to do a couple of things:

  • The data needs to be kept somewhere completely separate from the application code. A top-level /data directory as you show is a good choice.
  • The application proper should be owned by root, and world-readable but not world-writeable; do not RUN chown ... the application, just COPY it in and run its build sequence as root.
  • The image should create a non-root user, but it does not need to match any particular host user.
  • The image needs to create the data directory, but it should be completely empty.
  • The image startup (often an entrypoint wrapper script) needs to be able to populate the data directory if it is totally empty at startup time.
FROM some-base-image

# Do all of the initial setup and build as root
WORKDIR /app
COPY . .
RUN ...

# Create some non-root user that owns the data directory by default
RUN useradd -r myuser # no specific user ID
RUN mkdir /data && chown myuser /data
# VOLUME ["/data"] # optional, the only place VOLUME makes sense at all

# Specify how to run the container
USER myuser # not earlier than this
EXPOSE ... # optional but good practice
ENTRYPOINT ["/entrypoint.sh"] # knows how to seed /data, then `exec "$@"`
CMD my_app ... # a complete command line

Mounted Docker volume has different ownership when using Travis

Try running the docker again with this command, so the uid outside the container is propagated inside:

docker run -u `id -u`

alternative, as pointed by @anemyte:

docker run -u $(id -u)

This should involve the creation of the new files inside the docker to be owned by "jovyan".

If you are able to guess that mounting points will exist, you could also pre-create them so the ownership of the files inside is also correct:

docker run -v /path/on/host:/path/in/container ...

If you set the permissions of your local path (/path/on/host) as 777, that will also be propagated to the mounting point: no permission error will be thrown regardless of the user that docker uses to create those files.

After that, you'll be free to restore permissions, if needed.

Understanding user file ownership in docker: how to avoid changing permissions of linked volumes

Is that correct? Can someone point me to documentation of this, I'm just conjecturing based on the above experiment.

Perhaps this is just because they both have the same numerical value on the kernel, and if I tested on a system where my home user was not id 1000 then permissions would get changed in every case?

Have a read of info coreutils 'chown invocation', that might give you a better idea of how file permissions / ownership works.

Basically, though, each file on your machine has a set of bits tacked on to it that defines its permissions and ownership. When you chown a file, you're just setting these bits.

When you chown a file to a particular user/group using the username or group name, chown will look in /etc/passwd for the username and /etc/group for the group to attempt to map the name to an ID. If the username / group name doesn't exist in those files, chown will fail.

root@dc3070f25a13:/test# touch test
root@dc3070f25a13:/test# ll
total 8
drwxr-xr-x 2 root root 4096 Oct 22 18:15 ./
drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../
-rw-r--r-- 1 root root 0 Oct 22 18:15 test
root@dc3070f25a13:/test# chown test:test test
chown: invalid user: 'test:test'

However, you can chown a file using IDs to whatever you want (within some upper positive integer bounds, of course), whether there is a user / group that exists with those IDs on your machine or not.

root@dc3070f25a13:/test# chown 5000:5000 test
root@dc3070f25a13:/test# ll
total 8
drwxr-xr-x 2 root root 4096 Oct 22 18:15 ./
drwxr-xr-x 22 root root 4096 Oct 22 18:15 ../
-rw-r--r-- 1 5000 5000 0 Oct 22 18:15 test

The UID and GID bits are set on the file itself, so when you mount those files inside your docker container, the file has the same owner / group UID as it does on the host, but is now mapped to /etc/passwd in the container, which is probably going to be a different user unless it's owned by root (UID 0).

The real question is, of course, 'what do I do about this?' If bob is logged in as bob on the given host machine, he should be able to run the container as bob and not have file permissions altered under his host account. As it stands, he actually needs to run the container as user docker to avoid having his account altered.

It seems like, with your current set-up, you'll need to make sure your UIDs > usernames in /etc/passwd on your host match up to your UIDs > usernames in your containers /etc/passwd if you want to interact with your mounted user directory as the same user that's logged in on the host.

You can create a user with a specific user id with useradd -u xxxx. Buuuut, that does seem like a messy solution...

You might have to come up with a solution that doesn't mount a host users home directory.

Cannot change owner of Docker Volume directory to non-root user

When you declare a directory as a VOLUME, you effectively can't use it in a Dockerfile any more. The basic reason is that volumes are set up when the container is run, not built.

In this case, you could simply move the VOLUME statement to the end of the Dockerfile. Any data in the image at that directory will be copied into the volume when the container is started.

How to give non-root user in Docker container access to a volume mounted on the host

There's no magic solution here: permissions inside docker are managed the same as permissions without docker. You need to run the appropriate chown and chmod commands to change the permissions of the directory.

One solution is to have your container run as root and use an ENTRYPOINT script to make the appropriate permission changes, and then your CMD as an unprivileged user. For example, put the following in entrypoint.sh:

#!/bin/sh

chown -R appuser:appgroup /path/to/volume
exec runuser -u appuser "$@"

This assumes you have the runuser command available. You can accomplish pretty much the same thing using sudo instead.

Use the above script by including an ENTRYPOINT directive in your Dockerfile:

FROM baseimage

COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/bin/sh", "entrypoint.sh"]
CMD ["/usr/bin/myapp"]

This will start the container with:

/bin/sh entrypoint.sh /usr/bin/myapp

The entrypoint script will make the required permissions changes, then run /usr/bin/myapp as appuser.



Related Topics



Leave a reply



Submit