Workaround of permission issue in Docker Volume

Curious Dev
Curious Dev Grail
Published in
6 min readMay 10, 2019

If you are reading this post then i am assuming that you know what is Docker and how to work with docker and deploy containerized application, and about docker volume. If you still don’t know what is docker and how to use it. You won’t feel off with this post.

What is Docker?

Docker is a tool designed to make it easier to create, deploy, and run applications by using containers. Containers allow a developer to package up an application with all of the parts it needs, such as libraries and other dependencies, and ship it all out as one package.(From opensource.com)

Why you need docker?

Suppose you developed an application that required certain 3rd party libraries, and particular configuration of the OS that it can run on, along with your application source code. But you bought a cloud server that has neither those dependencies and has a different OS, which doesn’t support your application to run . One solution could be you install or either bought a new server and install those dependencies that are required by your application which will be time consuming as well as costly solution. The other could be using Container that could be provide the same configurations that are required by your application and install all the dependencies with a single command on the same host OS that you are currently having.(It is like a box that have all the items that you required to build the application and serve to the targeted user without ). And suppose if you need to clean up your host machine for a new application you just need to remove those container, and your host machine will be like the new one that you have bought, no manual removal of packages will be required.

What are docker Volume?

  • When a Docker container is deleted, relaunching the image will start a fresh container without any of the changes made in the previously running container — those changes are lost. Docker calls this combination of read-only layers with a read-write layer on top a Union File System. In order to be able to save (persist) data and also to share data between containers, Docker came up with the concept of volumes. Quite simply, volumes are directories (or files) that are outside of the default Union File System and exist as normal directories and files on the host filesystem.(From Container Solutions)

Now you might be thinking that what all you need is: a fully packaged application and Stable storage That let’s your application changes be persistent. Then wait!

What the issue is?

Every operation inside a container run as root user, whether it is the application specific like database changes and other operation like new file upload by user using your application that is hosted in containerized environment. So when a container volume is mounted on your host application any new file creation or any other changes that happens to your application is having root authorization, and whenever these newly created files are need to be manipulated within your host system. Either you need to change the authorization from root user to your host machine user, or provide the read write permission to groups and other

user, which is kind of bad idea since you don’t know when the new files will be created by your application.

Let me show this to you by a Simple flask application that let’s you upload new file in the application and is hosted within the container.

Dockerfile

FROM python:3.6
ADD src/requirements.txt /tmp/
RUN pip3 install -r requirements.txt
ADD . /usr/app
WORKDIR /usr/app/src/
ENTRYPOINT [“python3”]
CMD [“app.py”]

This will create an image having base image as python 3.6

docker-compose.yml

version: ‘1’
services:
fileService:
image: file-uploader
ports:
— “5000:5000”
volumes:
— .:/usr/app/
container_name: fileUploader

Now open terminal and execute commands

docker build -t file-uploader .
docker-compose up -d fileUploader

This will give you an application running on http://localhost:5000

And When you upload a file with it you The file will be uploaded and you will be redirected to URL that will display the file but when you go over directory and see the File Author and Permission. It is stated as below.

Now if you try to delete file You won’t be able to delete it due to not having permission .

How you could solve it?

Now there are number of solution like

  1. Changing Permission manually, whenever a new file is created.
  2. Mapping Host User to the Container User

Changing Permission Manually, whenever a new File is created

Since it’s the age of automation changing permission manually is very time consuming and you need to persistently check when a new file is created in the container. So what you can do is to create a Cron Job that will perform this. Enter this in Host Terminal:

$ sudo crontab -e

and enter following line to this

10 * * * * /bin/chown -R hostuser:hostUserGroup /home/hostuser/directory_where_file_will_be_created && /bin/chmod u+rw /home/hostuser/directory_where_file_will_be_created

This will change owner from root to hostuser, and group from root to hostUserGroup of that particular directory and give permission of rw to that user , in every 10 minute.

Mapping Host User to the Container User

To Map Host Machine user with the container user then the user id and group id of the host machine must be same as the user id and group id of the container machine. To do this let’s just modify our Dockerfile a bit

FROM python:3.6
ADD src/requirements.txt /tmp/
RUN pip3 install -r /tmp/requirements.txt
#added groupid argument with default value 9000 which can be manipulated while building image
ARG gid=9000
#added userid argument with default value 9000 which can be manipulated while building image
ARG uid=9000
#added new user dockerize with user id uid and group id gid
RUN addgroup --gid $gid dockerize && \
adduser --uid $uid --ingroup dockerize --home /home/dockerize --shell /bin/sh --disabled-password --gecos "" dockerize
ADD . /usr/app/
WORKDIR /usr/app/src/
#activate the user dockerize
USER dockerize
ENTRYPOINT ["python3"]
CMD ["app.py"]

The first thing added are two arguments gid and uid with default value 9000 that can be overridden while building container.

ARG gid=9000
ARG uid=9000

and then added user dockerize with user id uid and group id gid with following command:

RUN addgroup --gid $gid  dockerize && \
adduser --uid $uid --ingroup dockerize --home /home/dockerize --shell /bin/sh --disabled-password --gecos "" dockerize

and activate that dockerize user by default whenver container start by the following:

USER dockerize

then you need to build the container again but this time the command will vary and it looks like:

$ docker build --build-arg uid=$(id -u) --build-arg gid=$(id -g) -t file-uploader .

This will replace the two ARG declared in the Dockerfile by host system user id and group id and when you up the container by the command

$ docker-compose up -d fileService

now the container will be running with user dockerize having gid and uid as your host uid and gid . Now try uploading file again this time and check permission. You will see the owner of the file and group as your host system user and group

This time it will be same as your host machine (in my case its r-gaurav). Now you can read and write file easily as well.

But this Docker build command is long and error prone as well so instead you could build a Makefile that will just need two words to build container and image.

Makefile

image: Dockerfile src
docker build --build-arg uid=$$(id -u) --build-arg gid=$$(id -g) -t file-uploader .
container: docker-compose.yml
docker-compose up -d fileService

Now you just need to execute make image instead of docker build command and make container instead of docker-compose up

Hope You liked it. Share with your Devops Friends. All the source Code You can find here https://github.com/curious-dev-grail/persmission-issue-docker/.

--

--