Usar la instrucción RUN en un Dockerfile con 'fuente' no funciona

Resuelto Hugo Rodger-Brown asked hace 10 años • 0 respuestas

Tengo un Dockerfile que estoy preparando para instalar un entorno básico de Python (en el que instalaré una aplicación, pero en una fecha posterior).

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

La compilación funciona bien hasta la última línea, donde aparece la siguiente excepción:

[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

Si lsentro en ese directorio (solo para probar que se confirmaron los pasos anteriores), puedo ver que los archivos existen como se esperaba:

$ 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

Si intento simplemente ejecutar el sourcecomando, aparece el mismo error "no encontrado" que el anterior. Sin embargo, si ejecuto una sesión de shell interactiva, la fuente funciona:

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

Puedo ejecutar el script desde aquí y luego acceder felizmente workon.mkvirtualenv etc.

Investigué un poco e inicialmente parecía que el problema podría residir en la diferencia entre bash como shell de inicio de sesión de Ubuntu y dash como shell del sistema de Ubuntu , donde dash no admite elsource comando.

Sin embargo, la respuesta a esto parece ser utilizar '.' en lugar desource , pero esto solo hace que el tiempo de ejecución de Docker explote con una excepción de pánico.

¿Cuál es la mejor manera de ejecutar un script de shell desde una instrucción RUN de Dockerfile para solucionar este problema (estoy ejecutando la imagen base predeterminada para Ubuntu 12.04 LTS)?

Hugo Rodger-Brown avatar Dec 17 '13 20:12 Hugo Rodger-Brown
Aceptado

Respuesta original

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

Esto debería funcionar para todas las imágenes base de la ventana acoplable de Ubuntu. Generalmente agrego esta línea para cada Dockerfile que escribo.

Editado por un espectador preocupado

Si desea obtener el efecto de "usar bashen lugar de shen todo este Dockerfile", sin alterar y posiblemente dañar * el sistema operativo dentro del contenedor, simplemente puede decirle a Docker su intención . Eso se hace así:

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

* El posible daño es que muchos scripts en Linux (en una instalación nueva de Ubuntu grep -rHInE '/bin/sh' /arroja más de 2700 resultados) esperan un shell completamente POSIX en /bin/sh. El shell bash no es solo POSIX más funciones integradas adicionales. Hay funciones integradas (y más) que se comportan de manera completamente diferente a las de POSIX. Apoyo TOTALMENTE evitar POSIX (y la falacia de que cualquier script que no hayas probado en otro Shell funcionará porque crees que evitaste los basmismos) y simplemente usar bashismo. Pero eso lo haces con un tinglado adecuado en tu guión. No sacando el shell POSIX de debajo de todo el sistema operativo. (A menos que tenga tiempo para verificar todos los scripts 2700 plus que vienen con Linux más todos los de los paquetes que instale).

Más detalles en esta respuesta a continuación. https://stackoverflow.com/a/45087082/117471

Anubhav Sinha avatar Aug 21 '2014 09:08 Anubhav Sinha

El shell predeterminado para la RUNinstrucción es ["/bin/sh", "-c"].

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

Usando la instrucción SHELL , puede cambiar el shell predeterminado para RUNinstrucciones posteriores en Dockerfile:

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

Ahora, el shell predeterminado ha cambiado y no es necesario definirlo explícitamente en cada instrucción RUN.

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

Nota adicional : También puede agregar --loginuna opción que iniciaría un shell de inicio de sesión. Esto significa que ~/.bashrc, por ejemplo, se leerá y no es necesario obtenerlo explícitamente antes de su comando.

Ahmad Abdelghany avatar Sep 29 '2016 18:09 Ahmad Abdelghany

La forma más sencilla es utilizar el operador punto en lugar de fuente, que es el equivalente sh del sourcecomando bash:

En lugar de:

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

Usar:

RUN . /usr/local/bin/virtualenvwrapper.sh
mixja avatar Dec 11 '2015 06:12 mixja

El SHELLcomando Dockerfile se puede utilizar para cambiar el shell predeterminado. (SHELL se introdujo en Docker 1.12)

por ejemplo, use el shell bash:

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

use bash y obtenga un virtualenv de Python:

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

La instrucción SHELL permite anular el shell predeterminado utilizado para la forma de shell de los comandos. El shell predeterminado en Linux es ["/bin/sh", "-c"] y en Windows es ["cmd", "/S", "/C"]. https://docs.docker.com/engine/reference/builder/#shell

Mithril avatar Feb 14 '2017 00:02 Mithril