在Dockerfile中使用'source'运行指令不起作用

我有一个Dockerfile,我正在安装一个香草python环境(我将安装一个应用程序,但在以后的date)。

FROM ubuntu:12.04 # required to build certain python libraries RUN apt-get install python-dev -y # install pip - canonical installation instructions from pip-installer.org # http://www.pip-installer.org/en/latest/installing.html ADD https://bitbucket.org/pypa/setuptools/raw/bootstrap/ez_setup.py /tmp/ez_setup.py ADD https://raw.github.com/pypa/pip/master/contrib/get-pip.py /tmp/get-pip.py RUN python /tmp/ez_setup.py RUN python /tmp/get-pip.py RUN pip install --upgrade pip # install and configure virtualenv RUN pip install virtualenv RUN pip install virtualenvwrapper ENV WORKON_HOME ~/.virtualenvs RUN mkdir -p $WORKON_HOME RUN source /usr/local/bin/virtualenvwrapper.sh 

生成运行正常,直到最后一行,我得到以下exception:

 [previous steps 1-9 removed for clarity] ... Successfully installed virtualenvwrapper virtualenv-clone stevedore Cleaning up... ---> 1fc253a8f860 Step 10 : ENV WORKON_HOME ~/.virtualenvs ---> Running in 8b0145d2c80d ---> 0f91a5d96013 Step 11 : RUN mkdir -p $WORKON_HOME ---> Running in 9d2552712ddf ---> 3a87364c7b45 Step 12 : RUN source /usr/local/bin/virtualenvwrapper.sh ---> Running in c13a187261ec /bin/sh: 1: source: not found 

如果我进入该目录(只是为了testing前面的步骤已经提交),我可以看到文件存在按预期:

 $ docker run 3a87 ls /usr/local/bin easy_install easy_install-2.7 pip pip-2.7 virtualenv virtualenv-2.7 virtualenv-clone virtualenvwrapper.sh virtualenvwrapper_lazy.sh 

如果我试着运行source命令,我会得到和上面一样的'not found'错误。 如果我运行一个交互式shell会话,源代码确实工作:

 $ docker run 3a87 bash source bash: line 1: source: filename argument required source: usage: source filename [arguments] 

我可以从这里运行脚本,然后高兴地访问workonmkvirtualenv等。

我已经做了一些挖掘,最初看起来问题可能在于Ubuntu loginshell的 bash和Ubuntu 系统shell的 破折号之间的区别,不支持source命令。

但是,这个答案似乎是使用'。' 而不是source ,但是这只会导致Docker运行时崩溃,出现恐慌exception。

从Dockerfile的RUN指令中运行shell脚本的最好方法是绕过这个(运行Ubuntu 12.04 LTS的默认基本映像)。

RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"

 FROM ubuntu:14.04 RUN rm /bin/sh && ln -s /bin/bash /bin/sh 

这应该适用于每个Ubuntu Docker基本映像。 我通常为我写的每个Dockerfile添加这一行。

我有同样的问题,为了在virtualenv内执行pip install,我不得不使用这个命令:

 RUN pip install virtualenv virtualenvwrapper RUN mkdir -p /opt/virtualenvs ENV WORKON_HOME /opt/virtualenvs RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh \ && mkvirtualenv myapp \ && workon myapp \ && pip install -r /mycode/myapp/requirements.txt" 

我希望它有帮助。

最简单的方法是使用点运算符代替源代码,这是bash source的sh source

代替:

 RUN source /usr/local/bin/virtualenvwrapper.sh 

使用:

 RUN . /usr/local/bin/virtualenvwrapper.sh 

检查SHELL命令 。 Linux上的默认shell是[“/ bin / sh”,“-c”]

 RUN "source file" # translates to: RUN /bin/sh -c "source file" 

您可以使用SHELL更改默认shell, SHELL会更改用于Dockerfile中后续RUN指令的shell

 SHELL ["/bin/bash", "-c"] 

现在,默认的shell已经改变了,你不需要在每个RUN指令中明确地定义它

 RUN "source file" # now translates to: RUN /bin/bash -c "source file" 

附加说明 :您还可以添加--login选项,这将启动一个loginshell。 这意味着~/.bachrc将被读取,而且你不需要在你的命令之前显式地获取它

build立在这个页面上的答案我会补充一点,你必须知道,每个RUN语句独立于/bin/sh -c ,因此不会得到任何通常在loginshell中产生的环境variables。

到目前为止,我发现的最好的方法是将脚本添加到/etc/bash.bashrc ,然后调用每个命令作为bashlogin。

 RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc RUN /bin/bash --login -c "your command" 

例如你可以安装并设置virtualenvwrapper,创build虚拟env,当你使用bashlogin时激活它,然后把你的python模块安装到这个env中:

 RUN pip install virtualenv virtualenvwrapper RUN mkdir -p /opt/virtualenvs ENV WORKON_HOME /opt/virtualenvs RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc RUN /bin/bash --login -c "mkvirtualenv myapp" RUN echo "workon mpyapp" >> /etc/bash.bashrc RUN /bin/bash --login -c "pip install ..." 

阅读有关bash启动文件的手册有助于了解什么是什么时候。

如果您使用的是Docker 1.12或更新版本,请使用SHELL

简答:

一般:

 SHELL ["/bin/bash", "-c"] 

pythonvituralenv:

 SHELL ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"] 

长答案:

https://docs.docker.com/engine/reference/builder/#/shell

 SHELL ["executable", "parameters"] 

SHELL指令允许覆盖用于shell命令forms的默认shell。 Linux上的默认shell是[“/ bin / sh”,“-c”],在Windows上是[“cmd”,“/ S”,“/ C”]。 SHELL指令必须以JSON格式写入Dockerfile中。

