我有一个Dockerfile,我正在整理它来安装一个vanilla 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
如果我 ls
进入该目录(只是为了测试前面提到的步骤)我可以看到文件按预期存在:
$ 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
等 .
我做了一些挖掘,最初看起来问题可能在于 bash 作为Ubuntu登录shell和 dash 作为Ubuntu系统shell之间的区别, dash 不支持 source
命令 .
但是,对此的答案似乎是使用 '.' 而不是 source
,但这只会导致Docker运行时爆炸,出现恐慌异常 .
从Dockerfile RUN指令运行shell脚本以解决此问题的最佳方法是什么(运行Ubuntu 12.04 LTS的默认基本映像) .
14 回答
原始答案
这适用于每个Ubuntu docker基础映像 . 我通常为我写的每个Dockerfile添加这一行 .
由有关旁观者编辑
如果你想获得“在整个Dockerfile中使用
bash
而不是sh
”的效果,没有 altering 和 possibly damaging *容器内的操作系统,你可以只tell Docker your intention . 这样做是这样的:以下答案中有更多细节 . https://stackoverflow.com/a/45087082/117471
我遇到了同样的问题,为了在virtualenv中执行pip安装,我不得不使用这个命令:
我希望它有所帮助 .
这可能会发生,因为
source
是一个内置的bash而不是文件系统上的某个二进制文件 . 你打算使用脚本来改变容器吗?如果您只是尝试使用pip在virtualenv中安装某些东西,可以修改PATH环境以首先查看virtualenv的bin文件夹
ENV PATH="/path/to/venv/bin:${PATH}"
然后,Dockerfile中的任何
pip install
命令将首先找到/ path / to / venv / bin / pip并使用它,它将安装到virtualenv而不是系统python中 .我最终把我的env东西放在了
.profile
并且突变了SHELL
之类的东西您可能希望运行
bash -v
以查看所获取的内容 .我会做以下而不是使用符号链接:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
检查SHELL Command . Linux上的默认shell是["/bin/sh","-c"]
您可以使用
SHELL
更改默认shell,这会更改用于Dockerfile中后续RUN
指令的shell现在,默认shell已更改,您无需在每个RUN指令中明确定义它
Additional Note :您还可以添加启动登录shell的
--login
选项 . 这意味着~/.bachrc
例如将被读取,您不需要在命令之前显式地获取它最简单的方法是使用点运算符代替source,它是bash
source
命令的sh等价物:代替:
使用:
基于此页面上的答案,我要补充一点,您必须知道每个RUN语句都使用
/bin/sh -c
独立于其他语句运行,因此不会获得通常在登录shell中获取的任何环境变量 .到目前为止,我发现的最好的方法是将脚本添加到
/etc/bash.bashrc
然后以bash登录的方式调用每个命令 .例如,您可以安装和设置virtualenvwrapper,创建虚拟环境,在使用bash登录时激活它,然后将python模块安装到此环境中:
阅读bash startup files上的手册有助于了解何时采购 .
根据https://docs.docker.com/engine/reference/builder/#run
RUN
的默认[Linux] shell是/bin/sh -c
. 您似乎期待bashisms,因此您应该使用"exec form"RUN
指定您的shell .除此以外,使用RUN的“shell表单”并指定不同的shell会导致嵌套shell .
如果你有多个命令需要一个不同的shell,你应该阅读https://docs.docker.com/engine/reference/builder/#shell并通过在你的RUN命令之前放置它来更改你的默认shell:
最后,如果您在根用户的
.bashrc
文件中放置了所需的任何内容,则可以将-l
标志添加到SHELL
或RUN
命令以使其成为登录shell并确保其获取来源 .注意:我故意忽略了这样一个事实:将脚本作为RUN中唯一的命令来源是没有意义的 .
我在Dockerfile中运行
source
时遇到了问题这对于构建CentOS 6.6 Docker容器非常适合,但是在Debian容器中存在问题
这就是我解决它的方式,可能不是一种优雅的方式,但这对我有用
如果您使用的是Docker 1.12或更高版本,请使用
SHELL
!简答:
一般:
为python vituralenv:
完整答案:
来自https://docs.docker.com/engine/reference/builder/#/shell
#执行为cmd / S / C echo默认值
RUN echo默认
#执行为cmd / S / C powershell -command Write-Host default
RUN powershell -command Write-Host默认值
#执行powershell -command Write-Host hello
SHELL [“powershell”,“ - command”]
RUN写主机问候
#执行为cmd / S / C echo hello
SHELL [“cmd”,“/ S”“,”/ C“]
RUN echo你好
当在Dockerfile中使用它们的shell形式时,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 -command前缀命令 . 为了提高效率,可以采用两种机制中的一种 . 一种是使用RUN命令的JSON形式,例如:...
RUN [“powershell”,“ - command”,“Execute-MyCmdlet”,“ - param1 \”c:\ foo.txt \“”]
...
虽然JSON表单是明确的,并且不使用不必要的cmd.exe,但它确实需要通过双引号和转义更加详细 . 另一种机制是使用SHELL指令和shell表单,为Windows用户提供更自然的语法,特别是与转义解析器指令结合使用时:#escape =`
来自microsoft / nanoserver
SHELL [“powershell”,“ - command”]
RUN New-Item -ItemType目录C:\ Example
添加Execute-MyCmdlet.ps1 c:\ example
运行c:\ example \ Execute-MyCmdlet -sample'hello world'
导致:PS E:\ docker \ build \ shell> docker build -t shell .
将构建上下文发送到Docker守护程序4.096 kB
第1/5步:从microsoft / nanoserver
---> 22738ff49c6d
第2/5步:SHELL powershell -command
--->在6fcdb6855ae2中运行
---> 6331462d4300
拆除中间容器6fcdb6855ae2
步骤3/5:运行New-Item -ItemType目录C:\ Example
--->在d0eef8386e97中运行
目录:C:\
模式LastWriteTime长度名称
d ----- 10/28/2016 11:26 AM示例
---> 3f2fbf1395d9
删除中间容器d0eef8386e97
步骤4/5:添加Execute-MyCmdlet.ps1 c:\ example
---> a955b2621c31
拆除中间容器b825593d39fc
步骤5/5:运行c:\ example \ Execute-MyCmdlet'hello world'
--->在be6d8e63fe75中运行
你好,世界
---> 8e559e9bf424
拆除中间容器be6d8e63fe75
成功建成8e559e9bf424
PS E:\ docker \ build \ shell>
SHELL指令也可用于修改shell的运行方式 . 例如,在Windows上使用SHELL cmd / S / C / V:ON | OFF,可以修改延迟的环境变量扩展语义 . 如果需要备用shell,例如zsh,csh,tcsh等,也可以在Linux上使用SHELL指令 . 在Docker 1.12中添加了SHELL功能 .
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
根据Docker文档
见https://docs.docker.com/engine/reference/builder/#run