Running Django's collectstatic in Dockerfile produces empty directory

Question:

I’m trying to run Django from a Docker container on Heroku, but to make that work, I need to run python manage.py collectstatic during my build phase. To achieve that, I wrote the following Dockerfile:

# Set up image
FROM python:3.10
WORKDIR /usr/src/app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1

# Install poetry and identify Python dependencies
RUN pip install poetry
COPY pyproject.toml /usr/src/app/

# Install Python dependencies
RUN set -x 
    && apt update -y 
    && apt install -y 
        libpq-dev 
        gcc 
    && poetry config virtualenvs.create false 
    && poetry install --no-ansi

# Copy source into image
COPY . /usr/src/app/

# Collect static files
RUN python -m manage collectstatic -v 3 --no-input

And here’s the docker-compose.yml file I used to run the image:

services:
    db:
        image: postgres
        env_file:
            - .env.docker.db
        volumes:
            - db:/var/lib/postgresql/data
        networks:
            - backend
        ports:
            - "5433:5432"
    web:
        build: .
        restart: always
        env_file:
            - .env.docker.web
        ports:
            - "8001:$PORT"
        volumes:
            - .:/usr/src/app
        depends_on:
            - db
        networks:
            - backend
        command: gunicorn --bind 0.0.0.0:$PORT myapp.wsgi
volumes:
    db:
networks:
    backend:
        driver: bridge

The Dockerfile builds just fine, and I can even see that collectstatic is running and collecting the appropriate files during the build. However, when the build is finished, the only evidence that collectstatic ran is an empty directory called staticfiles. If I run collectstatic again inside of my container, collectstatic works just fine, but since Heroku doesn’t persist files created after the build stage, they disappear when my app restarts.

I found a few SO answers discussing how to get collectstatic to run inside a Dockerfile, but that’s not my problem; my problem is that it does run, but the collected files don’t show up in the container. Anyone have a clue what’s going on?

UPDATE: This answer did the trick. My docker-compose.yml was overriding the changes made by collectstatic with this line:

        volumes:
            - .:/usr/src/app

If, like me, you want to keep the bind mount for ease of local development (so that you don’t need to re-build each time), you can edit the command for the web service as follows:

        command: bash -c "python -m manage collectstatic && gunicorn --bind 0.0.0.0:$PORT myapp.wsgi"

Note that the image would have run just fine as-is had I pushed it to Heroku (since Heroku doesn’t use the docker-compose.yml file), so this was just a problem affecting containers I created on my local machine.

Asked By: coreye

||

Answers:

You are overriding the content of /usr/src/app in your container when you added the

volumes:
        - .:/usr/src/app

to your docker compose file.

Remove it since you already copied everything during the build.

Answered By: Sergio Santiago
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.