【问题标题】:Docker Compose cannot find pip installed packageDocker Compose 找不到 pip 安装包
【发布时间】:2022-01-04 15:09:21
【问题描述】:

Docker Compose 给出ModuleNotFoundError: No module named 'django' 错误。 Docker Compose 没有安装我的 pip 安装包pip install -r requirements.txt,但以任何其他方式运行映像显示它们已安装,这个问题仅与 docker-compose 有关,为什么?

撰写

version: '3.8'

services:
  web:
    build: ./
    user: python
    volumes:
      - ./:/app
    ports:
      - 8000:8000
    env_file:
      - ./.env.dev

Dockerfile

# Base image  
FROM python:3.9.6

ENV HOME=/app

# create directory for the app user
RUN mkdir -p $HOME

# set work directory
WORKDIR $HOME
 
# install psycopg2 dependencies
RUN apt-get update \
    && apt-get -y install libpq-dev gcc \
    && pip install psycopg2 \
    && apt-get -y install gunicorn3

RUN pip install --upgrade pip
ADD requirements*.txt .
RUN pip install -r requirements.txt
COPY python . .

ENTRYPOINT ["/app/entrypoint.sh"]

EXPOSE 8000

问题:

我创建了以下 Dockerfile,它在生产中运行,甚至在 docker-compose 之外本地运行,没有任何问题,即以下工作没有错误docker run -p 8000:8000 web/lastest

但是,当我通过 docker-compose 运行它时,它找不到我安装的 pip 包。

例如:

  • docker-compose 构建(成功)
  • 码头工人组成

错误

web_1  | 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?
web_1  | [2022-01-04 14:55:05 +0000] [1] [INFO] Starting gunicorn 20.1.0
web_1  | [2022-01-04 14:55:05 +0000] [1] [INFO] Listening at: http://0.0.0.0:8000 (1)
web_1  | [2022-01-04 14:55:05 +0000] [1] [INFO] Using worker: sync
web_1  | [2022-01-04 14:55:05 +0000] [8] [INFO] Booting worker with pid: 8
web_1  | [2022-01-04 14:55:05 +0000] [8] [ERROR] Exception in worker process
web_1  | Traceback (most recent call last):
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/arbiter.py", line 589, in spawn_worker
web_1  |     worker.init_process()
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/workers/base.py", line 134, in init_process
web_1  |     self.load_wsgi()
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/workers/base.py", line 146, in load_wsgi
web_1  |     self.wsgi = self.app.wsgi()
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/app/base.py", line 67, in wsgi
web_1  |     self.callable = self.load()
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/app/wsgiapp.py", line 58, in load
web_1  |     return self.load_wsgiapp()
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/app/wsgiapp.py", line 48, in load_wsgiapp
web_1  |     return util.import_app(self.app_uri)
web_1  |   File "/usr/lib/python3/dist-packages/gunicorn/util.py", line 384, in import_app
web_1  |     mod = importlib.import_module(module)
web_1  |   File "/usr/lib/python3.9/importlib/__init__.py", line 127, in import_module
web_1  |     return _bootstrap._gcd_import(name[level:], package, level)
web_1  |   File "<frozen importlib._bootstrap>", line 1030, in _gcd_import
web_1  |   File "<frozen importlib._bootstrap>", line 1007, in _find_and_load
web_1  |   File "<frozen importlib._bootstrap>", line 986, in _find_and_load_unlocked
web_1  |   File "<frozen importlib._bootstrap>", line 680, in _load_unlocked
web_1  |   File "<frozen importlib._bootstrap_external>", line 790, in exec_module
web_1  |   File "<frozen importlib._bootstrap>", line 228, in _call_with_frames_removed
web_1  |   File "/app/app/wsgi.py", line 12, in <module>
web_1  |     from django.core.wsgi import get_wsgi_application
web_1  | ModuleNotFoundError: No module named 'django' 

在直接运行映像和使用 docker-compose 时运行 which python 输出 /usr/local/bin/python

正在运行docker run -it 43d991d65c02 /bin/bash 我可以看到并运行 Django。只有运行docker-compose时没有安装Django,为什么?

【问题讨论】:

  • 您在运行时使用卷挂载覆盖容器中的/app 目录。
  • 好吧,我太傻了。我不知道卷会清除 docker OS 系统中已安装的软件包。很高兴除非你回答
  • 在 requirements.txt 中不应该是 Django 吗?
  • 这取决于软件包的安装位置。如果我们通过卷挂载来挂载目录,则配置的容器目录是“覆盖”的。如果这个容器目录包含已安装的模块,那么是的,它们已经消失了。您能否检查 a) 删除卷挂载或 b) 在容器启动时重新运行 pip install -r requirements.txt 是否可以解决问题?
  • 感谢@Turing85,当我删除卷时,这现在可以工作了。我只想在本地进行更改并更新正在运行的容器。我想我误解了它的作用

标签: python docker docker-compose


【解决方案1】:

在提供的容器文件中,我们在容器目录/app 中工作。但是在运行时,我们将一个卷挂载到/app。因此,存储在/app 中的映像构建期间生成的所有内容都会被卷安装覆盖。如果运行时的依赖项安装在 /app 中,则它们会被卷挂载覆盖。

要解决这个问题,我想到了两种可能性:

  1. 我们可以删除卷挂载。然而,这将使我们失去“热重载”的能力。

  2. 我们可以在容器启动时重新运行pip install -r requirements.txt,然后再启动应用程序。这意味着将pip install -r requirements.txt 行添加到entrypoint.sh-script。

【讨论】:

  • 是否有第三个选项可以在 docker 构建过程中将要求安装在不同的位置并且卷不会覆盖它?或者可能运行 docker-compose command 进行安装,但也可以在主 docker 文件中运行 CMD。我没有在启动脚本中运行 pip install 的选项,这会增加很多开销
  • 我不是 python 开发人员,因此不熟悉 pip。不得不传这个。从外观上看,--target 就是您要找的东西。有关详细信息,请参阅this question。但我不知道您的应用程序是否会在启动时自动从配置的目录中获取依赖项。
  • 我想第三个选项更好的问题是,我可以运行 docker-compose command 并且它仍然运行 dockerfile CMD,我认为你不能有两个
  • 无论如何,你已经回答了我原来的问题,所以我会接受。感谢您的帮助
  • 您可以将 WORKDIR 更改为另一个文件夹,然后从该位置将需求导入您的应用程序
【解决方案2】:

当 docker-compose 将卷挂载到 /app 文件夹时,其先前的结构将被隐藏,并且新结构会覆盖先前的结构。

【讨论】:

    猜你喜欢
    • 2018-05-24
    • 1970-01-01
    • 1970-01-01
    • 2018-03-16
    • 1970-01-01
    • 2019-10-07
    • 1970-01-01
    • 2020-01-24
    • 2017-08-02
    相关资源
    最近更新 更多