Não entendendo o que está acontecendo quando tento executar dois comandos em tempo de execução via diretiva CMD em `Dockerfile. Eu assumi que isso deveria funcionar:
CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]
Mas não está funcionando. O contêiner não foi iniciado. Então tive que fazer assim:
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Não entendo. Por que é que? Por que a primeira linha não é o caminho certo? Alguém pode me explicar essas coisas "formato shell CMD vs formato JSON, etc". Em palavras simples.
Apenas para observar - o mesmo ocorreu com a command:
diretiva em docker-compose.yml
, como esperado.
Acredito que a diferença possa ser porque o segundo comando faz o processamento do shell enquanto o primeiro não. De acordo com a documentação oficial , existem os formulários
exec
e .shell
Seu primeiro comando é umexec
formulário. Oexec
formulário não expande as variáveis de ambiente enquanto oshell
formulário o faz. É possível que, ao usar oexec
formulário, o comando falhe devido à sua dependência do processamento do shell. Você pode verificar isso executandodocker logs CONTAINERID
Seu segundo comando, o formulário do shell, é equivalente a -
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
Excertos da documentação -
Não torne isso difícil para si mesmo. Basta criar um arquivo bash "start.sh":
no seu Dockerfile faça:
A sintaxe json de
CMD
(andRUN
andENTRYPOINT
) passa os argumentos para o kernel diretamente como uma exec syscall. Não há separação do comando dos argumentos por espaços, escape de aspas, redirecionamento de IO, substituição de variável, tubulação entre comandos, execução de vários comandos, etc, no exec syscall. O syscall só leva o executável para ser executado e a lista de argumentos para passar para esse executável e o executa.Caracteres como
$
expandir variáveis,;
separar comandos,(espaço) para separar argumentos
&&
e||
encadear comandos,>
para redirecionamento de saída,|
canalizar entre comandos, etc., são todos recursos do shell e precisam de algo como/bin/sh
ou/bin/bash
para interpretá-los e implementá-los.Se você alternar para a sintaxe de string de
CMD
, o docker executará seu comando com um shell:Caso contrário, sua segunda sintaxe faz exatamente a mesma coisa:
Observe que não recomendo executar vários comandos dessa maneira dentro de um contêiner, pois não há tratamento de erros se o primeiro comando falhar, especialmente se ele for executado em segundo plano. Você também deixa um shell rodando como pid 1 dentro do contêiner, o que interromperá o manuseio do sinal, resultando em um atraso de 10 segundos e uma morte sem graça do seu contêiner pelo docker. O tratamento do sinal pode ser mitigado usando o
exec
comando shell:No entanto, lidar com processos que falham silenciosamente em segundo plano exige que você alterne para algum tipo de gerenciador de vários processos como o supervisord ou, de preferência, divida seu aplicativo em vários contêineres e os implante com algo como docker-compose.
Eu acho que o primeiro comando falha porque no formulário DOCKER CMD, apenas o primeiro parâmetro é executado, o resto é alimentado neste comando.
A segunda forma funciona porque todos os comandos são separados por ";" são alimentados no comando sh, que os executa.
Por exemplo, imagine que você tenha dois comandos python para executar
python init_reset.py
epython app.py
. Em seguida, usando o CMD, você pode combinar os dois comandos com o único comandoNo Docker compose, isso pode ser feito conforme o exemplo a seguir:
O
exec
irá mudar o contexto do executável principal para apache2-forground.Eu não acho que você deve colocar uma vírgula depois de "start"
ao invés de usar
tentar
como o docker usa "sh -c", o comando acima será executado como abaixo