Categories
Software

Improve your local web app development with Docker

Host file permissions

This is all looking great now, but you may have noticed an issue when editing mounted files from the host machine. Docker creates files with the user assigned within the container, meaning that you are likely to get permissions errors if you try and edit files that were created in the container first (e.g. try editing go.mod in your host’s file editor/IDE).

One way of fixing this is to chown the file or directory whenever you encounter this permissions issue:

$ sudo chown $USER <filename>

This is only a temporary fix though. A better solution is to build the container with a user that has the same username and ID as your host machine. So instead of using an image in the docker-compose file, we will create a Dockerfile with the build steps:

Dockerfile

FROM golang:1.14-alpine

## The below is a mix of:
## https://vsupalov.com/docker-shared-permissions/
## https://stackoverflow.com/a/55757473

ARG USER_ID
ARG USER

RUN adduser --disabled-password --gecos "" --uid $USER_ID $USER

USER $USER

This creates a non-root user with the build arguments USER_ID and USER, and sets that user to be the one for running future commands. We then change the docker-compose file to use build instead of image:

docker-compose.yaml

version: '3'

services:
  app:
    working_dir: /app
    stdin_open: true
    build: ./
    volumes:
      - ./:/app
    env_file:
      - .env
    ports:
      - ${HTTP_PORT}:${HTTP_PORT}

  redis:
    command: redis-server --port ${REDIS_PORT}
    image: redis:6.0-alpine
    env_file:
      - .env
    ports:
      - ${REDIS_PORT}:${REDIS_PORT}

Now we build the container with a command that passes the current $USER and user ID in:

$ docker-compose build --build-arg USER=$USER --build-arg USER_ID=$(id -u)

And when starting the application, you should no longer encounter these permissions issues. 👌

Closing thoughts

Over the course of this article, we’ve learned how to set up a containerized app that works for local development, allowing future developers to get productive quickly. Hopefully this will enable you to make the local development experience for other members of your team more enjoyable and more consistent!

For a full reference to the final code — which has make targets for running the commands more easily, as well as some other tweaks — check out my Github repository.

Helpful resources