Posso eseguire più programmi in un contenitore Docker?


150

Sto cercando di avvolgere la mia testa intorno a Docker dal punto di distribuire un'applicazione che è destinata a essere eseguita sugli utenti sul desktop. La mia applicazione è semplicemente un'applicazione web di pallone e un database mongo. Normalmente installerei entrambi in una macchina virtuale e inoltrerei una porta host all'app web guest. Mi piacerebbe provare Docker ma non sono sicuro di come dovrei usare più di un programma. La documentazione dice che può esserci solo ENTRYPOINT, quindi come posso avere Mongo e la mia applicazione di pallone. Oppure devono trovarsi in contenitori separati, nel qual caso come si comunicano tra loro e in che modo ciò semplifica la distribuzione dell'app?


2
Spot on: mi chiedo perché la docker fosse così popolare .. (processo singolo ..?) - ma vediamo cosa ci dicono le risposte ..
javadba,

Risposte:


120

Può esserci un solo ENTRYPOINT, ma quel target è di solito uno script che avvia tutti i programmi necessari. È inoltre possibile utilizzare ad esempio Supervisord o simili per occuparsi dell'avvio di più servizi all'interno di un singolo contenitore. Questo è un esempio di contenitore docker che esegue mysql, apache e wordpress all'interno di un singolo contenitore .

Dì, hai un database che viene utilizzato da una singola applicazione web. Quindi è probabilmente più semplice eseguirli entrambi in un singolo contenitore.

Se si dispone di un database condiviso utilizzato da più di un'applicazione, sarebbe meglio eseguire il database nel proprio contenitore e le applicazioni ognuna nei propri contenitori.

Esistono almeno due possibilità su come le applicazioni possono comunicare tra loro quando sono in esecuzione in contenitori diversi:

  1. Utilizzare le porte IP esposte e connettersi tramite esse.
  2. Le versioni recenti della finestra mobile supportano il collegamento .

1
Sembra che le nuove versioni di Docker ora supportino le reti di container Docker .
jpierson,

Docker ora supporta l'esecuzione di Supervisor, consentendoti di settare il comportamento di ogni processo come autorestart = true, stdout_logfile, stderr_logfile ecc. Dai un'occhiata a docs.docker.com/engine/admin/using_supervisord
Andreas Lundgren

5
Non consiglierei assolutamente di provare a eseguire l'applicazione web e mongodb nello stesso contenitore in questo esempio. Ci sono buoni casi d'uso di supervisord o processi simili simili a init in Docker ma questo non fa parte di essi. È molto più semplice utilizzare docker-compose per eseguire semplicemente i due servizi in contenitori separati.
nicolas-van

@ nicolas-van perché è più semplice? È perché se il db muore posso quindi riavviare il contenitore del db invece di dover riavviare il tutto?
Brillout,

Le applicazioni sulla stessa macchina possono anche comunicare su socket di dominio Unix . Massime prestazioni garantite.
Scettico Jule il

21

Avevo requisiti simili per l'esecuzione di uno stack LAMP, Mongo DB e i miei servizi

Docker è la virtualizzazione basata su OS, motivo per cui isola il suo contenitore attorno a un processo in esecuzione, quindi richiede almeno un processo in esecuzione in FOREGROUND.

Quindi fornisci il tuo script di avvio come punto di ingresso, quindi lo script di avvio diventa uno script di immagini Docker esteso, in cui puoi impilare un numero qualsiasi di servizi fino a quando viene avviato almeno un servizio in primo piano, che anche verso la fine

Quindi il mio file di immagine Docker ha due righe di seguito alla fine:

COPY myStartupScript.sh /usr/local/myscripts/myStartupScript.sh
CMD ["/bin/bash", "/usr/local/myscripts/myStartupScript.sh"]

Nel mio script eseguo tutti MySQL, MongoDB, Tomcat ecc. Alla fine eseguo il mio Apache come thread in primo piano.

source /etc/apache2/envvars
/usr/sbin/apache2 -DFOREGROUND

Ciò mi consente di avviare tutti i miei servizi e mantenere attivo il contenitore con l'ultimo servizio avviato in primo piano

Spero che sia d'aiuto

AGGIORNAMENTO : Dall'ultima volta che ho risposto a questa domanda, sono emerse nuove cose come Docker compose , che può aiutarti a eseguire ogni servizio nel suo contenitore, ma a collegarli tutti insieme come dipendenze tra quei servizi, prova a saperne di più su docker-compose e usalo, è un modo più elegante a meno che il tuo bisogno non corrisponda ad esso.


6

Non sono assolutamente d'accordo con alcune soluzioni precedenti che consigliavano di eseguire entrambi i servizi nello stesso contenitore. È chiaramente indicato nella documentazione che non è raccomandato :

In genere si consiglia di separare le aree problematiche utilizzando un servizio per contenitore. Tale servizio può essere suddiviso in più processi (ad esempio, il server Web Apache avvia più processi di lavoro). Va bene disporre di più processi, ma per ottenere il massimo beneficio da Docker, evitare che un contenitore sia responsabile di molteplici aspetti dell'applicazione complessiva. È possibile connettere più contenitori utilizzando reti definite dall'utente e volumi condivisi.

