在Dockerfile构建过程中激活和切换Anaconda环境

25

我已经尝试了几个小时,但是无法弄清如何在Dockerfile的构建过程中激活和切换anaconda环境。

以下是初始代码:

FROM nvidia/cuda:10.1-cudnn7-devel-ubuntu16.04

# Set user
ENV SETUSER myuser

RUN useradd -m $SETUSER
USER $SETUSER
WORKDIR /home/$SETUSER

# Install Anaconda
RUN wget https://repo.anaconda.com/archive/Anaconda3-2019.03-Linux-x86_64.sh
RUN bash Anaconda3-2019.03-Linux-x86_64.sh -b
RUN rm Anaconda3-2019.03-Linux-x86_64.sh

# Set path to conda
ENV CONDA_ENV_NAME mynewenv
RUN /home/$SETUSER/anaconda3/condabin/conda create -q --name $CONDA_ENV_NAME python=3.6 && \
    /home/$SETUSER/anaconda3/condabin/conda clean --yes --all
RUN /home/$SETUSER/anaconda3/condabin/conda activate base #Just for testing anaconda environment

在开始之前,Docker 中的 Anaconda 会抱怨 shell 配置不正确,因此在 conda create 命令后面我添加了以下内容:

RUN /home/$SETUSER/anaconda3/condabin/conda init bash
RUN /bin/bash -c "source /home/$SETUSER/.bashrc"
RUN /home/$SETUSER/anaconda3/condabin/conda activate base

构建 Docker 镜像后执行这三个命令是有效的(即在调用 docker run 容器名称后交互式运行),但由于某种原因,在构建容器时不起作用。我发现在构建过程中 $PATH 变量没有被更新,所以我比较了在构建前和构建后的 $PATH。
ENV PATH /home/$SETUSER/anaconda3/envs/$CONDA_ENV_NAME/bin:$PATH
ENV PATH /home/$SETUSER/anaconda3/condabin:$PATH
ENV PATH /home/$SETUSER/anaconda3/bin:$PATH
RUN conda init bash
RUN /bin/bash -c "source /home/$SETUSER/.bashrc"
RUN conda activate base

现在,在构建时的Docker $PATH和交互式运行容器后修改的$PATH是相同的,但我仍然收到“shell未正确设置”的错误。
CommandNotFoundError: 您的shell未正确配置使用'conda activate'。 要初始化您的shell,请运行 $ conda init 当前支持的shell是: - bash - fish - tcsh - xonsh - zsh - powershell 有关更多信息和选项,请参见“conda init --help”。 重要提示:在运行“conda init”之后,您可能需要关闭并重新启动shell。
为什么这不起作用?
我看到可能有一种解决方法是使用miniconda docker模板,但我不能使用那个。如何在Docker构建过程中创建和切换anaconda环境?谢谢!

通常在Docker中,您不需要像Conda这样的工具来管理多个并发隔离的软件安装:Docker本身提供了该隔离功能。对于Python包,只需在Dockerfile中运行pip install即可将其安装到“系统”Python中(隔离到您正在构建的镜像)。 - David Maze
这一切都很好,但我需要运行特定版本的Python。因此,我需要为此创建一个新的Anaconda环境。 - xnet
你尝试过将 RUN conda activate base 更改为 RUN bash -c "conda activate base" 吗? - Andrew Li
@DavidMaze 一些软件包仅通过Anaconda分发,而在PyPI上不可用。 - Zhe
4个回答

18

你的 Dockerfile 中有太多的 RUN 命令。不仅每个 RUN 命令都会在镜像中创建一个新的层,而且每个 RUN 命令都会启动一个新的 shell,conda activate 仅适用于当前的 shell。

你应该将逻辑上相关的操作合并为单个 RUN 命令。使用 && 来组合命令,并使用 \ 来换行以增加可读性:

RUN conda activate <myenv> \
 && conda install <whatever> \
 && ...

请记住:在RUN命令结束时,shell将会退出。如果您想以后对该conda环境进行其他操作,必须再次运行conda activate,否则使用-n <myenv>将某些内容放入环境中而不首先激活它。

当您从镜像启动容器时,还必须在容器内调用conda activate


8
假设您想安装conda环境并在其中运行某些内容,这种方法使用ENV PATH间接启动conda环境中的Python。 人们可能会疑惑是否真正激活了该环境,但只要后续的命令能够正常工作,事实上它们确实可以,那么这可能并不重要。
FROM continuumio/miniconda3:latest
WORKDIR myappdir
COPY environment.yml .
RUN set -x && \
#   apt-get update && apt-get -y install gcc && \
    conda install -n base -c defaults conda=4.* && \
    conda env create -n condaenv  # Installs environment.yml && \
    conda clean -a
COPY myapppkg myapppkg
ENV PATH /opt/conda/envs/condaenv/bin:$PATH
ENTRYPOINT ["python", "-m", "myapppkg"]

我建议不要使用 conda run,因为它处于实验阶段并存在严重错误的历史,例如影响它的此问题。尽管这个特定的 bug 现在已经被修复了,但是通过 conda run -h 显示的“实验性”本质意味着它可以再次破坏上游,限制人们对它的信任。
参考资料:

6

我还没有使用nvidia镜像进行测试,但多阶段Docker构建应该能够帮助您,大概是这样的:

# get Miniconda docker image to get a installed conda env; WARNING: That image is Debian based
FROM continuumio/miniconda3:latest AS miniconda


# your Docker commands
FROM nvidia/cuda:10.1-cudnn7-devel-ubuntu16.04

# Set user
ENV SETUSER myuser

RUN useradd -m $SETUSER
USER $SETUSER
WORKDIR /home/$SETUSER


# Miniconda: get necessary files from build
COPY --from=miniconda /opt/conda /opt/conda
# Set correct permissions
RUN chown -R $SETUSER: /opt/conda
#   New terminals will have conda active
# If nvidia's Docker image has no .bashrc
# COPY --from=miniconda /home/$SETUSER/.bashrc
# else
RUN echo ". /opt/conda/etc/profile.d/conda.sh" >> ~/.bashrc && \
    echo "conda activate base" >> ~/.bashrc

# switch shell sh (default in Linux) to bash
SHELL ["/bin/bash", "-c"]

# give bash access to Anaconda, then normal anaconda commands, e.g. (-q: quiet, -y: answer yes)
RUN source /home/$SETUSER/.bashrc \
 && conda create -q --name testy \
 && conda activate testy \
 && conda install -y your_package

这个GitHub问题启发了我:https://github.com/ContinuumIO/docker-images/issues/89


1

尝试了所有的解决方案后,最终对我有效的方法是在创建conda环境之后,在调用conda activate之前引用conda脚本。以下是我的Dockerfile摘录,其中我创建了三个不同的conda环境,并希望在每个环境中安装pip

RUN bash miniconda.sh -b -p /opt/conda
RUN source /opt/conda/etc/profile.d/conda.sh && conda init bash

RUN source /opt/conda/etc/profile.d/conda.sh && \
    conda create --name py37 python=3.7 -y && source /opt/conda/etc/profile.d/conda.sh && \
    conda activate py37 && conda install -c anaconda pip -y && \
    conda create --name py38 python=3.8 -y && source /opt/conda/etc/profile.d/conda.sh && \
    conda activate py38 && conda install -c anaconda pip -y && \
    conda create --name py39 python=3.9 -y && source /opt/conda/etc/profile.d/conda.sh && \
    conda activate py39 && conda install -c anaconda pip -y

没有源代码,调用conda.sh而不使用conda activate会导致conda init <SHELL_NAME>错误。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接