Perché non posso utilizzare Docker CMD più volte per eseguire più servizi?


96

Ho creato un'immagine di base da Dockerfile denominata centos + ssh. Nel Dockerfile di centos + ssh, utilizzo CMD per eseguire il servizio ssh.

Quindi voglio creare un'immagine per eseguire un altro servizio chiamato rabbitmq, il Dockerfile:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD /opt/mq/sbin/rabbitmq-server start

Per avviare rabbitmq container , esegui :

docker run -d -p 222:22 -p 4149:4149 rabbitmq

ma il servizio ssh non funziona, rileva che Dockerfile CMD di rabbitmq ha la precedenza su CMD di centos.

  1. Come funziona CMD all'interno dell'immagine Docker?
  2. Se voglio eseguire più servizi, come? Usi il supervisore?

Risposte:


62

Anche se CMD è scritto nel Dockerfile, è davvero un'informazione di runtime. Proprio come EXPOSE, ma contrariamente ad es. RUN e ADD. Con questo, intendo che puoi sovrascriverlo in seguito, in un Dockerfile estendibile, o semplice nel tuo comando di esecuzione, che è quello che stai sperimentando. In ogni momento, può esserci un solo CMD.

Se vuoi eseguire più servizi, in effetti userò il supervisore. È possibile creare un file di configurazione del supervisore per ogni servizio, AGGIUNGERLI in una directory ed eseguire il supervisore supervisord -c /etc/supervisorin modo che punti a un file di configurazione del supervisore che carica tutti i servizi e ha l'aspetto

[supervisord]
nodaemon=true

[include]
files = /etc/supervisor/conf.d/*.conf

Se desideri maggiori dettagli, ho scritto un blog su questo argomento qui: http://blog.trifork.com/2014/03/11/using-supervisor-with-docker-to-manage-processes-supporting-image- eredità/


Grazie, il supervisore è una buona idea, ma mi chiedo come funzioni CMD all'interno dell'immagine finestra mobile
edwardsbean

2
Hai posto due domande, 2. sull'esecuzione di più servizi. Chiedendosi come funziona CMD, per favore elabora ciò che vuoi sapere nello specifico. L'ho già menzionato come informazioni di runtime e sovrascritto da qualsiasi nuovo CMD.
qkrijger

118

Hai ragione, il secondo Dockerfile sovrascriverà il CMDcomando del primo. Docker eseguirà sempre un singolo comando, non di più. Quindi alla fine del tuo Dockerfile, puoi specificare un comando da eseguire. Non di più.

Ma puoi eseguire entrambi i comandi in una riga:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD service sshd start && /opt/mq/sbin/rabbitmq-server start

Quello che potresti fare anche per rendere il tuo Dockerfile un po 'più pulito, potresti mettere i tuoi comandi CMD in un file extra:

FROM centos+ssh
EXPOSE 22
EXPOSE 4149
CMD sh /home/centos/all_your_commands.sh

E un file come questo:

service sshd start &
/opt/mq/sbin/rabbitmq-server start

1
grazie, penso che usare il supervisore sia meglio. ma perché docker esegue solo un CMD? cosa succede all'interno?
edwardsbean

1
Non so cosa stia succedendo dentro. Ma penso che sia stato progettato proprio così. Quando hai un'immagine e esegui un comando in essa (ad esempio con CMD), avvia un contenitore. Il contenitore viene eseguito finché viene eseguito il comando. E non appena termina il comando, si ferma anche il container. Quindi ogni contenitore rappresenta un singolo comando (in esecuzione).
Thomas Uhrig

Penso che forse a causa di lcx o di un limite di qualcosa
edwardsbean

2
@ Tyguy7 .. perché ................?
StartupGuy

1
&&la tecnica funzionerà solo con servizi non interattivi (che possono essere avviati in background) altrimenti verrà eseguito solo il primo.
noraj

26

Anche se rispetto la risposta di qkrijger che spiega come puoi aggirare questo problema, penso che ci sia molto di più che possiamo imparare su cosa sta succedendo qui ...

Per rispondere effettivamente alla tua domanda sul " perché " ... Penso che sarebbe utile per te capire come funziona il docker stopcomando e che tutti i processi dovrebbero essere chiusi in modo pulito per evitare problemi quando provi a riavviarli (danneggiamento dei file, ecc.).

Problema: cosa succede se docker ha avviato SSH dal suo comando e ha avviato RabbitMQ dal tuo file Docker? " Il comando docker stop tenta di arrestare prima un container in esecuzione inviando un segnale SIGTERM al processo root (PID 1) nel container. " Quale processo sta monitorando docker come PID 1 che otterrà SIGTERM? Sarà SSH o Rabbit ?? "Secondo il modello di processo Unix, il processo di inizializzazione - PID 1 - eredita tutti i processi figli orfani e deve raccoglierli. La maggior parte dei contenitori Docker non ha un processo di inizializzazione che lo faccia correttamente, e di conseguenza i loro contenitori vengono riempiti con processi zombie nel tempo ".

Risposta: Docker prende semplicemente l'ultimo CMD come quello che verrà avviato come processo di root con PID 1 e otterrà il SIGTERM da docker stop.

Soluzione suggerita: dovresti usare (o creare) un'immagine di base creata appositamente per l'esecuzione di più di un servizio, come phusion / baseimage

Dovrebbe essere importante notare che tini esiste esattamente per questo motivo e, a partire da Docker 1.13 e versioni successive, tini fa ufficialmente parte di Docker, il che ci dice che l'esecuzione di più di un processo in Docker È VALIDO .. quindi anche se qualcuno afferma di sii più abile riguardo a Docker e insiste sul fatto che sei assurdo pensando di farlo, sappi che non lo sei. Ci sono situazioni perfettamente valide per farlo.

Buono a sapersi:


3

La risposta ufficiale della finestra mobile per eseguire più servizi in un container .

Spiega come puoi farlo con un sistema init (systemd, sysvinit, upstart), uno script ( CMD ./my_wrapper_script.sh) o un supervisore come supervisord.

La &&soluzione alternativa può funzionare solo per i servizi che vengono avviati in background (daemon) o che verranno eseguiti rapidamente senza interazione e rilasceranno il prompt. Farlo con un servizio interattivo (che mantiene il prompt) e verrà avviato solo il primo servizio.


0

Per affrontare il motivo per cui CMD è progettato per eseguire un solo servizio per contenitore, realizziamo solo cosa accadrebbe se i server secondari eseguiti nello stesso contenitore non fossero banali / ausiliari ma "principali" (ad esempio, lo storage in bundle con l'app frontend). Per i principianti, interromperà diverse importanti funzionalità di containerizzazione come il ridimensionamento (automatico) orizzontale e la riprogrammazione tra i nodi, entrambi i quali presuppongono che ci sia una sola applicazione (origine del carico della CPU) per contenitore. Poi c'è il problema delle vulnerabilità: più server esposti in un container significa patch più frequenti dei CVE ...

Quindi ammettiamo che si tratta di una "spinta" dei designer di Docker (e Kubernetes / Openshift) verso buone pratiche e non dovremmo reinventare soluzioni alternative (SSH non è necessario - abbiamo docker exec / kubectl exec / oc rshprogettato per sostituirlo).

  • Ulteriori informazioni

/devops/447/why-it-is-recommended-to-run-only-one-process-in-a-container

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.