Varios comandos en la directiva CMD de Docker

No entiendo lo que sucede cuando intento ejecutar dos comandos en tiempo de ejecución a través de la directiva CMD en `Dockerfile. Asumí que esto debería funcionar:

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

Pero no está funcionando. El contenedor no se ha iniciado. Así que tuve que hacerlo así:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

No lo entiendo. ¿Por qué es eso? ¿Por qué la primera línea no es el camino correcto? Alguien puede explicarme estas cosas de "formato de shell CMD vs formato JSON, etc." En palabras simples.

Solo para tener en cuenta : lo mismo sucedió con command: directiva en docker-compose.yml, como se esperaba.

Creo que la diferencia podría deberse a que el segundo comando procesa el shell mientras que el primero no. Por el documentación oficial, están los exec y shell forma. Su primer comando es un exec forma. El exec el formulario no expande las variables de entorno mientras shell la forma lo hace. Es posible que al usar el exec formulario el comando está fallando debido a su dependencia del procesamiento de shell. Puede verificar esto ejecutando docker logs CONTAINERID

Su segundo comando, la forma de shell, es equivalente a -

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

Extractos de la documentación -

Nota: A diferencia del formulario shell, el formulario exec no invoca un shell de comandos. Esto significa que el procesamiento normal de shell no ocurre. Por ejemplo, CMD [ "echo", "$HOME" ] no realizará la sustitución de variables en $HOME. Si desea procesamiento de shell, utilice el formulario de shell o ejecute un shell directamente, por ejemplo: CMD [ "sh", "-c", "echo", "$HOME" ].

No te lo pongas difícil. Simplemente cree un archivo bash & quot; start. sh":

#!/bin/bash/usr/bin/command2 param1/usr/bin/command1

en su Dockerfile, haga:

ADD start.sh /RUN chmod +x /start.shCMD ["/start.sh"]

La sintaxis json de CMD (y RUN y ENTRYPOINT) pase los argumentos al núcleo directamente como una llamada de sistema exec. No hay separación del comando de los argumentos por espacios, escape de comillas, redirección de E / S, sustitución de variables, canalización entre comandos, ejecución de múltiples comandos, etc., en la llamada al sistema exec. La llamada al sistema solo toma el ejecutable para ejecutar y la lista de argumentos para pasar a ese ejecutable, y lo ejecuta.

Personajes como $ para expandir variables, ; para separar comandos, (espacio) para separar argumentos, && y || para encadenar comandos, > para la redirección de salida, | canalizar entre comandos, etc., son todas características del shell y necesitan algo como /bin/sh o /bin/bash interpretarlas e implementarlas.


Si cambia a la sintaxis de cadena de CMD, docker ejecutará su comando con un shell:

CMD /etc/init.d/nullmailer start ; /usr/sbin/php5-fpm

De lo contrario, su segunda sintaxis hace exactamente lo mismo:

CMD ["sh", "-c", "/etc/init.d/nullmailer start ; /usr/sbin/php5-fpm"]

Tenga en cuenta que no recomiendo ejecutar varios comandos de esta manera dentro de un contenedor, ya que no hay manejo de errores si su primer comando falla, especialmente si se ejecuta en segundo plano. También deja un shell ejecutándose como pid 1 dentro del contenedor, lo que interrumpirá el manejo de la señal, lo que provocará un retraso de 10 segundos y la muerte no grata de su contenedor por parte de docker. El manejo de la señal se puede mitigar utilizando el shell exec comando:

CMD /etc/init.d/nullmailer start ; exec /usr/sbin/php5-fpm

Sin embargo, manejar procesos que fallan silenciosamente en segundo plano requiere que cambie a algún tipo de administrador de multiprocesos como supervisord, o preferiblemente divida su aplicación en múltiples contenedores y los implemente con algo como docker-compose.

Supongo que el primer comando falla porque en el formulario DOCKER CMD, solo se ejecuta el primer parámetro, el resto se alimenta a este comando.

La segunda forma funciona porque todos los comandos separados por"; " se introducen en el comando sh, que los ejecuta.

Por ejemplo, imagine que tiene dos comandos de Python para ejecutar python init_reset.py y python app.py. Luego, usando CMD, puede combinar los dos comandos con el comando único

CMD python init_reset.py ; python app.py

En Docker Compose, esto se puede hacer como en el siguiente ejemplo:

command: ["sh", "-c", "    apt update && apt install -y libldap-common;    cp /ca.crt /usr/local/share/ca-certificates/;    update-ca-certificates;    exec apache2-foreground  "]

El exec cambiará el contexto del ejecutable principal a apache2-forground.

No creo que debas poner una coma después de "inicio"

en lugar de usar

CMD ["/etc/init.d/nullmailer", "start", ";", "/usr/sbin/php5-fpm"]

tratar

CMD ["/etc/init.d/nullmailer", "start", "/usr/sbin/php5-fpm"]

como docker usa "sh-c", el comando anterior se ejecutará de la siguiente manera

/etc/init.d/nullmailer start/etc/init.d/nullmailer /usr/sbin/php5-fpm