【问题标题】:Docker run python script cant find locally installed moduleDocker运行python脚本找不到本地安装的模块
【发布时间】:2020-03-10 18:01:53
【问题描述】:

就上下文而言,此问题与将使用 azure batch 运行的 docker 映像有关。

这里是Dockerfile,全文:

FROM continuumio/miniconda3

ADD . /pipegen

ADD environment.yml /tmp/environment.yml
RUN conda env create -f /tmp/environment.yml

RUN echo "conda activate $(head -1 /tmp/environment.yml | cut -d' ' -f2)" >> ~/.bashrc

ENV PATH /opt/conda/envs/$(head -1 /tmp/environment.yml | cut -d' ' -f2)/bin:$PATH
ENV CONDA_DEFAULT_ENV $(head -1 /tmp/environment.yml | cut -d' ' -f2)

ADD classify.py /classify.py
RUN rm -rf /pipegen

pipgen 是使用environment.yml 文件安装的本地模块(Dockerfile 所在的位置)。这是environment.yml的完整文件:

name: pointcloudz

channels:
  - conda-forge
  - defaults

dependencies:
  - python=3.7
  - python-pdal
  - entwine
  - matplotlib
  - geopandas
  - notebook
  - azure-storage-blob==1.4.0
  - pip:
    - /pipegen
    - azure-batch==6.0.0

为清楚起见,目录结构如下所示:

Dockerfile
pipegen
  \__ __init__.py
  \__ pipegen.py
  \__ utils.py
classify.py
batch_containers.py
environment.yml
setup.py

Dockerfile 建立使用environment.yml 文件创建的环境作为容器运行时的默认 (conda) python 环境。因此,我可以按如下方式交互式运行容器:

docker run -it pdalcontainers.azurecr.io/pdalcontainers/pdal-pipelines

然后,从容器内部,使用一些命令行参数执行classify.py 脚本,如下所示:

python classify.py in.las out.las --defaults

脚本按预期执行。但是,当我运行以下命令,尝试从容器“外部”执行相同的脚本时,

docker run -it pdalcontainers.azurecr.io/pdalcontainers/pdal-pipelines python classify.py in.las out.las --defualts

我收到以下错误:

File "classify.py", line 2, in <module>
    from pipegen.pipegen import build_pipeline, write_las
ModuleNotFoundError: No module named 'pipegen'

为了清楚起见,classify.py 脚本导入了 pipegen,这是现在安装在 Dockerfile 中创建的 conda 环境中的本地模块。由于 Azure 批处理运行作业的方式受到限制,我需要能够使用上面的 docker run 命令执行脚本。我已经尝试了多个修复,但现在非常卡住。任何智慧将不胜感激!

【问题讨论】:

  • Azure Batch 有哪些限制?

标签: python azure docker azure-batch


【解决方案1】:

您面临的问题是因为您将conda activate 添加到仅对登录shell 激活的.bashrc 脚本中。当您以交互方式运行容器时,这就是您所得到的。但是,当您尝试直接调用 python 脚本时,您不会获得登录 shell,因此您的 conda 环境激活。

您认为您可以做的就是不使用 conda activate 而是使用 conda run 运行脚本。要简化命令行,请将此入口点添加到您的 Dockerfile:

ENTRYPOINT ["conda", "run", "-n", "$CONDA_DEFAULT_ENV", "python", "classify.py"]

在入口点中使用它还允许调用者通过 docker run 传递命令行参数。

来自Dockerfile reference

docker run 的命令行参数将附加在 exec 表单 ENTRYPOINT 中的所有元素之后

更详细的解释见Activating a Conda environment in your Dockerfile

【讨论】:

  • 非常感谢尼克,非常有帮助和澄清。如果我每次都运行相同的脚本而不需要将命令行参数传递给它,这听起来像是一个完美的解决方案。我一直试图找出一个解决方案,该解决方案允许为 azure 批处理中的每个“作业”传递新参数。有什么想法吗?
  • @JmeCS,您可以在使用入口点时传递命令行参数。我更新了答案以包含相关参考。
猜你喜欢
  • 2021-11-04
  • 1970-01-01
  • 2019-12-12
  • 2021-10-22
  • 1970-01-01
  • 1970-01-01
  • 2022-07-08
  • 2020-06-26
  • 1970-01-01
相关资源
最近更新 更多