Как настроить docker compose с помощью django и pdm
У меня есть проект на django с pdm и docker compose, и я настроил объем кодовой базы, чтобы включить горячую перезагрузку и отладку django в контейнере. Сборка с помощью compose config работает нормально, но когда я пытаюсь запустить сервер с помощью docker compose up -d
Я получаю сообщение об ошибке python, как будто библиотеки не были подобраны должным образом.
Проект имеет следующую архитектуру
project/
├── config/
│ ├── settings.py
│ └── urls.py
│ └── ...
├── some_django_app/
│ └── ...
├── compose.yaml
├── Dockerfile
├── README.md
├── pyproject.toml
└── pdm.lock
файл compose выглядит следующим образом
services:
web:
build:
dockerfile: Dockerfile
command: pdm run python manage.py runserver 0.0.0.0:8000
ports:
- 8000:8000
volumes:
- .:/app
env_file:
- .env
мой файл dockerfile выглядит следующим образом
# Use an official Python runtime as a parent image
FROM python:3.13.2-slim-bullseye
# Set environment variables
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
# Set the working directory in the container
WORKDIR /app
# Install system dependencies
RUN apt-get update && apt-get install -y \
build-essential \
libpq-dev \
&& rm -rf /var/lib/apt/lists/*
# Install PDM
RUN pip install --no-cache-dir pdm
# Copy the project files into the container
COPY . /app
# Accept build argument for ENVIRONMENT
ARG ENVIRONMENT=prod
# Install project dependencies using PDM
pdm install --prod --no-lock --no-editable;
Вот след ошибки, возникшей при запуске контейнера
INFO: The saved Python interpreter does not exist or broken. Trying to find another one.
INFO: __pypackages__ is detected, using the PEP 582 mode
Traceback (most recent call last):
File "/app/manage.py", line 12, in main
from django.core.management import execute_from_command_line
ModuleNotFoundError: No module named 'django'
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "/app/manage.py", line 23, in <module>
main()
~~~~^^
File "/app/manage.py", line 14, in main
raise ImportError(
...<3 lines>...
) from exc
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?
Это похоже на то, что pdm не может получить доступ к моим локальным библиотекам. Когда я удаляю строку контейнера в моем файле compose и перестраиваю, django работает нормально. Что не так с моей конфигурацией?
volumes:
в вашем файле Compose скрывает виртуальную среду, которую создает pdm. Документация по pdm примечания:
При первом запуске
pdm install
[...] PDM создаст virtualenv в<project_root>/.venv
и установит в него зависимости.
Это происходит в строке RUN pdm install
в конце файла Dockerfile. Однако в файле Compose вы подключаете текущий каталог хоста в целом к /app
в контейнере, и это также скрывает виртуальную среду.
Такое монтирование с привязкой фактически означает, что вы вообще ничего не используете в своем образе Docker и вновь сталкиваетесь с проблемой "работает на моем компьютере", которую Docker обычно пытается избежать. Я бы удалил это монтирование привязки и использовал локальную виртуальную среду Python (возможно, даже управляемую pdm) для повседневной разработки. Убедитесь, что ваш Dockerfile объявляет CMD
ENTRYPOINT ["pdm", "run"]
CMD ["./manage.py", "runserver", "0.0.0.0:8000"]
и затем вы можете удалить части файла Compose, которые дублируют настройки изображения – нет volumes:
или command:
.
version: "3.8"
services:
web:
build: .
ports:
- 8000:8000
env_file:
- .env
Поскольку pdm использует стандартные метаданные упаковки PEP 621 (то есть файл pyproject.toml
с ключом верхнего уровня [project]
), вы также можете использовать стандартные инструменты Python (pip) в своем образе Docker, даже если вы используйте pdm для вашей локальной настройки разработки. RUN pip install ...
в Dockerfile, как правило, что-то устанавливается в "системную" установку Python, но поскольку ваш образ содержит только одно приложение, при этом нет риска возникновения конфликта.
# Dockerfile
# Don't install pdm, but you should be able to
WORKDIR /app
COPY pyproject.toml ./ # maybe with some other files too, but not the whole project
RUN pip install -e . # into the "system" Python
COPY ./ ./
# There's not a virtual environment so you don't need to do anything to activate it
CMD ["./manage.py", "runserver", "0.0.0.0:8000"]
(По совпадению, эта последняя настройка будет работать с монтированием volumes:
, скрывающим код приложения, поскольку библиотечные зависимости не установлены в /app
. Все еще существуют потенциальные проблемы, если Dockerfile выполняет какие-либо манипуляции с деревом исходных текстов, или вы загружаете в контейнер такие вещи, как __pycache__
каталоги.)
В итоге я использовал многоступенчатый подход, как описано в документе PDM, поэтому PDM используется только во время сборки, а не во время выполнения. Чтобы убедиться, что container .venv не перезаписан кодовой базой venv, я также добавил определенный именованный контейнер следующим образом:
services:
web:
build:
dockerfile: Dockerfile
command: pdm run python manage.py runserver 0.0.0.0:8000
ports:
- 8000:8000
volumes:
- .:/app
- venv:/app/.venv
env_file:
- .env
volumes:
venv:
Это решило мою проблему: я все еще могу использовать pdm и docker во время разработки и иметь объем для кодовой базы.