【问题标题】:condas `source activate virtualenv` does not work within Dockerfileconda `source activate virtualenv` 在 Dockerfile 中不起作用
【发布时间】:2016-10-23 01:56:19
【问题描述】:

场景

我正在尝试基于公共 continuumio/anaconda3 容器设置一个简单的 docker 映像(我对 docker 很陌生,所以请纠正我可能存在的误解)。

Dockerfile:

FROM continuumio/anaconda3:latest

# update conda and setup environment
RUN conda update conda -y \
    && conda env list \
    && conda create -n testenv pip -y \
    && source activate testenv \
    && conda env list

docker build -t test . 的构建和图像以错误结束:

/bin/sh: 1: source: not found

激活新的虚拟环境时。

建议一:

按照this answer我试过了:

FROM continuumio/anaconda3:latest

# update conda and setup environment
RUN conda update conda -y \
    && conda env list \
    && conda create -y -n testenv pip \
    && /bin/bash -c "source activate testenv" \
    && conda env list

起初这似乎有效,因为它输出:prepending /opt/conda/envs/testenv/bin to PATH,但conda env list 以及echo $PATH 清楚地表明它没有:

[...]
# conda environments:
#
testenv                  /opt/conda/envs/testenv
root                  *  /opt/conda

---> 80a77e55a11f
Removing intermediate container 33982c006f94
Step 3 : RUN echo $PATH
---> Running in a30bb3706731
/opt/conda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

docker 文件作为 MWE 开箱即用。 我很欣赏任何想法。谢谢!

【问题讨论】:

  • bash -c "source activate whatever" 将其导入到新的 shell 中,但这不是您需要的——您希望将这些变量添加到您的 现有 shell 中,以便它们发挥作用,否则当以bash -c 命令退出的shell 启动时,更新将被破坏,因此在您可以列出环境变量。
  • 因此,如果您希望新变量出现在env list 中,您需要它更像... && source testenv/bin/activate && conda env list——尽管它们仍然不会出现在任何未来的运行中调用,因为每次调用都在一个新的 shell 中,没有 shell(或其他 UNIX 进程)可以修改其父进程的环境变量。
  • 感谢@CharlesDuffy,你帮助我理解了潜在的问题。
  • @ccauet 你能更新你的问题,解释你遇到的问题吗?我的 docker 找不到 bash -c 但是当我进入容器本身然后激活容器内的 conda env 时,一切正常。最好明确说明您遇到的问题。
  • 似乎 RUN /bin/bash -c "source activate pytorch-py35" 确实有效...不知道为什么 RUN /bin/bash -c source activate pytorch-py35 无效。

标签: docker anaconda conda


【解决方案1】:

方法一:使用带有自定义入口点脚本的SHELL

编辑:我开发了一种新的、改进的方法,它比"conda", "run" 语法更好。

Sample dockerfile available at this gist。它通过利用自定义入口点脚本在execing RUN 节的参数之前设置环境来工作。

为什么会这样?

shell 是(简单地说)一个可以作为任意程序入口点的进程。 exec "$@" 允许我们启动一个新进程,继承父进程的所有环境。在这种情况下,这意味着我们激活 conda(它基本上会破坏一堆环境变量),然后运行 ​​/bin/bash -c CONTENTS_OF_DOCKER_RUN。


方法2:带参数的SHELL

这是我之前的方法,感谢Itamar Turner-Trauring;非常感谢他们!

# Create the environment:
COPY environment.yml .
RUN conda env create -f environment.yml

# Set the default docker build shell to run as the conda wrapped process
SHELL ["conda", "run", "-n", "vigilant_detect", "/bin/bash", "-c"]

# Set your entrypoint to use the conda environment as well
ENTRYPOINT ["conda", "run", "-n", "myenv", "python", "run.py"]

修改ENV 可能不是最好的方法,因为 conda 喜欢自己控制环境变量。此外,您的自定义 conda env 可能会激活其他脚本以进一步调整环境。

为什么会这样?

这利用conda run 在启动新的 bash shell 之前“将条目添加到环境的 PATH 并运行环境可能包含的任何激活脚本”。

