Comandi multipli nella direttiva Docker CMD


39

Non capendo cosa sta succedendo quando provo ad eseguire due comandi in fase di esecuzione tramite la direttiva CMD in `Dockerfile. Ho assunto che questo dovrebbe funzionare:

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

Ma non funziona. Il contenitore non è stato avviato. Quindi ho dovuto farlo in questo modo:

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

Non capisco. Perché? Perché la prima riga non è la strada giusta? Qualcuno può spiegarmi queste cose "Formato shell CMD vs formato JSON, ecc". In parole semplici.

Solo per notare - lo stesso è stato con la command:direttiva docker-compose.yml, come previsto.

Risposte:


33

Credo che la differenza potrebbe avere a che fare con, il secondo comando esegue l'elaborazione della shell, mentre il primo no. Secondo la documentazione ufficiale , c'è il modulo exece shell, il tuo primo comando è un modulo exec e ad esempio non espande le variabili di ambiente, mentre il secondo lo fa. Quindi è possibile che, usando il modulo exec, il comando potrebbe fallire a causa della sua dipendenza dall'elaborazione della shell. Puoi verificarlo eseguendodocker logs CONTAINERID

Il tuo secondo comando, il modulo shell, equivale a -

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

Estratti dalla documentazione -

Nota: a differenza del modulo shell, il modulo exec non invoca una shell comandi. Ciò significa che la normale elaborazione della shell non avviene. Ad esempio, CMD [ "echo", "$HOME" ]non eseguirà la sostituzione variabile su $HOME. Se si desidera che l'elaborazione di shell quindi utilizzare il modulo shell o eseguire una shell direttamente, per esempio: CMD [ "sh", "-c", "echo", "$HOME" ].


Probabilmente il comando non è riuscito a causa delle variabili di ambiente. Devo ancora utilizzare questo execmodulo, in quanto è il modulo preferito? Perché è preferito? O dovrei usare un shellmodulo più semplice ?
Vladan,

Non è riuscito perché l'esecuzione di un comando dopo l'altro è una funzione di shell. Le variabili d'ambiente sono un'aringa rossa.
Bryan,

Se stai eseguendo più servizi in Docker, ti consiglio di utilizzare un gestore di processi come supervisore. In questo modo si avvia solo supervisord nella sezione CMD e si occuperà dell'avvio dei servizi. Puoi controllare i dettagli qui - docs.docker.com/articles/using_supervisord
Daniel t.

Questo è un articolo esatto che stavo leggendo :) Grazie.
Vladan,

Non capisco ancora perché devi farlo CMD [ "sh", "-c", "echo", "$HOME"]. Perché no CMD ["sh", "-c", "echo $HOME"]o, del resto CMD ["sh -c echo $HOME"],?
sixty4bit

4

Non renderti duro con te stesso. Basta creare un file bash "start.sh":

#!/bin/bash

/usr/bin/command2 param1
/usr/bin/commnad1

nel tuo Dockerfile fai:

ADD start.sh /
RUN chmod +x /start.sh

CMD ["/start.sh"]

2

La sintassi json di CMD(e RUNe ENTRYPOINT) passa gli argomenti al kernel direttamente come syscall exec. Non vi è alcuna separazione del comando dagli argomenti da spazi, escape di virgolette, reindirizzamento IO, sostituzione variabile, piping tra comandi, esecuzione di più comandi, ecc., Nel programma di esecuzione exec. Il syscall richiede solo l'esecuzione del file eseguibile e l'elenco degli argomenti da passare al file eseguibile e lo esegue.

I personaggi come $espandere le variabili, ;separare i comandi, (spaziare) per separare gli argomenti &&e ||mettere in ordine i comandi, >per il reindirizzamento dell'output, |per passare da un comando all'altro, ecc., Sono tutte caratteristiche della shell e hanno bisogno di qualcosa di simile /bin/sho /bin/bashdi interpretarle e implementarle.


Se si passa alla sintassi della stringa di CMD, la finestra mobile eseguirà il comando con una shell:

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

Altrimenti, la tua seconda sintassi fa esattamente la stessa cosa:

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

Nota che non consiglio di eseguire più comandi in questo modo all'interno di un contenitore poiché non vi è alcun errore nella gestione se il tuo primo comando fallisce, specialmente se viene eseguito in background. Lasci anche una shell in esecuzione come pid 1 all'interno del container che interromperà la gestione del segnale, causando un ritardo di 10 secondi e un'uccisione ingrata del container da parte della docker. La gestione del segnale può essere mitigata usando il execcomando shell :

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

Tuttavia, la gestione silenziosa dei processi in background richiede il passaggio a una sorta di gestore multi-processo come supervisord, o preferibilmente suddividere l'applicazione in più contenitori e distribuirli con qualcosa come docker-compose.


1

Immagino che il primo comando fallisca perché nella forma DOCKER CMD viene eseguito solo il primo parametro, il resto viene inserito in questo comando.

Il secondo modulo funziona perché tutti i comandi separati da ";" vengono inseriti nel comando sh, che li esegue.


1

Non credo che dovresti mettere la virgola dopo "start"

invece di usare

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

provare

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

poiché la finestra mobile utilizza "sh -c", il comando precedente verrà eseguito come di seguito

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

La sintassi json non esegue comandi con una shell, non esiste sh -cin quello scenario.
BMitch
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.