SHELL指令在Windows中有两个常用和完全不同的本机shell特别有用:cmd和powershell,以及可用的备用shell,包括sh。

SHELL指令可以出现多次。 每个SHELL指令将覆盖所有先前的SHELL指令,并影响所有后续指令。 例如:

 FROM microsoft/windowsservercore # Executed as cmd /S /C echo default RUN echo default # Executed as cmd /S /C powershell -command Write-Host default RUN powershell -command Write-Host default # Executed as powershell -command Write-Host hello SHELL ["powershell", "-command"] RUN Write-Host hello # Executed as cmd /S /C echo hello SHELL ["cmd", "/S"", "/C"] RUN echo hello 

如果在Dockerfile中使用SHELL指令,则会影响以下指令:RUN,CMD和ENTRYPOINT。

以下示例是在Windows上可以通过使用SHELL指令简化的常见模式:

 ... RUN powershell -command Execute-MyCmdlet -param1 "c:\foo.txt" ... 

docker调用的命令是:

 cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:\foo.txt" 

这是低效率的,原因有两个。 首先,调用一个不必要的cmd.exe命令处理器(又名shell)。 其次,shell格式中的每条RUN指令都需要在命令前加上一个额外的powershell命令。

为了提高效率,可以采用两种机制之一。 一种是使用RUN命令的JSON格式,例如:

 ... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 \"c:\\foo.txt\""] ... 

虽然JSON格式是明确的,并且不使用不必要的cmd.exe,但是通过双引号和转义确实需要更多的冗长。 另一种机制是使用SHELL指令和shellforms,为Windows用户提供更自然的语法,特别是与escape parser指令结合使用时:

 # escape=` FROM microsoft/nanoserver SHELL ["powershell","-command"] RUN New-Item -ItemType Directory C:\Example ADD Execute-MyCmdlet.ps1 c:\example\ RUN c:\example\Execute-MyCmdlet -sample 'hello world' 

导致:

 PS E:\docker\build\shell> docker build -t shell . Sending build context to Docker daemon 4.096 kB Step 1/5 : FROM microsoft/nanoserver ---> 22738ff49c6d Step 2/5 : SHELL powershell -command ---> Running in 6fcdb6855ae2 ---> 6331462d4300 Removing intermediate container 6fcdb6855ae2 Step 3/5 : RUN New-Item -ItemType Directory C:\Example ---> Running in d0eef8386e97 Directory: C:\ Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 10/28/2016 11:26 AM Example ---> 3f2fbf1395d9 Removing intermediate container d0eef8386e97 Step 4/5 : ADD Execute-MyCmdlet.ps1 c:\example\ ---> a955b2621c31 Removing intermediate container b825593d39fc Step 5/5 : RUN c:\example\Execute-MyCmdlet 'hello world' ---> Running in be6d8e63fe75 hello world ---> 8e559e9bf424 Removing intermediate container be6d8e63fe75 Successfully built 8e559e9bf424 PS E:\docker\build\shell> 

SHELL指令也可以用来修改shell的运行方式。 例如,在Windows上使用SHELL cmd / S / C / V:ON | OFF,可以修改延迟的环境variables扩展语义。

SHELL指令也可以在Linux上使用,如果需要备用shell,如zsh,csh,tcsh等。

SHELLfunction是在Docker 1.12中添加的。

根据Docker文档

要使用不同于'/ bin / sh'的shell,请使用传递给所需shell的exec表单。 例如,

 RUN ["/bin/bash", "-c", "echo hello"] 

请参阅https://docs.docker.com/engine/reference/builder/#run

我也遇到了在Dockerfile中运行source的问题

这对于构buildCentOS 6.6 Docker容器来说运行得非常好,但是在Debian容器中给出了问题

 RUN cd ansible && source ./hacking/env-setup 

这是我如何处理它,可能不是一个优雅的方式,但这是对我来说是什么工作

 RUN echo "source /ansible/hacking/env-setup" >> /tmp/setup RUN /bin/bash -C "/tmp/setup" RUN rm -f /tmp/setup 

你可能想运行bash -v来查看是什么来源。

我会做以下,而不是玩符号链接:

RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc

根据https://docs.docker.com/engine/reference/builder/#run,RUN的默认%5BLinux%5D shell是/bin/sh -c 。 你似乎期待bashisms,所以你应该使用RUN的“execforms”来指定你的shell。

 RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"] 

否则,使用RUN的“shellforms”并指定不同的shell将导致嵌套的shell。

 # don't do this... RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh" # because it is the same as this... RUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"] 

如果你有一个以上的命令需要一个不同的shell,你应该阅读https://docs.docker.com/engine/reference/builder/#shell ,把你的默认shell放到你的RUN命令之前:

 SHELL ["/bin/sh", "-c"] 

注意:我有意忽略这样一个事实,即将一个脚本作为RUN中的唯一命令进行源代码访问是毫无意义的。

这可能是因为source是一个内置的bash而不是文件系统上的某个二进制文件。 您是否打算在之后采购脚本来更改容器?

如果你只是想用pip在virtualenv中安装某些东西,你可以修改PATH env来首先查看virtualenv的bin文件夹

ENV PATH="/path/to/venv/bin:${PATH}"

然后,Dockerfile中的任何pip install命令将首先find/ path / to / venv / bin / pip,然后使用该命令将安装到该virtualenv中,而不是系统python。

我结束了把我的env的东西放在.profile和变异的SHELL东西

 SHELL ["/bin/bash", "-c", "-l"] # Install ruby version specified in .ruby-version RUN rvm install $(<.ruby-version) # Install deps RUN rvm use $(<.ruby-version) && gem install bundler && bundle install CMD rvm use $(<.ruby-version) && ./myscript.rb