Múltiples 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. Supuse que esto debería funcionar:

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

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

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

No 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 sencillas.

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

Creo que la diferencia podría deberse a que el segundo comando hace el procesamiento de shell mientras que el primero no lo hace. Según 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 que shell la forma sí. Es posible que mediante el uso de la exec form el comando está fallando debido a su dependencia del procesamiento del shell. Puedes comprobarlo 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 de 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 hará 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. Basta con crear un archivo bash & quot; start. sh";:

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

en su Dockerfile hacer:

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

La sintaxis json de CMD (y RUN y ENTRYPOINT) pasa 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 de sistema exec. La syscall sólo toma el ejecutable que se ejecuta y la lista de argumentos para pasar a ese ejecutable, y corre.

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


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, la 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 el primer comando falla, especialmente si se ejecuta en segundo plano. También deja un shell funcionando como pid 1 dentro del contenedor que interrumpirá el manejo de la señal, lo que resultará en un retraso de 10 segundos y una muerte ingrata 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, el manejo de procesos que fallan silenciosamente en segundo plano requiere cambiar a algún tipo de administrador de múltiples procesos como supervisord, o preferiblemente dividir la aplicación en varios contenedores e implementarlos con algo como docker-compose.

Supongo que el primer comando falla porque en el formulario CMD de DOCKER, 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. A continuación, utilizando CMD, puede combinar los dos comandos con el único comando

CMD python init_reset.py ; python app.py

En Docker compose, esto se puede hacer como 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