使用 conda 可能是一种令人沮丧的体验,因为这两种工具都想有效地垄断环境,从理论上讲,您永远不需要在容器中使用 conda。但是最后期限和技术债务是一个问题,有时你只需要完成它,有时 conda 是提供依赖项的最简单方法(看看你,GDAL)。

【讨论】:

  • 由于conda run 的问题,我得出了同样的结论,即确实需要这样一个入口点脚本才能获得正确的解决方案。然而,看看你的答案,巨大的“为什么这行得通?”文字将我所有的注意力从您改进的答案上转移开。您能否将“新的、改进的方法”放在大写字母中,而不是旧的 conda run 方法?
  • 感谢您的提示。我也在努力清理要点。如果您遇到任何问题,请告诉我!
  • 对我来说,它只能通过删除 conda install -n base pip 和 conda init 命令来工作,第一个是因为它说它找不到基本环境,第二个是因为我的 miniconda3 版本没有init 命令。但是,现在每次我执行 RUN 命令时,都会出现一个 stderr 错误告诉我CommandNotFoundError: activate is not a conda command,即使该命令运行良好
【解决方案2】:

捎带 ccauet 的回答(我无法开始工作),以及 Charles Duffey 的评论,说它不仅仅是PATH,这就是解决这个问题的方法。

激活环境时,conda 会设置以下变量,以及一些在停用环境时可以引用的备份默认值。这些变量已从 Dockerfile 中省略,因为根 conda 环境不再需要使用。作为参考,这些是CONDA_PATH_BACKUP、CONDA_PS1_BACKUP 和_CONDA_SET_PROJ_LIB。它还设置了PS1,以便在终端提示行的左侧显示(testenv),这也被省略了。下面的语句会做你想做的。

ENV PATH /opt/conda/envs/testenv/bin:$PATH
ENV CONDA_DEFAULT_ENV testenv
ENV CONDA_PREFIX /opt/conda/envs/testenv

为了减少创建的层数,您可以将这些命令组合成一个 ENV 命令,同时设置所有变量。

根据包的不同,可能还有一些其他的变量需要设置。例如,

ENV GDAL_DATA /opt/conda/envs/testenv/share/gdal
ENV CPL_ZIP_ENCODING UTF-8
ENV PROJ_LIB /opt/conda/envs/testenv/share/proj

获取此信息的简单方法是在根环境中调用printenv > root_env.txt,激活testenv,然后调用printenv > test_env.txt,并检查 diff root_env.txt test_env.txt.

【讨论】:

    【解决方案3】:

    使用 docker ENV 指令可以将虚拟环境路径永久添加到PATH。 虽然这并不能解决conda env list 下列出的选定环境。

    查看 MWE:

    FROM continuumio/anaconda3:latest
    
    # update conda and setup environment
    RUN conda update conda -y \
        && conda create -y -n testenv pip
    
    ENV PATH /opt/conda/envs/testenv/bin:$PATH
    
    RUN echo $PATH
    RUN conda env list
    

    【讨论】:

    • 除了关于所选 conda 环境的持久性问题外,此解决方案还使用了硬编码路径 /opt/conda/envs/testenv/bin,这对我来说似乎不需要。现在我将使用这个解决方案,因为 docker setup 保证路径是正确的。
    • 好答案。也就是说,激活 virtualenv 的不仅仅是 PATH——activate 也改变了PYTHONHOME,并设置了一个VIRTUAL_ENV 环境变量(前者是两者中更重要的,因为它会影响模块加载)。
    • 谢谢。您确定这种activate 行为吗?我没有使用virtualenv 的经验,但也许 conda 环境的工作方式不同?我刚刚在我的本地机器上激活了一个 conda 虚拟环境,得到了 echo $PYTHONHOME 和 echo $VIRTUAL_ENV 的空字符串。
    • 我假设 conda 使用标准的 virtualenv 工具;如果这个假设不成立,那么我上面可能错了。
    • 好的,再次感谢。我将密切关注此设置,并留意对我最初的问题的更好或更完整的答案。
    猜你喜欢
    • 1970-01-01
    • 2018-09-11
    • 2016-04-04
    • 2020-12-06
    • 2018-06-15
    • 1970-01-01
    • 2020-06-21
    • 2017-07-17
    相关资源
    最近更新 更多