Понимание и исправление ModuleNotFoundError
Теперь, когда мы столкнулись с ModuleNotFoundError, давайте разберемся, почему это произошло и как это исправить.
Почему возникает ModuleNotFoundError в Docker?
ModuleNotFoundError возникает в Docker по нескольким распространенным причинам:
- Отсутствие установки зависимостей: Мы не установили необходимые пакеты Python в образе Docker.
- Неправильный PYTHONPATH: Интерпретатор Python не может найти модули в ожидаемых местах.
- Проблемы со структурой файлов: Структура кода приложения не соответствует тому, как выполняются импорты.
В нашем случае ошибка возникла из-за того, что мы не установили пакет requests в нашем образе Docker. В отличие от нашей локальной среды разработки, где у нас может быть этот пакет, установленный глобально, контейнеры Docker являются изолированными средами.
Метод 1: Установка зависимостей с помощью pip в Dockerfile
Давайте изменим наш Dockerfile, чтобы установить необходимые зависимости:
nano Dockerfile
Обновите Dockerfile следующим содержимым:
FROM python:3.9-slim
WORKDIR /app
COPY app.py .
## Fix Method 1: Directly install the required package
RUN pip install requests==2.28.1
CMD ["python", "app.py"]
Давайте соберем и запустим этот обновленный образ:
docker build -t python-app-fixed-1 .
Вы должны увидеть вывод, который включает установку пакета:
Sending build context to Docker daemon 3.072kB
Step 1/5 : FROM python:3.9-slim
---> 3a4bac80b3ea
Step 2/5 : WORKDIR /app
---> Using cache
---> a8a4f574dbf5
Step 3/5 : COPY app.py .
---> Using cache
---> 7d5ae315f84b
Step 4/5 : RUN pip install requests==2.28.1
---> Running in 5a6d7e8f9b0c
Collecting requests==2.28.1
Downloading requests-2.28.1-py3-none-any.whl (62 kB)
Collecting charset-normalizer<3,>=2
Downloading charset_normalizer-2.1.1-py3-none-any.whl (39 kB)
Collecting certifi>=2017.4.17
Downloading certifi-2022.9.24-py3-none-any.whl (161 kB)
Collecting idna<4,>=2.5
Downloading idna-3.4-py3-none-any.whl (61 kB)
Collecting urllib3<1.27,>=1.21.1
Downloading urllib3-1.26.12-py2.py3-none-any.whl (140 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2022.9.24 charset-normalizer-2.1.1 idna-3.4 requests-2.28.1 urllib3-1.26.12
---> 2b3c4d5e6f7g
Removing intermediate container 5a6d7e8f9b0c
Step 5/5 : CMD ["python", "app.py"]
---> Running in 8h9i0j1k2l3m
---> 3n4o5p6q7r8s
Removing intermediate container 8h9i0j1k2l3m
Successfully built 3n4o5p6q7r8s
Successfully tagged python-app-fixed-1:latest
Теперь давайте запустим исправленный контейнер:
docker run python-app-fixed-1
Вы должны увидеть вывод, похожий на этот:
Status code: 200
Content length: 1256 characters
Отлично! Приложение теперь успешно работает, потому что мы установили необходимую зависимость.
Метод 2: Использование requirements.txt для управления зависимостями
Хотя прямая установка пакетов работает, лучше использовать файл requirements.txt для более организованного управления зависимостями. Давайте обновим наш Dockerfile:
nano Dockerfile
Обновите Dockerfile следующим содержимым:
FROM python:3.9-slim
WORKDIR /app
## Copy requirements first to leverage Docker cache
COPY requirements.txt .
## Fix Method 2: Use requirements.txt
RUN pip install -r requirements.txt
## Copy the rest of the application
COPY app.py .
CMD ["python", "app.py"]
Этот подход имеет несколько преимуществ:
- Он отделяет управление зависимостями от кода
- Упрощает обновление зависимостей
- Соответствует лучшим практикам для кэширования слоев Docker-образа
Давайте соберем и запустим этот обновленный образ:
docker build -t python-app-fixed-2 .
Вы должны увидеть вывод, аналогичный предыдущей сборке, но на этот раз он использует requirements.txt:
Sending build context to Docker daemon 4.096kB
Step 1/5 : FROM python:3.9-slim
---> 3a4bac80b3ea
Step 2/5 : WORKDIR /app
---> Using cache
---> a8a4f574dbf5
Step 3/5 : COPY requirements.txt .
---> Using cache
---> b2c3d4e5f6g7
Step 4/5 : RUN pip install -r requirements.txt
---> Running in h8i9j0k1l2m3
Collecting requests==2.28.1
Using cached requests-2.28.1-py3-none-any.whl (62 kB)
Collecting charset-normalizer<3,>=2
Using cached charset_normalizer-2.1.1-py3-none-any.whl (39 kB)
Collecting idna<4,>=2.5
Using cached idna-3.4-py3-none-any.whl (61 kB)
Collecting certifi>=2017.4.17
Using cached certifi-2022.9.24-py3-none-any.whl (161 kB)
Collecting urllib3<1.27,>=1.21.1
Using cached urllib3-1.26.12-py2.py3-none-any.whl (140 kB)
Installing collected packages: urllib3, idna, charset-normalizer, certifi, requests
Successfully installed certifi-2022.9.24 charset-normalizer-2.1.1 idna-3.4 requests-2.28.1 urllib3-1.26.12
---> n4o5p6q7r8s9
Removing intermediate container h8i9j0k1l2m3
Step 5/5 : COPY app.py .
---> t0u1v2w3x4y5
Step 6/6 : CMD ["python", "app.py"]
---> Running in z5a6b7c8d9e0
---> f1g2h3i4j5k6
Removing intermediate container z5a6b7c8d9e0
Successfully built f1g2h3i4j5k6
Successfully tagged python-app-fixed-2:latest
Теперь давайте запустим контейнер:
docker run python-app-fixed-2
Вы должны увидеть тот же успешный вывод:
Status code: 200
Content length: 1256 characters
Вы успешно исправили ModuleNotFoundError, используя два разных метода!