0

I have a Django REST framework API that I'm trying to run in Docker. The project uses Poetry 1.1.12. When running, I can see that Poetry is installed correctly, and that Poetry installs the packages in my pyproject.toml, including Django. I'm using supervisor to run the API using Daphne, as well as some other tasks (like collecting static files).

However, when supervisor runs the app, I get:

Traceback (most recent call last):
  File "/home/docker/api/manage.py", line 22, in <module>
    main()
  File "/home/docker/api/manage.py", line 13, in main
    raise ImportError(
ImportError: Couldn't import Django. Are you sure it's installed and available on your PYTHONPATH environment variable? Did you forget to activate a virtual environment?
Traceback (most recent call last):
  File "/home/docker/api/manage.py", line 11, in main
    from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'

Notice how I set POETRY_VIRTUALENVS_CREATE=false and ENV PATH="/root/.local/bin:${PATH}". According to the poetry installation script, that is the path that needs to be added to PATH.

Here is an abridged versioned of my Dockerfile:

FROM python:3.9-slim-buster
ENV PATH="/root/.local/bin:${PATH}"

RUN apt-get update && apt-get install -y --no-install-recommends \
    ... \
    curl \
    supervisor \
    && curl -sSL 'https://install.python-poetry.org' | python - && poetry --version \
    && apt-get remove -y curl \
    && apt-get purge -y --auto-remove -o APT::AutoRemove::RecommendsImportant=false \
    && apt-get clean -y && rm -rf /var/lib/apt/lists/* \
    && rm -rf /var/lib/apt/lists/*

COPY poetry.lock pyproject.toml /home/docker/api/

WORKDIR /home/docker/api

RUN if [ "$DEBUG" = "false" ] \
    ; then POETRY_VIRTUALENVS_CREATE=false poetry install --no-dev --no-interaction --no-ansi -vvv --extras "production" \
    ; else POETRY_VIRTUALENVS_CREATE=false poetry install --no-interaction --no-ansi -vvv --extras "production" \
    ; fi

COPY . /home/docker/api/
COPY .docker/services/api/files/supervisor.conf /etc/supervisor/conf.d/

CMD ["supervisord", "-n"]

Which is pretty much how I see others doing it. Any ideas?

2 Answers2

8

Poetry documents itself as trying very very hard to always run inside a virtual environment. However, a Docker container is itself isolation from other Pythons, and it's normal (and easiest) to install packages in the "system" Python.

There is a poetry export command that can convert Poetry's files to a normal pip requirements.txt file, and from there you can RUN pip install in your Dockerfile. You could use a multi-stage Dockerfile to generate that file without actually including Poetry in your main image.

FROM python:3.9-slim-buster AS poetry
RUN pip install poetry
WORKDIR /app
COPY pyproject.toml poetry.lock .
RUN poetry export -f requirements.txt --output requirements.txt

FROM python:3.9-slim-buster
WORKDIR /app
COPY --from=poetry /app/requirements.txt .
RUN pip install -r requirements.txt
COPY . .
CMD ["./manage.py", "runserver", "0.0.0.0:8000"]

django should show up in the generated requirements.txt file, and since pip install installs it as a "normal" "system" Python package, your application should be able to see it normally, without tweaking environment variables or other settings.

David Maze
  • 130,717
  • 29
  • 175
  • 215
  • Thank you for this idea. Unfortunately, I'm still getting "no module named django", even though it's included in the exported requirements.txt and is installed according to the logs: `django==3.2.11; python_version >= "3.6"` – 404usernamenotfound Jan 21 '22 at 14:52
  • Nevermind, the actual error is "no module named main", which is on me, because there really is no module named main. Accepting answer, thanks! – 404usernamenotfound Jan 21 '22 at 15:02
0

Could it be because of a missing DJANGO_SETTINGS_MODULE environment variable?

Arnaud
  • 101
  • 5