What is the (best) way to manage permissions for Docker shared volumes?
UPDATE 2016-03-02: As of Docker 1.9.0, Docker has named volumes which replace data-only containers. The answer below, as well as my linked blog post, still has value in the sense of how to think about data inside docker but consider using named volumes to implement the pattern described below rather than data containers.
I believe the canonical way to solve this is by using data-only containers. With this approach, all access to the volume data is via containers that use -volumes-from
the data container, so the host uid/gid doesn't matter.
For example, one use case given in the documentation is backing up a data volume. To do this another container is used to do the backup via tar
, and it too uses -volumes-from
in order to mount the volume. So I think the key point to grok is: rather than thinking about how to get access to the data on the host with the proper permissions, think about how to do whatever you need -- backups, browsing, etc. -- via another container. The containers themselves need to use consistent uid/gids, but they don't need to map to anything on the host, thereby remaining portable.
This is relatively new for me as well but if you have a particular use case feel free to comment and I'll try to expand on the answer.
UPDATE: For the given use case in the comments, you might have an image some/graphite
to run graphite, and an image some/graphitedata
as the data container. So, ignoring ports and such, the Dockerfile
of image some/graphitedata
is something like:
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
RUN mkdir -p /data/graphite \
&& chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]
Build and create the data container:
docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata
The some/graphite
Dockerfile should also get the same uid/gids, therefore it might look something like this:
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
# ... graphite installation ...
VOLUME /data/graphite
USER graphite
CMD ["/bin/graphite"]
And it would be run as follows:
docker run --volumes-from=graphitedata some/graphite
Ok, now that gives us our graphite container and associated data-only container with the correct user/group (note you could re-use the some/graphite
container for the data container as well, overriding the entrypoing/cmd when running it, but having them as separate images IMO is clearer).
Now, lets say you want to edit something in the data folder. So rather than bind mounting the volume to the host and editing it there, create a new container to do that job. Lets call it some/graphitetools
. Lets also create the appropriate user/group, just like the some/graphite
image.
FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
&& useradd -r -g graphite graphite
VOLUME /data/graphite
USER graphite
CMD ["/bin/bash"]
You could make this DRY by inheriting from some/graphite
or some/graphitedata
in the Dockerfile, or instead of creating a new image just re-use one of the existing ones (overriding entrypoint/cmd as necessary).
Now, you simply run:
docker run -ti --rm --volumes-from=graphitedata some/graphitetools
and then vi /data/graphite/whatever.txt
. This works perfectly because all the containers have the same graphite user with matching uid/gid.
Since you never mount /data/graphite
from the host, you don't care how the host uid/gid maps to the uid/gid defined inside the graphite
and graphitetools
containers. Those containers can now be deployed to any host, and they will continue to work perfectly.
The neat thing about this is that graphitetools
could have all sorts of useful utilities and scripts, that you can now also deploy in a portable manner.
UPDATE 2: After writing this answer, I decided to write a more complete blog post about this approach. I hope it helps.
UPDATE 3: I corrected this answer and added more specifics. It previously contained some incorrect assumptions about ownership and perms -- the ownership is usually assigned at volume creation time i.e. in the data container, because that is when the volume is created. See this blog. This is not a requirement though -- you can just use the data container as a "reference/handle" and set the ownership/perms in another container via chown in an entrypoint, which ends with gosu to run the command as the correct user. If anyone is interested in this approach, please comment and I can provide links to a sample using this approach.
How to give folder permissions inside a docker container Folder
I guess you are switching to user "admin" which doesn't have the ownership to change permissions on /app directory. Change the ownership using "root" user. Below Dockerfile worked for me -
FROM python:2.7
RUN pip install Flask==0.11.1
RUN useradd -ms /bin/bash admin
COPY app /app
WORKDIR /app
RUN chown -R admin:admin /app
RUN chmod 755 /app
USER admin
CMD ["python", "app.py"]
PS - Try to get rid of "777" permission. I momentarily tried to do it in above Dockerfile.
How to manage permissions for a volume mounted into a docker container?
You can do this by overwriting the entrypoint for the wordpress image.
Create a file startup.sh in your project and make is executable:
#!/bin/bash
chown -R www-data:www-data /var/www/html/wp-content
docker-entrypoint.sh apache2-foreground
Then in your docker-compose.yml:
...
wordpress:
...
working_dir: /var/www/html
volumes:
- './my-theme:/var/www/html/wp-content/themes/my-theme'
- './startup.sh:/startup.sh'
entrypoint: /startup.sh
This worked for me, let me know if you have problems implementing it.
How to handle permissions for same non-root user on Docker & Host?
It turns out, we can sync the user inside the container and on host by bind mounting /etc/passwd and /etc/group.
Compose syntax is,
- type: bind
source: /etc/group
target: /etc/group
read_only: true
- type: bind
source: /etc/passwd
target: /etc/passwd
read_only: true
Docker permissions development environment using a host mounted volume
One of the solutions is to execure the commands inside your container. I've tried multiple workarounds for the same issue I faced in the past. I find executing the command inside the container the most user-friendly.
Example command: docker-compose run CONTAINER_NAME php bin/console cache:clear
. You may use make
, ant
or any modern tool to keep the commands short.
Example with Makefile
:
all: | build run test
build: | docker-compose-build
run: | composer-install clear-cache
############## docker compose
docker-compose-build:
docker-compose build
############## composer
composer-install:
docker-compose run app composer install
composer-update:
docker-compose run app composer update
############## cache
clear-cache:
docker-compose run app php bin/console cache:clear
docker-set-permissions:
docker-compose run app chown -R www-data:www-data var/logs
docker-compose run app chown -R www-data:www-data var/cache
############## test
test:
docker-compose run app php bin/phpunit
Alternatively, you may introduce a .env
file which contains a environment variables and then user one of the variables to run usermod
command in the Docker container.
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.
Related Topics
Individual Thread Priority Checking Using Command Line in Linux
Linux Async (Io_Submit) Write V/S Normal (Buffered) Write
Prevent Fork() from Copying Sockets
Error Message When Setting Up Adt in Linux
Delete Line from Text File with Line Numbers from Another File
Difference Between T and T in /Proc/Kallsyms
Find a Line in a File and Add Something to The End of The Line in Bash
What Happens Internally When Deleting an Opened File in Linux
Ssh Service Running on Multiple Ports with Custom Rules in Linux
Nasm Assembly Linux Timer or Sleep
Scale PDF to Add Border for Printing Full Size Pages
Pyinstaller on 32-Bit Linux - Importerror: The 'six' Package Is Required
How to Split Two Vertical Pane Inside a Horizontal Pane in Tmux Using Tmuxinator
/Usr/Local/Ssl/Lib/Libcrypto.A: Could Not Read Symbols: Bad Value
"Hello World" Function Without Using C Printf
Xargs and Find, Rm Complaining About \N (Newline) in Filename