在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]
我可以从这里运行脚本,然后高兴地访问workon
, mkvirtualenv
等。
我已经做了一些挖掘,最初看起来问题可能在于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"]
我也遇到了在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