Puis-je exécuter plusieurs programmes dans un conteneur Docker?

150

J'essaie de comprendre Docker à partir du moment où je déploie une application destinée à fonctionner sur les utilisateurs sur le bureau. Mon application est simplement une application web flask et une base de données mongo. Normalement, je voudrais installer à la fois dans une machine virtuelle et transférer un port hôte vers l'application Web invitée. J'aimerais essayer Docker, mais je ne sais pas comment je suis censé utiliser plus d'un programme. Les documentations indiquent qu'il ne peut y avoir que ENTRYPOINT, alors comment puis-je avoir Mongo et mon application flask. Ou doivent-ils se trouver dans des conteneurs séparés, auquel cas comment se parlent-ils et comment cela facilite-t-il la distribution de l'application?

nickponline
la source
2
Spot on: me demande pourquoi docker était si populaire .. (processus unique ..?) - mais voyons ce que les réponses nous disent ..
javadba

Réponses:

120

Il ne peut y avoir qu'un seul POINT D'ENTREE, mais cette cible est généralement un script qui lance autant de programmes que nécessaire. Vous pouvez en outre utiliser par exemple Supervisord ou similaire pour prendre en charge le lancement de plusieurs services dans un seul conteneur. Ceci est un exemple de conteneur docker exécutant mysql, apache et wordpress dans un seul conteneur .

Dites, vous avez une base de données utilisée par une seule application Web. Ensuite, il est probablement plus facile d'exécuter les deux dans un seul conteneur.

Si vous disposez d'une base de données partagée utilisée par plusieurs applications, il serait préférable d'exécuter la base de données dans son propre conteneur et les applications chacune dans leurs propres conteneurs.

Il existe au moins deux possibilités pour les applications de communiquer entre elles lorsqu'elles s'exécutent dans des conteneurs différents:

  1. Utilisez les ports IP exposés et connectez-vous via eux.
  2. Les versions récentes du docker prennent en charge la liaison .
vesako
la source
1
Il semble que les nouvelles versions de Docker prennent désormais en charge les réseaux de conteneurs Docker .
jpierson
Docker prend désormais en charge d'exécuter Superviseur, vous permettant de sepcify comportement pour chaque processus tels que autorestart = true, stdout_logfile, stderr_logfile etc. Jetez un oeil à docs.docker.com/engine/admin/using_supervisord
Andreas Lundgren
5
Je ne recommanderais certainement pas d'essayer d'exécuter l'application Web et mongodb dans le même conteneur dans cet exemple. Il existe de bons cas d'utilisation de supervisord ou de processus similaires de type init dans Docker, mais celui-ci n'en fait pas partie. Il est beaucoup plus simple d'utiliser docker-compose pour simplement exécuter les deux services dans des conteneurs séparés.
nicolas-van
@ nicolas-van pourquoi est-ce plus simple? Est-ce parce que si la base de données meurt, je peux redémarrer le conteneur de la base de données au lieu d'avoir à redémarrer le tout?
brillout
Les applications sur la même machine peuvent également communiquer via des sockets de domaine Unix . La plus haute performance garantie.
Skeptical Jule le
21

J'avais une exigence similaire d'exécuter une pile LAMP, Mongo DB et mes propres services

Docker est une virtualisation basée sur le système d'exploitation, c'est pourquoi il isole son conteneur autour d'un processus en cours d'exécution, il nécessite donc au moins un processus s'exécutant dans FOREGROUND.

Ainsi, vous fournissez votre propre script de démarrage comme point d'entrée, ainsi votre script de démarrage devient un script d'image Docker étendu, dans lequel vous pouvez empiler n'importe quel nombre de services dans la mesure où AU MOINS UN SERVICE PRÉCÉDENT EST DÉMARRÉ, TROP VERS LA FIN

Donc, mon fichier image Docker a deux lignes ci-dessous à la toute fin:

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

Dans mon script, j'exécute tout MySQL, MongoDB, Tomcat, etc. En fin de compte, je lance mon Apache en tant que thread de premier plan.

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

Cela me permet de démarrer tous mes services et de maintenir le conteneur en vie avec le dernier service commencé étant au premier plan

J'espère que ça aide

MISE À JOUR : Depuis ma dernière réponse à cette question, de nouvelles choses sont apparues comme Docker compose , qui peut vous aider à exécuter chaque service sur son propre conteneur, tout en les liant tous ensemble en tant que dépendances parmi ces services, essayez d'en savoir plus sur docker-compose et utilisez-le, c'est de manière plus élégante à moins que votre besoin ne corresponde pas à celui-ci.

Basav
la source
6

Je ne suis pas du tout d'accord avec certaines solutions précédentes qui recommandaient d'exécuter les deux services dans le même conteneur. Il est clairement indiqué dans la documentation que ce n'est pas recommandé :

