A sintaxe json de CMD
(e RUN
e ENTRYPOINT
) passe os argumentos para o kernel diretamente como um syscall exec. Não há separação do comando dos argumentos por espaços, escape de aspas, redirecionamento IO, substituição de variáveis, tubulação entre comandos, execução de vários comandos, etc, no exec syscall. O syscall leva apenas o executável para executar e lista de argumentos para passar para esse executável, e ele o executa.
Personagens como $
para expandir variáveis, ;
para separar comandos,
(espaço) para separar argumentos, &&
e ||
para comandos de cadeia, >
para redirecionamento de saída, |
para canalizar entre comandos, etc, são todos os recursos do shell e precisam de algo como /bin/sh
ou /bin/bash
para interpretá-los e implementá-los.
Se você mudar para a sintaxe de string de CMD
, docker executará seu comando com um shell:
CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm
Caso contrário, sua segunda sintaxe faz exatamente a mesma coisa:
CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]
Observe que não recomendo executar vários comandos dessa maneira dentro de um contêiner, pois não há tratamento de erros se seu primeiro comando falhar, especialmente se for executado em segundo plano. Você também deixa um shell funcionando como pid 1 dentro do contêiner, o que quebrará o manuseio do sinal, resultando em um atraso de 10 segundos e uma eliminação ingrata do contêiner pelo docker. O manuseio do sinal pode ser mitigado usando o shell exec
comando:
CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm
No entanto, lidar com processos que falham silenciosamente em segundo plano requer que você mude para algum tipo de Gerenciador de vários processos, como supervisord, ou, de preferência, divida seu aplicativo em vários contêineres e implemente-os com algo como docker-compose.