Executar um script dentro de um contêiner do docker usando script de shell

88

Estou tentando criar um script de shell para configurar um contêiner do docker. Meu arquivo de script se parece com:

#!bin/bash

docker run -t -i -p 5902:5902 --name "mycontainer" --privileged myImage:new /bin/bash

A execução desse arquivo de script executará o contêiner em um bash recém-invocado.

Agora eu preciso executar um arquivo de script (test.sh) que já está dentro do contêiner do script de shell fornecido acima. (Por exemplo: cd /path/to/test.sh && ./test.sh) Como fazer isso?

zappy
fonte
1
Por que não usar WORKDIRe CMD?
Dharmit
1
Você provavelmente não quer usar --privileged aqui. Consulte: stackoverflow.com/questions/36425230/…
CMP

Respostas:

123

Você pode executar um comando em um contêiner em execução usando docker exec [OPTIONS] CONTAINER COMMAND [ARG...]:

docker exec mycontainer /path/to/test.sh

E para executar a partir de uma sessão bash:

docker exec -it mycontainer /bin/bash

A partir daí, você pode executar seu script.

Javier Cortejoso
fonte
6
e se eu precisar entrar em / bin / bash primeiro e depois executar o comando dentro desse bash?
animado
49
Você também pode executar um script local diretamente do host. docker exec -i mycontainer bash < mylocal.sh Isso lê o script do host local e o executa dentro do contêiner. Você pode fazer isso com outras coisas (como arquivos .tgz canalizados para o tar) - é apenas usar o '-i' para canalizar para a entrada std do processo de contêiner.
Marvin
@Marvin, qual é o equivalente no PowerShell? o caractere "<" não é reconhecido.
Nicekiwi
1
Não sou um guru do PowerShell (felizmente), mas vaguei pelo SO e encontrei stackoverflow.com/a/11788475/500902 . Então, talvez Get-Content mylocal.sh | docker exec -i mycontainer bash. Não sei se isso funciona.
Marvin de
99

Supondo que seu contêiner do docker esteja instalado e funcionando, você pode executar comandos como:

docker exec mycontainer /bin/sh -c "cmd1;cmd2;...;cmdn"
Ciclope
fonte
2
Eu gosto dessa resposta; você não precisa fazer login no contêiner do docker para executar um comando ou conjunto de comandos. Obrigado!
Hatem Jaber de
Você sabe como dar um passo adiante e passar o comando inteiro ( /bin/sh -c "cmd1; cmd2; ...; cmdn") como o valor de uma variável de shell? Eu pergunto porque 'docker run' parece esperar um único comando e argumentos individuais não citados em vez de uma string entre aspas.
davidA
@meowsqueak: Esta resposta explica como executar vários comandos dentro de um contêiner já criado e em execução sem fazer login nesse contêiner, o que é útil na automação. No entanto, se você deseja executar vários comandos no momento da criação do contêiner (PS: o comando docker run cria e inicia o contêiner), você pode conseguir isso seguindo as respostas neste mesmo thread stackoverflow.com/a/41363989/777617
Cyclops
Em lugar de cmd1, eu preciso passar em um inteiro para-loop - mas espera que ;após o ciclo declaração e fazer declaração. Como posso executar todo o loop for como um único comando, ou seja cmd1? É possível?
Nicholas K
19

Eu estava procurando uma resposta para esta mesma pergunta e encontrei a solução ENTRYPOINT no Dockerfile para mim.

Dockerfile

...
ENTRYPOINT /my-script.sh ; /my-script2.sh ; /bin/bash

Agora os scripts são executados quando eu inicio o contêiner e recebo o prompt do bash após a execução dos scripts.

tojo
fonte
6

Você também pode montar um diretório local na imagem do docker e originar o script no seu .bashrc. Não se esqueça de que o script deve consistir em funções, a menos que você queira que ele seja executado em cada novo shell. (Isto está desatualizado, consulte o aviso de atualização.)

Estou usando esta solução para poder atualizar o script fora da instância do docker. Dessa forma, não preciso executar a imagem novamente se ocorrerem alterações, apenas abro um novo shell. (Livre-se de reabrir um shell - consulte o aviso de atualização)

Aqui está como você vincula seu diretório atual:

docker run -it -v $PWD:/scripts $my_docker_build /bin/bash

Agora seu diretório atual está vinculado à /scriptssua instância do docker.

(Desatualizado) Para salvar suas .bashrcalterações, envie sua imagem de trabalho com este comando:

docker commit $container_id $my_docker_build

Atualizar

Para resolver o problema de abrir um novo shell para cada mudança, agora faço o seguinte:

No próprio dockerfile, acrescento RUN echo "/scripts/bashrc" > /root/.bashrc". Dentro zshrc, exporto o diretório de scripts para o caminho. O diretório de scripts agora contém vários arquivos em vez de um. Agora posso chamar diretamente todos os scripts sem ter que abrir um sub shell em cada mudança.

BTW, você também pode definir o arquivo de histórico fora do seu contêiner. Dessa forma, não é mais necessário se comprometer com uma mudança de bash.

Devpool
fonte
Muito tarde..! @javier já mostra uma solução simples !! Eu sinto que esse ainda é melhor.
animado
2
@zappy a solução de javier não resolveu este problema convenientemente para mim - mas minha solução sim, pensei que seria interessante para aqueles que tinham um problema semelhante em que não querem reiniciar as imagens do docker para atualizar um ver as funções de que precisam. Por exemplo, se você usar várias imagens do docker de uma só vez para ativar um cluster de desenvolvimento, não deseja reiniciá-las o tempo todo.
Devpool de
3

Caso você não queira (ou tenha) um container em execução, você pode chamar seu script diretamente com o runcomando.

Remova os -i -targumentos tty iterativos e use isto:

    $ docker run ubuntu:bionic /bin/bash /path/to/script.sh

Isso (não testou) também funcionará para outros scripts:

    $ docker run ubuntu:bionic /usr/bin/python /path/to/script.py
Thomio
fonte
0

Se você deseja executar o mesmo comando em várias instâncias, pode fazer o seguinte:

for i in c1 dm1 dm2 ds1 ds2 gtm_m gtm_sl; do docker exec -it $i /bin/bash -c "service sshd start"; done
DMin
fonte