Il est généralement recommandé de séparer les domaines de préoccupation en utilisant un service par conteneur. Ce service peut se diviser en plusieurs processus (par exemple, le serveur Web Apache démarre plusieurs processus de travail). Il est normal d'avoir plusieurs processus, mais pour tirer le meilleur parti de Docker, évitez qu'un conteneur soit responsable de plusieurs aspects de votre application globale. Vous pouvez connecter plusieurs conteneurs à l'aide de réseaux définis par l'utilisateur et de volumes partagés.

Il existe de bons cas d'utilisation de supervisord ou de programmes similaires, mais l'exécution d'une application Web + base de données n'en fait pas partie.

Vous devez absolument utiliser docker-compose pour ce faire et orchestrer plusieurs conteneurs avec des responsabilités différentes.

Nicolas-van
la source
2
Ceci est un commentaire, pas une réponse. Veuillez envisager d'ajouter une explication et / ou des liens pour soutenir cette position. Sinon, ce n'est pas utile.
Ivan Ivanov
1
C'est une réponse dans le sens où la meilleure recommandation que je puisse donner dans un tel cas d'utilisation est d'utiliser docker-compose. Quoi qu'il en soit, vous avez raison de dire que je pourrais donner plus de liens vers des recommandations officielles. Je vais mettre à jour cela.
nicolas-van
La question est d'exécuter 2 processus dans un conteneur, donc ne se soucie pas des meilleures pratiques. Je vais vous donner un exemple: j'ai dû exécuter rabbitmq dans une image basée sur PhotonOS et un processus java aussi ... J'ai donc utilisé un script d'entrée et utilisé comme ENTRYPOINT :)
Vallerious
La question d'origine n'est pas une question générique sur la faisabilité technique de l'exécution de deux processus dans un conteneur Docker. Il énonce un cas d'utilisation spécifique qui est le déploiement d'une application Python avec une base de données MongoDB. Et, pour ce cas d'utilisation, la meilleure recommandation est de décourager l'utilisation d'un seul conteneur et de recommander l'utilisation de docker-compose.
nicolas-van
5

Ils peuvent se trouver dans des conteneurs séparés et, en fait, si l'application était également destinée à s'exécuter dans un environnement plus grand, ils le seraient probablement.

Un système multi-conteneurs nécessiterait plus d'orchestration pour être en mesure de mettre en place toutes les dépendances requises, bien que dans Docker v0.6.5 +, il existe une nouvelle fonctionnalité pour aider celle intégrée à Docker lui-même - Linking . Avec une solution multi-machines, c'est toujours quelque chose qui doit être organisé de l'extérieur de l'environnement Docker.

Avec deux conteneurs différents, les deux parties communiquent toujours via TCP / IP, mais à moins que les ports n'aient été verrouillés spécifiquement (non recommandé, car vous ne pourriez pas exécuter plus d'une copie), vous devrez passer le nouveau port que la base de données a été exposée comme à l'application, afin qu'elle puisse communiquer avec Mongo. C'est encore une fois quelque chose pour lequel Linking peut vous aider.

Pour une petite installation plus simple, où toutes les dépendances vont dans le même conteneur, il est également possible de démarrer à la fois la base de données et le runtime Python par le programme initialement appelé ENTRYPOINT. Cela peut être aussi simple qu'un script shell, ou un autre contrôleur de processus - Supervisord est assez populaire, et un certain nombre d'exemples existent dans les Dockerfiles publics.

Alister Bulman
la source
3

Je suis d'accord avec les autres réponses selon lesquelles l'utilisation de deux conteneurs est préférable, mais si vous avez à cœur de regrouper plusieurs services dans un seul conteneur, vous pouvez utiliser quelque chose comme supervisord.

dans Hipache par exemple, le Dockerfile inclus exécute supervisord, et le fichier supervisord.conf spécifie à la fois hipache et redis-server à exécuter.

Ben Schwartz
la source
2

Docker fournit quelques exemples sur la façon de procéder. L'option légère consiste à:

Mettez toutes vos commandes dans un script wrapper, avec des informations de test et de débogage. Exécutez le script wrapper en tant que votre CMD. C'est un exemple très naïf. Tout d'abord, le 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

Ensuite, le 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
OzNetNerd
la source
2

Vous pouvez exécuter 2 processus au premier plan en utilisant wait. Créez simplement un script bash avec le contenu suivant. Par exemple start.sh:

# runs 2 commands simultaneously:

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

Dans votre Dockerfile, démarrez-le avec

CMD bash start.sh
Sam
la source
0

Si un script dédié semble trop lourd, vous pouvez générer des processus distincts explicitement avec sh -c. Par exemple:

CMD sh -c 'mini_httpd -C /my/config -D &' \
 && ./content_computing_loop
Raphael
la source