I'm trying to install pre-commit hooks in my python alpine docker container so I can run them via
docker-compose run ... "/py/bin/pre-commit run --all-files"
I first install git, then run git init and then install the hooks. It all works fine and I have put in a "ls -a" command for debugging into the building process where the .git folder shows up.
.
..
.flake8
.git
.pre-commit-config.yaml
app
core
manage.py
However, after the build is finished and I run
docker-compose run ... "ls -a"
the .git folder has disappeared.
Accordingly, running pre-commit gives me the following error:
An error has occurred: FatalError: git failed. Is it installed, and are you in a Git repository directory?
Check the log at /home/django-user/.cache/pre-commit/pre-commit.log
ERROR: 1
Below is the full code of my Dockerfile:
FROM python:3.9-alpine3.13
LABEL maintainer="dummy-maintainer"
ENV PYTHONUNBUFFERED 1
# Add the requirements files temporarily to the container
# to intall the python dependencies.
COPY ./requirements.txt /tmp/requirements.txt
COPY ./requirements-dev.txt /tmp/requirements-dev.txt
# Add the app to the container.
COPY ./app /app
# Add the pre-commit configuration to the container.
COPY ./.pre-commit-config.yaml /app/.pre-commit-config.yaml
# Change the working directory to the app directory
WORKDIR /app
# Use port 8000 for communication
EXPOSE 8000
ARG DEV=false
# 1. Create a virtual environment for the python dependencies.
# 2. Install the postgres client and the build dependencies for the postgres python adapter.
# 3. Create a virtual dependencies folder for the build dependencies. (Makes cleaning up easier)
# 4. Install the python dependencies via pip.
# 5. If this is the development mode, install further python dependencies needed for development.
# 6. Furthermore, create an empty git repository to run pre-commit checks on the source code.
RUN python -m venv /py && \
/py/bin/pip install --upgrade pip && \
apk add --update --no-cache postgresql-client && \
apk add --update --no-cache --virtual .tmp-build-deps \
build-base postgresql-dev musl-dev gcc libc-dev linux-headers postgresql-dev libffi-dev && \
/py/bin/pip install -r /tmp/requirements.txt && \
if [ $DEV = "true" ]; \
then /py/bin/pip install -r /tmp/requirements-dev.txt && \
apk add --update --no-cache git && \
git init . && \
/py/bin/pre-commit install-hooks && \
ls -a; \
fi && \
rm -rf /tmp && \
apk del .tmp-build-deps && \
adduser \
--disabled-password \
django-user
# Add the py folder to the path to simplify python commands
ENV PATH="/py/bin:$PATH"
USER django-user
and this is my docker-compose.yml:
version: "3.9"
services:
app:
build:
context: .
args:
- DEV=true
ports:
- "8000:8000"
volumes:
- ./app:/app
command: >
sh -c "python manage.py wait_for_db &&
python manage.py migrate &&
python manage.py runserver 0.0.0.0:8000"
environment:
- DB_HOST=db
- DB_NAME=devdb
- DB_USER=devuser
- DB_PASS=changeme
depends_on:
- db
db:
image: postgres:13-alpine
volumes:
- dev-db-data:/var/lib/postgresql/data
environment:
- POSTGRES_DB=devdb
- POSTGRES_USER=devuser
- POSTGRES_PASSWORD=changeme
volumes:
dev-db-data:
Does anyone know what the problem might be?
CodePudding user response:
The volumes:
mount hides everything that's in the image's /app
directory and replaces it with the host content. If you ever have a setup where your Dockerfile is reorganizing the file structure with COPY
commands or RUN
ning steps to generate files, you can't also use a volumes:
mount over the same directory.
So in your case, you have a ./.pre-commit-config.yaml
file, and an ./app/manage.py
script. In the Dockerfile you're merging these two directories so you have both /app/.pre-commit-config.yaml
and /app/manage.py
; but then the volumes:
replace the container's /app
directory with the host's ./app
, without the pre-commit file.
The advice I'd normally give here is to not try to force everything into Docker space. On your host system you'll need ordinary development tools like a text editor and a Web browser anyways, and you probably even have Python preinstalled already; install Git too and you'll be able to directly run git commit
without the docker-compose run app
wrapper.
If it's really important to you to only have tools in Docker then you need to make the container filesystem layout exactly match the host's.
FROM python:3.9-alpine
RUN adduser --disabled-password django-user
# Create and switch to a directory to hold the application
WORKDIR /app
# Copy and install the Python-level requirements
COPY requirements*.txt ./
RUN apk add --virtual .build-deps ... \
&& pip install -r requirements.txt \
&& apk del .build-deps
# Copy in the entire source tree
COPY ./ ./
# Explain how to run the container
WORKDIR /app/app
EXPOSE 8000
USER django-user
ENTRYPOINT ["../entrypoint.sh"] # runs wait_for_db, migrate
CMD ["./manage.py", "runserver", "0.0.0.0:8000"]
Now since the image has the exact same layout as the host system, you can either bind-mount the entire host source tree or just the app
subdirectory.
volumes: ['.:/app']
volumes: ['./app:/app/app']