在 Dockerfile 中激活 python virtualenv

Posted

技术标签:

【中文标题】在 Dockerfile 中激活 python virtualenv【英文标题】:Activate python virtualenv in Dockerfile 【发布时间】:2018-07-11 17:35:11 【问题描述】:

我有一个 Dockerfile,我尝试在其中激活 python virtualenv,它应该在这个 env 中安装所有依赖项。但是,所有内容仍会在全局范围内安装。我使用了不同的方法,但没有一个有效。我也没有收到任何错误。哪里出了问题?

1。 ENV PATH $PATH:env/bin

2。 ENV PATH $PATH:env/bin/activate

3。 RUN . env/bin/activate

我也关注了an example of a Dockerfile config for the python-runtime image on Google Cloud,和上面的基本一样。

设置这些环境变量与运行 source /env/bin/activate 相同。

ENV VIRTUAL_ENV /env

ENV PATH /env/bin:$PATH

另外,ENV VIRTUAL_ENV /env 是什么意思,如何使用?

【问题讨论】:

source ../bin/activate 试过了吗? 您是否在同一个 Docker 容器中运行多个 python 应用程序? 在 Dockerfile 中使用 virtualenv 可能不是最佳实践,因为理想情况下,您只需使用每个容器一个应用程序进行全局安装。但是,我很高兴我遇到了这个问题,因为我有一个单元测试用例,它需要 Dockerfile 中的 virtualenv。这可能看起来很奇怪,但部分测试是针对 virtualenv 集成的。感谢您提出这个问题。 【参考方案1】:

在容器中使用 virtualenv 有完全正当的理由。

您不一定需要激活 virtualenv 来安装软件或使用它。尝试直接从 virtualenv 的 bin 目录调用可执行文件:

FROM python:2.7

RUN virtualenv /ve
RUN /ve/bin/pip install somepackage

CMD ["/ve/bin/python", "yourcode.py"]

您也可以只设置 PATH 环境变量,以便所有进一步的 Python 命令将使用 virtualenv 中的二进制文件,如 https://pythonspeed.com/articles/activate-virtualenv-dockerfile/ 中所述

FROM python:2.7

RUN virtualenv /ve
ENV PATH="/ve/bin:$PATH"
RUN pip install somepackage

CMD ["python", "yourcode.py"]

【讨论】:

我认为,如果 yourcode.py 创建了一个子进程,这将不起作用。您还需要摆弄 $PATH,如 monitorius 的回答中所述。【参考方案2】:

考虑迁移到 pipenv - 一个可以为您自动执行 virtualenv 和 pip 交互的工具。由PyPA推荐。

在docker镜像中通过pipenv重现环境非常简单:

FROM python:3.7

RUN pip install pipenv

COPY src/Pipfile* ./

RUN pipenv install --deploy

...

【讨论】:

对不起,如果这是一个愚蠢的问题,但是在使用实际图像时如何使用 pipenv 安装的依赖项?我的理解是 pipenv 安装到具有随机名称的 virtualenv 上。因此,如果我提取此图像,克隆我的存储库并尝试运行pipenv run pytest,那么它就无法从我的文件夹中访问那些已安装的要求。谢谢 @RayB 这是个好问题!我个人从我的回答中将--system 参数添加到RUN。然后你可以打电话给pytest。但这有一些关于特定操作系统的系统 python 站点包的内容的警告:内容可能不同。所以这种方式不是企业级的。但可用于开发。对于企业级解决方案,您需要设置或捕获 virtualenv 名称,恕我直言。【参考方案3】:

设置这个变量

ENV VIRTUAL_ENV /env
ENV PATH /env/bin:$PATH

和刚刚跑不完全一样

RUN . env/bin/activate

因为单个RUN 内的激活不会影响Dockerfile 中RUN 以下的任何行。但是通过ENV设置环境变量会为所有RUN命令激活你的虚拟环境。

看这个例子:

RUN virtualenv env                       # setup env
RUN which python                         # -> /usr/bin/python
RUN . /env/bin/activate && which python  # -> /env/bin/python
RUN which python                         # -> /usr/bin/python

因此,如果您确实需要为整个 Dockerfile 激活 virtualenv,则需要执行以下操作:

