Tengo un Dockerfile que estoy armando para instalar un entorno de python vainilla (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 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 entro ls
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 source
comando, obtengo 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.
He cavado un poco, e inicialmente parecía que el problema podría estar en la diferencia entre bash como el shell de inicio de sesión de Ubuntu y dash como el shell del sistema de Ubuntu , el dash no admite el source
comando.
Sin embargo, la respuesta a esto parece ser usar '.' en lugar de source
, 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 Dockerfile RUN para evitar esto (estoy ejecutando la imagen base predeterminada para Ubuntu 12.04 LTS)?
CMD source activate django-py35
Respuestas:
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
fuente
source
en lugar de solobash /usr/local/bin/virtualenvwrapper.sh
, en ese caso?RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
/bin/sh -c
es el shell predeterminado, esta "forma de shell" de RUN se traduce enRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Deberías seguir adelante y usar la "forma ejecutiva" de RUN para que puedassh
sacarlo asíRUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
bash
anidado ensh
y, por lo tanto, debe evitarse.Respuesta original
Esto debería funcionar para cada imagen base de Docker de Ubuntu. Generalmente agrego esta línea para cada Dockerfile que escribo.
Editar por un espectador preocupado
Si desea obtener el efecto de "usar en
bash
lugar de ensh
todo este Dockerfile", sin alterar y posiblemente dañar * el sistema operativo dentro del contenedor, puede decirle a Docker su intención . Eso se hace así:Más detalles en esta respuesta a continuación. https://stackoverflow.com/a/45087082/117471
fuente
ln -snf /bin/bash /bin/sh
sh
abash
ln -s /bin/bash /bin/sh
Esta es una idea terrible. Ubuntu apunta / bin / sh al guión por una razón. dash es un shell completamente posix que es de órdenes de magnitud más rápido que bash. vincular / bin / sh a bash reducirá drásticamente el rendimiento de su servidor. cita: wiki.ubuntu.com/DashAsBinShsh
shell, pero lo deseabash
, la solución adecuada es hacer que elsh
proceso se invoque debash
manera única, por ejemplobash -c 'source /script.sh && …'
, o incluso podría llegar al extremo de evitar bashismos (comosource
) por completo, y en su lugar optar por usar solo equivalentes POSIX válidos, por ejemplo. /script.sh
. (¡Cuidado con el espacio después del.
!) Por último, si su script es ejecutable (no solo fuente), nunca haga que su script descanse con un#!/bin/sh
shebang si no es realmente compatible con sh. Usar en su#!/bin/bash
lugar.El shell predeterminado para la
RUN
instrucción es["/bin/sh", "-c"]
.Con la instrucción SHELL , puede cambiar el shell predeterminado para las
RUN
instrucciones posteriores en Dockerfile:Ahora, el shell predeterminado ha cambiado y no necesita definirlo explícitamente en cada instrucción RUN
Nota adicional : También puede agregar la
--login
opción que iniciaría un shell de inicio de sesión. Esto significa que,~/.bachrc
por ejemplo, se leería y no necesita obtenerlo explícitamente antes de su comandofuente
--login
- solo lo descubrí yo mismoSHELL ["/bin/bash", "-c", "-l"]
pude usar más actualizaciones para el archivo .bashrc, lo que me permitió ejecutar comandos asdf fácilmente.Tuve el mismo problema y para ejecutar pip install dentro de virtualenv tuve que usar este comando:
Espero que ayude.
fuente
RUN /bin/bash -c "source /opt/ros/melodic/setup.bash && \ cd /home && \ git clone https://angelos.p:[email protected]/inno/grpc-comms.git && \ cd grpc-comms && \ mkdir build && \ cd build && \ cmake .. && make"
La manera más simple es usar el operador de punto en lugar de la fuente, que es el equivalente sh del
source
comando bash :En vez de:
Utilizar:
fuente
.
/source
también acepta parámetros posicionales después del nombre del archivosource
o.
se pierden cuando finaliza el comando EJECUTAR. Ver: stackoverflow.com/a/40045930/19501Si está utilizando Docker 1.12 o más reciente, ¡simplemente utilícelo
SHELL
!Respuesta corta:
general:
para python vituralenv:
Respuesta larga:
de https://docs.docker.com/engine/reference/builder/#/shell
fuente
Sobre la base de las respuestas en esta página, agregaría que debe tener en cuenta que cada instrucción RUN se ejecuta independientemente de las demás
/bin/sh -c
y, por lo tanto, no obtendrá ningún valor de entorno que normalmente se obtenga en shells de inicio de sesión.La mejor manera que he encontrado hasta ahora es agregar el script
/etc/bash.bashrc
y luego invocar cada comando como inicio de sesión bash.Por ejemplo, puede instalar y configurar virtualenvwrapper, crear el entorno virtual, activarlo cuando use un inicio de sesión bash y luego instalar sus módulos de Python en este entorno:
Leer el manual sobre los archivos de inicio de bash ayuda a comprender de qué se origina cuándo.
fuente
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
si el caso de uso de uno agrega más variables de entorno de inyección a la perspectiva de construcción de Docker como la mía, recomendaría echar un vistazo a docs.docker.com/compose/yml / # env-file también.RUN
comando, lo que significa que no puedes instalar una gran cantidad de dependencias del proyecto y luego copiar el código fuente y aprovechar los beneficios de Caché de paso intermedio de Docker. Reinstalará todas las dependencias del proyecto cada vez./etc/bashrc
para Redhat, en lugar de/etc/bash.bashrc
lo mencionado anteriormente (para Ubuntu)De acuerdo con https://docs.docker.com/engine/reference/builder/#run, el shell predeterminado [Linux]
RUN
es/bin/sh -c
. Parece que espera bashismos, por lo que debe utilizar la "forma ejecutiva" deRUN
para especificar su shell.De lo contrario, usar la "forma de shell" de RUN y especificar un shell diferente da como resultado shells anidados.
Si tiene más de 1 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:
Finalmente, si ha colocado algo en el
.bashrc
archivo del usuario raíz que necesita, puede agregar el-l
indicador al comandoSHELL
oRUN
para convertirlo en un shell de inicio de sesión y asegurarse de que se obtenga.Nota: He ignorado intencionalmente el hecho de que no tiene sentido obtener un script como único comando en un EJECUTAR.
fuente
SHELL ["/bin/sh", "-c", "-l"]
por lo que obtiene ~ / .bashrc, etc. en caso de que tenga configuraciones de entorno desde el contenedor base/bin/sh
Que no resolverá el problema de que bash no se use. Además, cuando se realiza una accióndocker build
, es poco probable que haya algo útil en el .bashrc del usuario raíz que necesite. Pero, si pones algo allí antes en el Dockerfile (como tal vez unJAVA_HOME
, entonces sí. Pondré una nota al respecto en mi respuesta.)De acuerdo con la documentación de Docker
Ver https://docs.docker.com/engine/reference/builder/#run
fuente
Si tiene
SHELL
disponible, debe ir con esta respuesta : no use la aceptada, lo que lo obliga a colocar el resto del dockerfile en un comando por este comentario .Si está utilizando una versión antigua de Docker y no tiene acceso a ella
SHELL
, esto funcionará siempre que no necesite nada.bashrc
(que es un caso raro en Dockerfiles):Tenga en cuenta que
-i
se necesita para que bash lea el archivo rc en absoluto.fuente
Es posible que desee correr
bash -v
para ver qué se obtiene.Haría lo siguiente en lugar de jugar con enlaces simbólicos:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
fuente
También tuve problemas para ejecutar
source
en un DockerfileEsto funciona perfectamente bien para construir el contenedor CentOS 6.6 Docker, pero dio problemas en los contenedores Debian
Así es como lo aborde, puede que no sea una forma elegante, pero esto es lo que funcionó para mí
fuente
Esto podría estar sucediendo porque
source
está integrado en bash en lugar de un binario en algún lugar del sistema de archivos. ¿Su intención para el script que está buscando para alterar el contenedor después?fuente
Terminé poniendo mis cosas env
.profile
y mutadoSHELL
algo comofuente
Si solo está tratando de usar pip para instalar algo en virtualenv, puede modificar el PATH env para buscar primero en la carpeta bin de virtualenv
ENV PATH="/path/to/venv/bin:${PATH}"
Luego, cualquier
pip install
comando que siga en el Dockerfile encontrará primero / path / to / venv / bin / pip y lo usará, lo que se instalará en ese virtualenv y no en el sistema python.fuente