DEV Community

Malte Riechmann for visuellverstehen

Posted on • Edited on • Originally published at happy-coding.visuellverstehen.de

Docker, Docker Compose and permissions

Introduction

Docker and Docker Compose are awesome. Just yesterday I had to install a software to create a user interface on top of the software's API. It took me only minutes to download the Dockerfile, add some configuration using Docker Compose, build the image and run the container. I am super happy Docker and Docker Compose exist, but I would like to see some improvements on macOS.

The concept of users, groups and file permissions is awesome, too. If you are new to this, I would recommend this article, that covers all the basics.

The problem

Last year I switched from macOS to Linux because of some performance issues. The switch definitely improved speed and stability of Docker volumes, but I kept running into a problem which did not occur on macOS: Broken file permissions.

When using Docker on macOS the file permissions do not get synchronized between your local machine and docker containers. On Linux file permissions get synchronized, which in my opinion is actually the way it should be for all operating systems.

This was a huge problem.

If I changed files locally, the file permissions would get changed inside of the container with user and group which did not even exist inside of the container.

If I changed files inside of the container using the only existing root user, the file permissions would also get changed on my local machine to root:root.

At the time a configuration looked roughly like the following:

Click to open Dockerfile
# Define base image FROM php:8.0-cli-buster 

Click to open docker-compose.yml
version: '3.3' networks: web: external: true services: application: container_name: application build: context: . dockerfile: ./Dockerfile networks: - web volumes: - ./:/var/www/html/ restart: always 

We used to run commands like this:

docker-compose exec application bash 
Enter fullscreen mode Exit fullscreen mode

The solution

Create a user and a group inside of the Docker container with the same IDs you are using locally. When this is done file permissions can be synchronized, because the same user and group is used.

At first you have to export your user and group ID in your shell configuration (e. g. ~/.zshrc or ~/.bashrc):

# Export variables for Docker and Docker Compose export USER_ID=$(id -u) export GROUP_ID=$(id -g) 
Enter fullscreen mode Exit fullscreen mode

Now our configuration looks roughly like this:

Click to open Dockerfile
# Define base image FROM php:8.0-cli-buster # Define build arguments ARG USER_ID ARG GROUP_ID # Define environment variables ENV USER_ID=$USER_ID ENV GROUP_ID=$GROUP_ID ENV USER_ID=${USER_ID:-1001} ENV GROUP_ID=${GROUP_ID:-1001} # Add group and user based on build arguments RUN addgroup --gid ${GROUP_ID} alice RUN adduser --disabled-password --gecos '' --uid ${USER_ID} --gid ${GROUP_ID} alice # Set user and group of working directory RUN chown -R alice:alice /var/www/html 

Click to open docker-compose.yml
version: '3.3' networks: web: external: true services: application: container_name: application build: context: . dockerfile: ./Dockerfile args: USER_ID: $USER_ID GROUP_ID: $GROUP_ID networks: - web volumes: - ./:/var/www/html/ restart: always 

From now on you have to execute commands inside of the container using the newly generated user. We now run commands like this:

docker-compose exec --user alice application bash 
Enter fullscreen mode Exit fullscreen mode

Further reading

If you want to read more about our local development environment using Docker and Docker Compose, have a look at an article a colleague of mine wrote a while ago.

Top comments (3)

Collapse
 
chrisjimallen profile image
Chris Allen

I've been struggling with this issue for a week, after switching from Vagrant. I'll try this with my WordPress site and see how I get on. One issue I need to consider is making the nginx container be able to write to the files, eg. when installing plugins or saving permalinks etc.

Currently, my host file permissions for my files are chrisallen:chrisallen, so will I need to chown them to be chrisallen:www-data, in order for my container to have write access? Or perhaps I could try just adding my own host user to the www-data group.

Did you find a workable solution for the above?

Collapse
 
malteriechmann profile image
Malte Riechmann visuellverstehen • Edited

Hi Chris, we have a working solution for our local development environment. We just tell Nginx and PHP-FPM to run as »chrisallen«. Below you can have a look at a simplified version of our Dockerfile.

# Define base image FROM php:8.1-fpm-alpine # Define build arguments ARG USER_ID ARG GROUP_ID # Define environment variables ENV USER_NAME=chrisallen ENV GROUP_NAME=chrisallen ENV USER_ID=$USER_ID ENV GROUP_ID=$GROUP_ID ENV USER_ID=${USER_ID:-1001} ENV GROUP_ID=${GROUP_ID:-1001} # Add group and user based on build arguments RUN addgroup --gid ${GROUP_ID} ${GROUP_NAME} RUN adduser --disabled-password --gecos '' --uid ${USER_ID} --ingroup ${GROUP_NAME} ${USER_NAME} # Set user and group of working directory RUN chown -R chrisallen:chrisallen /var/www/html # Update and install packages # […] # Install PHP extensions # […] # Set nginx and PHP-FPM user RUN sed -ri -e "s!user nginx!user ${USER_NAME}!g" /etc/nginx/nginx.conf RUN sed -ri -e "s!user = www-data!user = ${USER_NAME}!g" /usr/local/etc/php-fpm.d/www.conf RUN sed -ri -e "s!group = www-data!group = ${GROUP_NAME}!g" /usr/local/etc/php-fpm.d/www.conf # Manualy expose port 80 for outside access to nginx # […] # Copy configuration to application container # […] # Start nginx and PHP-FPM # […] 
Enter fullscreen mode Exit fullscreen mode

I hope this will help you.

Happy coding :)

Collapse
 
chrisjimallen profile image
Chris Allen

This is such a huge help, thanks for the personalised script ;) I'll try it out on the next setup.