RUN virtualenv env
ENV VIRTUAL_ENV /env                     # activating environment
ENV PATH /env/bin:$PATH                  # activating environment
RUN which python                         # -> /env/bin/python

【讨论】:

另一个非常流行的选择是运行一个 bash 脚本作为入口点,让它完成剩下的繁重工作。 入口点在运行时执行,此时已经构建并部署了映像。如果您想在运行时将软件包安装到 virtualenv 而不是映像构建时间,这应该是一个非常特殊的情况【参考方案4】:

如果你使用 python 3.x:

RUN pip install virtualenv
RUN virtualenv -p python3.5 virtual
RUN /bin/bash -c "source /virtual/bin/activate"

如果您使用的是 python 2.x:

RUN pip install virtualenv
RUN virtualenv virtual
RUN /bin/bash -c "source /virtual/bin/activate"

【讨论】:

【参考方案5】:

虽然我同意 Marcus 的观点,这不是使用 Docker 的方式,但你可以为所欲为。

直接使用 Docker 的 RUN 命令不会给你答案,因为它不会在虚拟环境中执行你的指令。而是使用 /bin/bash 压缩在一行中执行的指令。以下 Dockerfile 对我有用:

FROM python:2.7

RUN virtualenv virtual
RUN /bin/bash -c "source /virtual/bin/activate && pip install pyserial && deactivate"
...

这应该只在虚拟环境中安装 pyserial 模块。

【讨论】:

感谢您提供的解决方案,尽管它对我不起作用。现在,安装了依赖项(django),但我找不到 python 2/3 在 vi​​rtualenv 外部或内部时无法导入它的位置。我没有复杂的应用程序,因此我现在坚持使用 Docker 的主要目的,尽管仍然有一些线程解释了为什么在 docker 容器内创建 venv 仍然是一种很好的做法。 Example 希望你能解决问题。但是这很奇怪,您如何检查安装完成的位置? 真的需要最后的“&& deactivate”吗? docker 无论如何都会在新的 shell 中开始后续的 RUN,对吧? 对,我只是将它添加为干净的,以防激活对文件系统产生任何影响,该文件系统将保留在生成的 Docker 映像中。它很可能是可有可无的。【参考方案6】:

您不需要在 Docker 容器中使用 virtualenv。

virtualenv 用于依赖隔离。您希望防止安装的任何依赖项或软件包在应用程序之间泄漏。 Docker 实现了同样的目的,它将您的依赖项隔离在容器内,并防止容器之间和应用程序之间的泄漏。

因此,除非您在同一个容器中运行多个应用程序,否则在 Docker 容器中使用 virtualenv 毫无意义,如果是这种情况,我会说您做错了什么,解决方案是构建您的以更好的方式应用程序并将它们拆分到多个容器中。

【讨论】:

重点是节省空间。您可以按原样复制virtualenv 目录,而不需要目标映像中的python3-virtualenv。这为您节省了整个工具链(gcc 和朋友),因此节省了几百兆字节。 你不需要python3-virtualenv来做容器之间的依赖隔离。 许多 Python 包只支持在虚拟环境中安装,在这种情况下,能够在 docker 容器中激活 venv 很有用。 @MarcusLind 我认为问题是关于将 python 项目的内容打包到 docker 中,而不需要在 docker 内部构建环境。这里的 Virtualenv 用于将所有依赖项打包到一个子目录中,因此您可以将 COPY 它们放入 WORKDIR 中。但是,这将失败,因为它不会处理必须针对他的 docker 映像使用的任何基本操作系统构建的二进制依赖项。相反,一个解决方案是创建一个 docker 镜像来构建依赖项,然后将它们复制到多阶段构建中的目标镜像。 对离题投反对票。如果作者关心virtualenv和Docker一起使用的具体问题,那就意味着他实际上需要将virtualenv与Docker一起使用。

以上是关于在 Dockerfile 中激活 python virtualenv的主要内容,如果未能解决你的问题,请参考以下文章

Dockerfile Volume指令与docker -v的区别

docker -v 和Dockerfile 中VOLUME 区别

docker -v 和Dockerfile 中VOLUME 区别

Navicat Premium v12.0.23.0 安装,使用激活码激活

在 vuetify 中为 v-dialog 激活器使用自定义事件

77 swapon-激活Linux系统中交换空间