Esistono buoni casi d'uso per supervisord o programmi simili ma l'esecuzione di un'applicazione web + database non fa parte di essi.

Dovresti assolutamente usare docker-compose per farlo e orchestrare più contenitori con responsabilità diverse.


2
Questo è un commento, non una risposta. Si prega di considerare l'aggiunta di una spiegazione e / o collegamenti per supportare questa posizione. Altrimenti non è utile.
Ivan Ivanov,

1
Questa è una risposta nel senso che la migliore raccomandazione che posso dare in questo caso d'uso è quella di usare docker-compose. Ad ogni modo, hai ragione sul fatto che potrei fornire più collegamenti a raccomandazioni ufficiali. Lo aggiornerò.
nicolas-van,

La domanda riguarda l'esecuzione di 2 processi in un contenitore, quindi non si preoccupa delle migliori pratiche. Ti faccio un esempio: ho dovuto eseguire rabbitmq all'interno dell'immagine basata su PhotonOS e anche un processo java ... Quindi ho usato uno script di entrata e usato come ENTRYPOINT :)
Vallerious

La domanda originale non è una domanda generica sulla fattibilità tecnica dell'esecuzione di due processi in un contenitore Docker. Indica un caso d'uso specifico che è la distribuzione di un'applicazione Python insieme a un database MongoDB. E, per quel caso d'uso, la migliore raccomandazione è di scoraggiare l'uso di un singolo contenitore e raccomandare l'uso di docker-compose.
nicolas-van

5

Possono essere in contenitori separati e, in effetti, se l'applicazione fosse destinata a funzionare in un ambiente più ampio, probabilmente lo sarebbero.

Un sistema multi-contenitore richiederebbe un po 'più di orchestrazione per essere in grado di far emergere tutte le dipendenze richieste, sebbene in Docker v0.6.5 +, ci sia una nuova funzione per aiutare con quella integrata in Docker stesso - Collegamento . Con una soluzione multi-macchina, è comunque qualcosa che deve essere organizzato dall'esterno dell'ambiente Docker.

Con due contenitori diversi, le due parti comunicano comunque su TCP / IP, ma a meno che le porte non siano state bloccate in modo specifico (non consigliato, poiché non si sarebbe in grado di eseguire più di una copia), si dovrà passare la nuova porta che il database è stato esposto per quanto riguarda l'applicazione, in modo che potesse comunicare con Mongo. Anche questo è qualcosa con cui Linking può aiutarti.

Per un'installazione più semplice e di piccole dimensioni, in cui tutte le dipendenze si trovano nello stesso contenitore, è anche possibile avviare sia il database che il runtime Python dal programma inizialmente chiamato come ENTRYPOINT. Questo può essere semplice come uno script di shell o un altro controller di processo: Supervisord è piuttosto popolare ed esistono numerosi esempi nei file Docker pubblici.


3

Sono d'accordo con le altre risposte che è preferibile utilizzare due contenitori, ma se hai il cuore impegnato a raggruppare più servizi in un singolo contenitore puoi usare qualcosa come Supervord.

in Hipache, ad esempio, il Dockerfile incluso esegue supervisord e il file supervisord.conf specifica che devono essere eseguiti sia hipache che redis-server.


2

Docker fornisce un paio di esempi su come farlo. L'opzione leggera è:

Inserisci tutti i tuoi comandi in uno script wrapper, completo di informazioni di test e debug. Esegui lo script wrapper come tuo CMD. Questo è un esempio molto ingenuo. Innanzitutto, lo script wrapper:

#!/bin/bash

# Start the first process
./my_first_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_first_process: $status"
  exit $status
fi

# Start the second process
./my_second_process -D
status=$?
if [ $status -ne 0 ]; then
  echo "Failed to start my_second_process: $status"
  exit $status
fi

# Naive check runs checks once a minute to see if either of the processes exited.
# This illustrates part of the heavy lifting you need to do if you want to run
# more than one service in a container. The container will exit with an error
# if it detects that either of the processes has exited.
# Otherwise it will loop forever, waking up every 60 seconds

while /bin/true; do
  ps aux |grep my_first_process |grep -q -v grep
  PROCESS_1_STATUS=$?
  ps aux |grep my_second_process |grep -q -v grep
  PROCESS_2_STATUS=$?
  # If the greps above find anything, they will exit with 0 status
  # If they are not both 0, then something is wrong
  if [ $PROCESS_1_STATUS -ne 0 -o $PROCESS_2_STATUS -ne 0 ]; then
    echo "One of the processes has already exited."
    exit -1
  fi
  sleep 60
done

Successivamente, Dockerfile:

FROM ubuntu:latest
COPY my_first_process my_first_process
COPY my_second_process my_second_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh

2

È possibile eseguire 2 processi in primo piano utilizzando wait. Basta creare uno script bash con il seguente contenuto. Ad esempio start.sh:

# runs 2 commands simultaneously:

mongod & # your first application
P1=$!
python script.py & # your second application
P2=$!
wait $P1 $P2

Nel tuo Dockerfile, inizia con

CMD bash start.sh

0

Se uno script dedicato sembra eccessivo, puoi generare processi separati in modo esplicito sh -c. Per esempio:

CMD sh -c 'mini_httpd -C /my/config -D &' \
 && ./content_computing_loop
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.