将Shell脚本从Docker获取(“引用”)。
将Shell脚本从Docker获取(“引用”)。
我有一个Dockerfile,我正在用它安装一个基本的Python环境(稍后我将在其中安装一个应用程序)。
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
构建运行得很好,直到最后一行,我得到了以下异常:
[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
如果我进入该目录(为了测试之前的步骤是否已完成),我可以看到文件已按预期存在:
$ 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
命令,我会得到与上述相同的“未找到”错误。然而,如果我运行交互式Shell会话,则source
可以工作:
$ docker run 3a87 bash source bash: line 1: source: filename argument required source: usage: source filename [arguments]
我可以在这里运行脚本,然后愉快地访问workon
、mkvirtualenv
等。
我做了一些调查,最初看起来问题可能在于Ubuntu登录Shell是Bash,而Ubuntu系统Shell是Dash,Dash不支持source
命令。
然而,解决方法似乎是使用“。”而不是source
,但这会导致Docker运行时爆发go panicking异常。
从Dockerfile的RUN指令运行Shell脚本的最佳方法是什么(我正在运行Ubuntu 12.04 LTS的默认基本映像)?
RUN
指令的默认shell是["/bin/sh", "-c"]
。
RUN "source file" # translates to: RUN /bin/sh -c "source file"
使用SHELL指令,您可以更改Dockerfile中后续RUN
指令的默认shell:
SHELL ["/bin/bash", "-c"]
现在,默认的shell已经更改了,您不需要在每个RUN指令中显式定义它。
RUN "source file" # now translates to: RUN /bin/bash -c "source file"
附加说明:您还可以添加--login
选项,它将启动登录shell。这意味着~/.bashrc
例如将被读取,您不需要在执行命令之前显式的调用source命令。
原始回答
FROM ubuntu:14.04 RUN rm /bin/sh && ln -s /bin/bash /bin/sh
这对于每个Ubuntu docker基础镜像都应该有效。我通常为我编写的每个Dockerfile添加这一行。
由关注的旁观者编辑
如果您想获得“在整个Dockerfile中使用bash
而不是sh
”的效果,而不改变和可能损坏容器内部的操作系统,您可以只是告诉Docker您的意图。这是这样完成的:
SHELL ["/bin/bash", "-c"]
*可能的损害是许多Linux脚本(在一个新的Ubuntu安装中,
grep -rHInE '/bin/sh' /
返回超过2700个结果)都期望一个完全的POSIX shell在/bin/sh
上。Bash shell不仅仅是POSIX加上额外的内置内容。有内置内容(以及更多内容)的行为与POSIX完全不同。我完全支持避免POSIX(和你认为你避免了basmisms的任何脚本的谬论)并只使用bashism。但是,您要通过脚本中的适当shebang来实现这一点。而不是从整个操作系统中提取POSIX shell。(除非您有时间验证所有随Linux附带的2700多个脚本以及任何安装的包中的所有脚本。)
在下面的这个回答中有更多的细节。https://stackoverflow.com/a/45087082/117471