Как настроить 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 во время разработки и иметь объем для кодовой базы.

Вернуться на верх