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.
“docker-compose up” as root user or 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 user
to 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"