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?
CodePudding user response:
Could it be because of a missing DJANGO_SETTINGS_MODULE environment variable?
CodePudding user response:
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.
