I’m learning test-driven development with the course Microservices with Docker, Flask, and React.
It’s been a lot of fun. I’ve also learned more about using Docker and docker-compose.
The course uses Coverage.py for measuring Python code coverage.
However, Coverage.py and Docker don’t play well with each other if you run the Docker container as a normal (non-root) user.
PermissionError: [Errno 13] Permission denied: 'usr/src/app/.coverage'
Here is the Dockerfile:
## base image FROM python:3.7.2-slim ## install dependencies RUN apt-get update && \ apt-get -y install netcat && \ apt-get clean ## set working directory WORKDIR /usr/src/app ## add and install requirements COPY ./requirements.txt /usr/src/app/requirements.txt RUN pip install --upgrade pip && pip install -r requirements.txt ## add entrypoint.sh COPY ./entrypoint.sh /usr/src/app/entrypoint.sh RUN chmod +x /usr/src/app/entrypoint.sh ## add app COPY . /usr/src/app ## add user RUN addgroup --system user && adduser --system --group user RUN chown -R user:user /usr/src/app && chmod -R 755 /usr/src/app USER user ## run server CMD ["/usr/src/app/entrypoint.sh"]
As you can see, I add a normal user to the docker container, give them permission to the directory and run all following commands as non-root user.
Let’s say I run this command:
docker-compose exec users python manage.py coverage
My docker-compose config doesn’t specify a user. My Dockerfile (see above) switches to a non-root user.
Thus, my docker-compose commands run as non-root user.
docker-compose run --rm users sh -c "id -u -n" > user
According to my research, it is more secure to run applications inside of the container as non-root user.
The important detail is to run applications inside of your container as a non-root user. It’s the equivalent of systemd running as root and launching a program as a non-root user.
But now the permissions for Coverage.py don’t work.
This seems to be a common problem: Test coverage in a docker container.
Trying to give permissions to the non-root user via
chmod +x doesn’t work.
So, I need to run docker-compose as root user for Coverage.py.
I could add a
docker-compose.yml like so:
version: '3.7' services: users: user: root build: context: ./services/users dockerfile: Dockerfile (...rest of docker-compose file)
But I don’t want to run all commands as root.
Instead it’s possible to add a flag to the
docker-compose CLI command:
docker-compose run -u root --rm users sh -c "id -u -n" > root
To run Coverage.py as root user:
docker-compose run -u root --rm users sh -c "python manage.py cov"