Eu tenho um Dockerfile que estou montando para instalar um ambiente vanilla python (no qual instalarei um aplicativo, mas posteriormente).
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
A compilação funciona bem até a última linha, onde recebo a seguinte exceção:
[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
Se eu ls
entrar nesse diretório (apenas para testar se as etapas anteriores foram confirmadas), posso ver que os arquivos existem conforme o esperado:
$ 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
Se eu tentar apenas executar o source
comando, recebo o mesmo erro 'não encontrado' como acima. Se eu executar uma sessão de shell interativa, no entanto, a fonte funcionará:
$ docker run 3a87 bash
source
bash: line 1: source: filename argument required
source: usage: source filename [arguments]
Eu posso executar o script a partir daqui e acessar com prazer workon
, mkvirtualenv
etc.
Eu fiz algumas pesquisas e, inicialmente, parecia que o problema poderia estar na diferença entre o bash como o shell de login do Ubuntu e o dash como o shell do sistema Ubuntu , o dash não suportando o source
comando.
No entanto, a resposta para isso parece ser usar '.' em vez de source
, mas isso apenas faz com que o tempo de execução do Docker exploda com uma exceção de pânico.
Qual é a melhor maneira de executar um shell script a partir de uma instrução RUN do Dockerfile para contornar isso (estou executando a imagem base padrão do Ubuntu 12.04 LTS).
CMD source activate django-py35
Respostas:
RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh"
fonte
source
, vs apenasbash /usr/local/bin/virtualenvwrapper.sh
, nesse caso?RUN /bin/bash -c "source /usr/local/bin/virtualenvwrapper.sh; my_command; my_command; my_command;"
/bin/sh -c
é o shell padrão, esse "formulário de shell" do RUN se traduz emRUN ["/bin/sh", "-c", "/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
. Você deve seguir em frente e usar a "forma executiva" do RUN para que você possash
sair assim.RUN ["/bin/bash" "-c" "source /usr/local/bin/virtualenvwrapper.sh"]
bash
aninhado em umsh
e, portanto, deve ser evitado.Resposta original
Isso deve funcionar para todas as imagens base do docker do Ubuntu. Geralmente, adiciono essa linha a todos os Dockerfiles que escrevo.
Editar por um espectador preocupado
Se você deseja obter o efeito de "usar em
bash
vez desh
todo esse arquivo Dockerfile", sem alterar e possivelmente danificar * o sistema operacional dentro do contêiner, basta dizer à Docker sua intenção . Isso é feito assim:Mais detalhes nesta resposta abaixo. https://stackoverflow.com/a/45087082/117471
fonte
ln -snf /bin/bash /bin/sh
sh
parabash
ln -s /bin/bash /bin/sh
essa é uma péssima ideia. O Ubuntu direciona / bin / sh para correr por um motivo. dash é um shell totalmente posix, com ordens de magnitude mais rápidas que o bash. vincular / bin / sh ao bash reduzirá drasticamente o desempenho do seu servidor. citação: wiki.ubuntu.com/DashAsBinShsh
shell, mas você desejabash
, a solução adequada é fazer com que osh
processo seja invocadobash
como único, por exemplobash -c 'source /script.sh && …'
, ou você pode até ir longe para evitar totalmente bashismos (comosource
) e, em vez disso, optar por sempre usar apenas equivalentes POSIX válidos, por exemplo. /script.sh
. (Lembre-se do espaço após o.
!) Por último, se o seu script for executável (não apenas fonte), nunca faça o seu script ficar com um#!/bin/sh
shebang se ele não for realmente compatível com sh. Use em#!/bin/bash
vez disso.O shell padrão para a
RUN
instrução é["/bin/sh", "-c"]
.Usando a instrução SHELL , você pode alterar o shell padrão para
RUN
instruções subsequentes no Dockerfile:Agora, o shell padrão mudou e você não precisa defini-lo explicitamente em todas as instruções RUN
Nota adicional : Você também pode adicionar a
--login
opção que iniciaria um shell de login. Isso significa que,~/.bachrc
por exemplo, seria lido e você não precisa fornecê-lo explicitamente antes do seu comandofonte
--login
- apenas descobriu isso sozinhoSHELL ["/bin/bash", "-c", "-l"]
eu pude usar outras atualizações no arquivo .bashrc, o que me permitiu executar comandos asdf facilmente.Eu tive o mesmo problema e, para executar a instalação do pip dentro do virtualenv, tive que usar este comando:
Espero que ajude.
fonte
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"
A maneira mais simples é usar o operador de ponto no lugar da fonte, que é o equivalente sh do
source
comando bash :Ao invés de:
Usar:
fonte
.
/source
também aceita parâmetros posicionais após o nome do arquivosource
ou.
são perdidas quando o comando RUN é concluído. Veja: stackoverflow.com/a/40045930/19501Se você estiver usando o Docker 1.12 ou mais recente, basta usar
SHELL
!Resposta curta:
geral:
para python vituralenv:
Resposta longa:
de https://docs.docker.com/engine/reference/builder/#/shell
fonte
Com base nas respostas desta página, eu acrescentaria que você deve estar ciente de que cada instrução RUN é executada independentemente das outras
/bin/sh -c
e, portanto, não obterá nenhum ambiente de variáveis que normalmente seriam originadas em shells de login.A melhor maneira que encontrei até agora é adicionar o script
/etc/bash.bashrc
e, em seguida, chamar cada comando como login do bash.Você pode, por exemplo, instalar e configurar o virtualenvwrapper, criar o ambiente virtual, ativá-lo quando você usa um login bash e, em seguida, instalar seus módulos python nesse ambiente:
A leitura do manual nos arquivos de inicialização do bash ajuda a entender o que é originado quando.
fonte
ADD env-file /etc/profile.d/installerenv.sh
RUN /bin/bash --login -c 'env'
RUN /bin/bash -c 'rm /etc/profile.d/installerenv.sh'
Se o caso de uso de alguém adiciona mais variáveis de ambiente de injeção à perspectiva de construção do docker como a minha, recomendo consultar docs.docker.com/compose/yml / # env-file também.RUN
comando, o que significa que não é possível instalar muitas dependências do projeto e, em seguida, copiar o código-fonte e tirar proveito dos benefícios de Armazenamento em cache da etapa intermediária do Docker. Ele reinstalará todas as dependências do projeto todas as vezes./etc/bashrc
para Redhat, em vez de/etc/bash.bashrc
, como mencionado acima (Para Ubuntu)De acordo com https://docs.docker.com/engine/reference/builder/#run, o shell [Linux] padrão para
RUN
é/bin/sh -c
. Você parece estar esperando basismos, então você deve usar o "exec form" deRUN
para especificar seu shell.Caso contrário, usar o "formulário de shell" do RUN e especificar um shell diferente resulta em shells aninhados.
Se você possui mais de um comando que precisa de um shell diferente, leia https://docs.docker.com/engine/reference/builder/#shell e altere o shell padrão colocando-o antes dos comandos RUN:
Por fim, se você colocou algo no
.bashrc
arquivo do usuário raiz que precisa, pode adicionar o-l
sinalizador ao comandoSHELL
ouRUN
para torná-lo um shell de logon e garantir que ele seja originado.Nota: Ignorei intencionalmente o fato de que não faz sentido originar um script como o único comando em um RUN.
fonte
SHELL ["/bin/sh", "-c", "-l"]
então ele/bin/sh
Que não resolverá o problema do bash não estar sendo usado. Além disso, ao fazer umdocker build
é improvável que exista algo útil no .bashrc do usuário raiz que você precise. Mas, se você colocar alguma coisa lá no início do Dockerfile (como talvez umJAVA_HOME
., Aí sim eu vou colocar uma nota sobre isso na minha resposta.De acordo com a documentação do Docker
Consulte https://docs.docker.com/engine/reference/builder/#run
fonte
Se você tiver
SHELL
disponível, siga esta resposta - não use a aceita, o que força você a colocar o restante do arquivo docker em um comando por esse comentário .Se você estiver usando uma versão antiga do Docker e não tiver acesso
SHELL
, isso funcionará desde que você não precise de nada.bashrc
(o que é um caso raro no Dockerfiles):Observe que
-i
é necessário fazer com que o bash leia o rcfile.fonte
Você pode querer correr
bash -v
para ver o que está sendo adquirido.Eu faria o seguinte em vez de jogar com links simbólicos:
RUN echo "source /usr/local/bin/virtualenvwrapper.sh" >> /etc/bash.bashrc
fonte
Eu também tive problemas na execução
source
em um DockerfileIsso funciona perfeitamente para criar contêineres CentOS 6.6 Docker, mas deu problemas em contêineres Debian
É assim que eu lidei com isso, pode não ser uma maneira elegante, mas é isso que funcionou para mim
fonte
Isso pode estar acontecendo porque
source
é um built-in para bash em vez de um binário em algum lugar do sistema de arquivos. Sua intenção para o script que você está contratando é alterar o contêiner posteriormente?fonte
Acabei colocando minhas coisas env
.profile
e mutadoSHELL
algo comofonte
Se você está apenas tentando usar o pip para instalar algo no virtualenv, pode modificar o env PATH para procurar primeiro na pasta bin do virtualenv
ENV PATH="/path/to/venv/bin:${PATH}"
Em seguida, quaisquer
pip install
comandos que seguem na Dockerfile vai encontrar / path / to / venv / bin / pip primeiro e usar isso, que irá instalar em que virtualenv e não o sistema de python.fonte