我有一个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
如果我试着运行源代码命令,我得到相同的'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,但这只会导致Docker运行时爆发一个go panic异常。
从Dockerfile run指令运行shell脚本来解决这个问题的最好方法是什么(我运行Ubuntu 12.04 LTS的默认基本映像)。
根据https://docs.docker.com/engine/reference/builder/#run,运行的默认[Linux] shell是/bin/sh -c。您似乎希望使用bashisms,因此应该使用RUN的“执行表单”来指定您的shell。
RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]
否则,使用RUN的“shell形式”并指定不同的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并将其放在RUN命令之前更改默认shell:
SHELL ["/bin/bash", "-c"]
最后,如果您在根用户的.bashrc文件中放置了您需要的任何东西,您可以在SHELL或RUN命令中添加-l标志,使其成为登录SHELL,并确保它得到源代码。
注意:我故意忽略了这样一个事实,即将脚本作为RUN中的唯一命令是没有意义的。
我曾经处理过一个用Django web框架开发的应用程序的类似场景,这些步骤对我来说非常有效:
我的Dockerfile内容
[mlazo@srvjenkins project_textile]$ cat docker/Dockerfile.debug
FROM malazo/project_textile_ubuntu:latest
ENV PROJECT_DIR=/proyectos/project_textile PROJECT_NAME=project_textile WRAPPER_PATH=/usr/share/virtualenvwrapper/virtualenvwrapper.sh
COPY . ${PROJECT_DIR}/
WORKDIR ${PROJECT_DIR}
RUN echo "source ${WRAPPER_PATH}" > ~/.bashrc
SHELL ["/bin/bash","-c","-l"]
RUN mkvirtualenv -p $(which python3) ${PROJECT_NAME} && \
workon ${PROJECT_NAME} && \
pip3 install -r requirements.txt
EXPOSE 8000
ENTRYPOINT ["tests/container_entrypoint.sh"]
CMD ["public/manage.py","runserver","0:8000"]
ENTRYPOINT文件"tests/container_entrypoint.sh"的内容:
[mlazo@srvjenkins project_textile]$ cat tests/container_entrypoint.sh
#!/bin/bash
# *-* encoding : UTF-8 *-*
sh tests/deliver_env.sh
source ~/.virtualenvs/project_textile/bin/activate
exec python "$@"
最后,我部署容器的方式是:
[mlazo@srvjenkins project_textile]$ cat ./tests/container_deployment.sh
#!/bin/bash
CONT_NAME="cont_app_server"
IMG_NAME="malazo/project_textile_app"
[ $(docker ps -a |grep -i ${CONT_NAME} |wc -l) -gt 0 ] && docker rm -f ${CONT_NAME}
docker run --name ${CONT_NAME} -p 8000:8000 -e DEBUG=${DEBUG} -e MYSQL_USER=${MYSQL_USER} -e MYSQL_PASSWORD=${MYSQL_PASSWORD} -e MYSQL_HOST=${MYSQL_HOST} -e MYSQL_DATABASE=${MYSQL_DATABASE} -e MYSQL_PORT=${MYSQL_PORT} -d ${IMG_NAME}
我真的希望这能对其他人有所帮助。
问候,