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, justCOPY
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
Dos2Unix: Binary Symbol Found, Skipping Binary File
Setting Environment Variable with Leading Digit in Bash
Dynamic Listening Ports Inside Docker Container
Programmatically Disable Hardware Prefetching on Amd Systems
Linux Kernel Changing Default CPU Scheduler
How Linux Scheduler Schedules Processes on Multi-Core Processors
Convert Charset from a Entire Project to Utf-8
Upgrading PHPmyadmin (And Other Packages) on Debian Squeeze
Gdb/Ddd Program Received Signal Sigill
How to Remove Warning: Link.Res Contains Output Sections; Did You Forget -T
Why Doesn't Time() from Time.H Have a Syscall to Sys_Time
How to Create a Core File for My Crashed Program