bash - subir - docker linux
Usar la instrucción RUN en un archivo Docker con ''fuente'' no funciona (14)
Respuesta original
FROM ubuntu:14.04
RUN rm /bin/sh && ln -s /bin/bash /bin/sh
Esto debería funcionar para cada imagen base de docker de Ubuntu. Generalmente agrego esta línea para cada archivo Docker que escribo.
Editar por un espectador preocupado
Si desea obtener el efecto de "usar bash
lugar de sh
todo este archivo Docker", sin alterar y posiblemente dañar * el sistema operativo dentro del contenedor, 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 nueva instalación de Ubuntu
grep -rHInE ''/bin/sh'' /
devuelve más de 2700 resultados) esperan un shell completamente POSIX en/bin/sh
. El shell bash no es solo POSIX más builtins adicionales. Hay construcciones (y más) que se comportan de forma completamente diferente a las de POSIX. Apoyo totalmente el evitar POSIX (y la falacia de que cualquier script que no hayas probado en otro shell funcionará porque piensas que evitaste el basmismo) y simplemente usar bashism. Pero haces eso con un shebang adecuado en tu script. No tirando del shell POSIX desde todo el sistema operativo. (A menos que tenga tiempo para verificar las más de 2700 secuencias de comandos que vienen con Linux, además de todas las incluidas en los paquetes que instale).
Más detalles en esta respuesta a continuación. stackoverflow.com/a/45087082/117471
Tengo un Dockerfile que estoy reuniendo para instalar un entorno vanthon python (en el que instalaré una aplicación, pero más adelante).
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 obtengo 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 ls
en ese directorio (solo para probar que se han confirmado 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 comando de source
, obtengo el mismo error de "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 a mkvirtualenv
, mkvirtualenv
, etc.
He hecho algunas excavaciones, y al principio parecía que el problema podría estar en la diferencia entre bash como el shell de inicio de sesión de Ubuntu, y el tablero como el sistema operativo de Ubuntu, dash no soporta el comando de source
.
Sin embargo, la respuesta a esto parece ser el uso de ''.'' en lugar de la source
, pero esto solo causa 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 Dockerfile RUN para evitar esto (estoy ejecutando la imagen base predeterminada para Ubuntu 12.04 LTS).
Basándome en las respuestas de esta página, agregaría que debe tener en cuenta que cada instrucción RUN se ejecuta independientemente de las demás con /bin/sh -c
y, por lo tanto, no obtendrá ninguna variable de entorno que normalmente se originaría en shells de inicio de sesión.
La mejor forma que he encontrado hasta ahora es agregar la secuencia de comandos a /etc/bash.bashrc
y luego invocar cada comando como inicio de sesión bash.
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
RUN /bin/bash --login -c "your command"
Por ejemplo, podría instalar y configurar virtualenvwrapper, crear el env virtual, activarlo cuando use un inicio de sesión de bash, y luego instalar los módulos de python en este 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 ..."
Leer el manual en los archivos de inicio de bash ayuda a comprender de qué se trata cuando.
Compruebe el comando SHELL . El shell predeterminado en Linux es ["/ bin / sh", "-c"]
RUN "source file" # translates to: RUN /bin/sh -c "source file"
Puede cambiar el shell predeterminado usando SHELL
que cambia el shell utilizado para las instrucciones RUN
subsiguientes en Dockerfile
SHELL ["/bin/bash", "-c"]
Ahora, el shell predeterminado ha cambiado y no necesita definirlo explícitamente en cada instrucción RUN
RUN "source file" # now translates to: RUN /bin/bash -c "source file"
Nota adicional : también podría agregar la opción --login
que iniciaría un shell de inicio de sesión. Esto significa que ~/.bachrc
por ejemplo sería leído y no es necesario que lo fuente explícitamente antes de su comando
De acuerdo con la documentación de Docker
Para usar un shell diferente, que no sea ''/ bin / sh'', use el formulario de administrador que pasa en el shell deseado. Por ejemplo,
RUN ["/bin/bash", "-c", "echo hello"]
Es posible que desee ejecutar bash -v
para ver qué se está obteniendo.
Haría lo siguiente en lugar de jugar con enlaces simbólicos:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
Esto podría estar sucediendo porque la source
está integrada en bash en lugar de en un binario en algún lugar del sistema de archivos. ¿Su intención para el script que está buscando es alterar el contenedor luego?
La forma más simple es usar el operador punto en lugar de la fuente, que es el equivalente sh del comando source
bash:
En lugar de:
RUN source /usr/local/bin/virtualenvwrapper.sh
Utilizar:
RUN . /usr/local/bin/virtualenvwrapper.sh
Según docs.docker.com/engine/reference/builder/#run el shell [Linux] predeterminado para RUN
es /bin/sh -c
. Parece que espera bashisms, por lo que debe utilizar la "forma ejecutiva" de RUN
para especificar su shell.
RUN ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]
De lo contrario, usar la "forma de shell" de RUN y especificar un shell diferente da como resultado shells anidados.
# 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"]
Si tiene más de un comando que necesita un shell diferente, debe leer https://docs.docker.com/engine/reference/builder/#shell y cambiar su shell predeterminado colocando esto antes de sus comandos RUN:
SHELL ["/bin/sh", "-c"]
Nota: Intencionalmente ignoré el hecho de que no tiene sentido generar un script como el único comando en un RUN.
Si está utilizando Docker 1.12 o posterior, ¡simplemente use SHELL
!
Respuesta corta:
general:
SHELL ["/bin/bash", "-c"]
para python vituralenv:
SHELL ["/bin/bash", "-c", "source /usr/local/bin/virtualenvwrapper.sh"]
Respuesta larga:
de https://docs.docker.com/engine/reference/builder/#/shell
SHELL ["executable", "parameters"]
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 está ["cmd", "/ S", "/ C"]. La instrucción SHELL debe escribirse en formato JSON en un archivo Docker.
La instrucción SHELL es particularmente útil en Windows, donde hay dos caparazones nativos comúnmente usados y bastante diferentes: cmd y powershell, así como conchas alternativas disponibles, incluida sh.
La instrucción SHELL puede aparecer varias veces. Cada instrucción SHELL anula todas las instrucciones de SHELL anteriores y afecta a todas las instrucciones posteriores. Por ejemplo:
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
Las siguientes instrucciones pueden verse afectadas por la instrucción SHELL cuando la forma de shell de ellas se utiliza en un archivo Docker: RUN, CMD y ENTRYPOINT.
El siguiente ejemplo es un patrón común que se encuentra en Windows y que se puede simplificar utilizando la instrucción SHELL:
... RUN powershell -command Execute-MyCmdlet -param1 "c:/foo.txt" ...
El comando invocado por Docker será:
cmd /S /C powershell -command Execute-MyCmdlet -param1 "c:/foo.txt"
Esto es ineficiente por dos razones. En primer lugar, se invoca un procesador de comandos cmd.exe innecesario (también conocido como shell). En segundo lugar, cada instrucción RUN en el formulario shell requiere un comando powershell adicional prefijando el comando.
Para hacer esto más eficiente, se puede emplear uno de dos mecanismos. Una es usar el formulario JSON del comando EJECUTAR tal como:
... RUN ["powershell", "-command", "Execute-MyCmdlet", "-param1 /"c://foo.txt/""] ...
Si bien el formulario JSON no es ambiguo y no utiliza el innecesario cmd.exe, sí requiere más detalle mediante dobles comillas y escapes. El mecanismo alternativo es usar la instrucción SHELL y el formulario de shell, creando una sintaxis más natural para los usuarios de Windows, especialmente cuando se combina con la directiva del analizador de escape:
# 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''
Resultando en:
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>
La instrucción SHELL también podría usarse para modificar la forma en que funciona un caparazón. Por ejemplo, utilizando SHELL cmd / S / C / V: ON | OFF en Windows, la semántica de expansión de variables de entorno diferidas podría modificarse.
La instrucción SHELL también se puede usar en Linux si se requiere un shell alternativo como zsh, csh, tcsh y otros.
La función SHELL se agregó en Docker 1.12.
Si solo está tratando de usar pip para instalar algo en el virtualenv, puede modificar el entorno PATH para buscar primero en la carpeta bin del virtualenv
ENV PATH="/path/to/venv/bin:${PATH}"
Entonces, cualquier comando de pip install
que siga en Dockerfile encontrará / path / to / venv / bin / pip primero y lo usará, que se instalará en ese virtualenv y no en el sistema python.
También tuve problemas al ejecutar la source
en un archivo Docker
Esto funciona perfectamente bien para construir contenedores Docker CentOS 6.6, pero dio problemas en contenedores Debian
RUN cd ansible && source ./hacking/env-setup
Así es como lo abordé, puede que no sea una manera elegante, pero esto es lo que funcionó para mí
RUN echo "source /ansible/hacking/env-setup" >> /tmp/setup
RUN /bin/bash -C "/tmp/setup"
RUN rm -f /tmp/setup
Terminé poniendo mi material env en. .profile
y SHELL
mutado algo así como
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
Tuve el mismo problema y para ejecutar pip install en Virtualenv tuve que usar este comando:
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"
Espero que ayude.
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"