Docker est une technologie permettant d’emballer les composants de votre pile sous forme de conteneurs isolés. Il est courant d’exécuter chacun de vos processus dans son propre conteneur, créant ainsi une séparation nette entre les composants. Cela améliore la modularité et vous permet d’accéder aux avantages d’évolutivité de la conteneurisation.
Il peut toujours y avoir des situations où vous souhaitez exécuter plusieurs services dans un même conteneur. Bien que cela ne soit pas naturel dans l’écosystème Docker, nous allons montrer quelques approches différentes que vous pouvez utiliser pour créer des conteneurs avec plusieurs processus de longue durée.
Identification du problème
Les conteneurs Docker exécutent un seul processus de premier plan. Ceci est défini par l’image ENTRYPOINT
et CMD
des instructions. ENTRYPOINT
est défini dans une image Dockerfile
tandis que CMD
peut être remplacé lors de la création de conteneurs. Les conteneurs s’arrêtent automatiquement lorsque leur processus de premier plan se termine.
Vous pouvez lancer d’autres processus à partir du CMD
mais le conteneur ne restera en cours d’exécution que tant que le processus de premier plan d’origine est actif. Maintenir le conteneur opérationnel pendant la durée de vie combinée de deux services indépendants n’est pas directement possible en utilisant le ENTRYPOINT/CMD
mécanisme.
Envelopper plusieurs processus dans un seul point d’entrée
Les scripts wrapper sont la solution la plus simple au problème. Vous pouvez écrire un script qui démarre tous vos processus et attend qu’ils se terminent. Définir le script comme votre Docker ENTRYPOINT
l’exécutera en tant que processus de premier plan du conteneur, en gardant le conteneur en cours d’exécution jusqu’à ce que l’un des scripts encapsulés se termine.
#!/bin/bash /opt/first-process & /opt/second-process & wait -n exit $?
Ce script lance le /opt/first-process
et /opt/second-process
binaires à l’intérieur du conteneur. L’utilisation de &
permet au script de continuer sans attendre la fin de chaque processus. wait
est utilisé pour suspendre le script jusqu’à ce que l’un des processus se termine. Le script se termine ensuite avec le code d’état émis par le script terminé.
Ce modèle permet au conteneur d’exécuter à la fois first-process
et second-process
jusqu’à ce que l’un d’eux sorte. À ce stade, le conteneur s’arrêtera, même si l’autre processus est toujours en cours d’exécution.
Pour utiliser ce script, modifiez votre image Docker ENTRYPOINT
et CMD
pour en faire le processus de premier plan du conteneur :
ENTRYPOINT ["/bin/sh"] CMD ["./path/to/script.sh"]
La --init
Option de conteneur
L’un des défis de la gestion des processus de conteneurs consiste à nettoyer efficacement à leur sortie. Docker exécute votre CMD
en tant que processus ID 1, ce qui le rend responsable de la gestion des signaux et de l’élimination des zombies. Si votre script ne dispose pas de ces fonctionnalités, vous pourriez vous retrouver avec des processus enfants orphelins persistants dans votre conteneur.
La docker run
la commande a un --init
drapeau qui modifie le point d’entrée à utiliser tini
comme PID 1. Il s’agit d’une implémentation minimale du processus d’initialisation qui exécute votre CMD
gère la transmission du signal et récolte continuellement des zombies.
Cela vaut la peine d’utiliser --init
si vous vous attendez à générer de nombreux processus et que vous ne souhaitez pas gérer manuellement le nettoyage. Tini est une saveur init légère conçue pour les conteneurs. C’est beaucoup plus petit que des alternatives à part entière comme systemd
et upstart
.
Utiliser un gestionnaire de processus dédié
Les scripts manuels deviennent rapidement sous-optimaux lorsque vous avez de nombreux processus à gérer. Adopter un gestionnaire de processus est une autre façon d’exécuter plusieurs services dans vos conteneurs Docker. Le gestionnaire de processus devient votre ENTRYPOINT
et est responsable du démarrage, de la maintenance et du nettoyage après vos processus de travail.
Plusieurs options sont disponibles lors de la mise en œuvre de cette approche. supervisord
est un choix populaire qui est facilement configuré via un /etc/supervisor/conf.d/supervisord.conf
dossier:
[program:apache2] command=/usr/sbin/apache2 -DFOREGROUND [program:mysqld] command=/usr/sbin/mysqld_safe
Ce fichier de configuration configure supervisord
pour démarrer Apache et MySQL. Pour l’utiliser dans un conteneur Docker, ajoutez tous les packages requis à votre image, puis copiez votre supervisord
fichier de configuration à l’emplacement correct. Régler supervisord
comme l’image CMD
pour l’exécuter automatiquement au démarrage des conteneurs.
FROM ubuntu:latest RUN apt-get install -y apache2 mysql-server supervisor COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf ENTRYPOINT ["/bin/sh"] CMD ["/usr/bin/supervisord"]
Car supervisord
s’exécute en continu, il n’est pas possible d’arrêter le conteneur lorsque l’un de vos processus surveillés se termine. Une option alternative est s6-overlay
qui a cette capacité. Il utilise un modèle de service déclaratif dans lequel vous placez des scripts de service directement dans /etc/services.d
:
# Add s6-overlay to your image ADD https://github.com/just-containers/s6-overlay/releases/download/v3.1.0.0/s6-overlay-noarch.tar.xz /tmp RUN tar -C / -Jxpf /tmp/s6-overlay-noarch.tar.xz RUN printf "#!/bin/shn/usr/sbin/apache2 -DFOREGROUND" > /etc/services.d/first-service/run RUN chmod +x /etc/services.d/first-service/run # Use s6-overlay as your image's entrypoint ENTRYPOINT ["/init"]
Vous pouvez ajouter un exécutable finish
script dans vos répertoires de service pour gérer l’arrêt du conteneur avec docker stop
. s6-overlay
exécutera automatiquement ces scripts lorsque son processus recevra un TERM
signal en raison de la stop
commande.
Les scripts de finition reçoivent le code de sortie de leur service comme premier argument. Le code est défini sur 256 lorsque le service est interrompu en raison d’un signal non capté. Le script doit écrire le code de sortie final pour /run/s6-linux-init-container-results/exitcode
; s6-overlay lit ce fichier et se termine avec la valeur qu’il contient, ce qui fait que ce code est utilisé comme code d’arrêt de votre conteneur.
#!/bin/sh echo "$1" > /run/s6-linux-init-container-results/exitcode
Quand devez-vous exécuter plusieurs processus dans un conteneur ?
Cette technique est mieux utilisée avec des processus étroitement couplés que vous ne pouvez pas séparer pour les exécuter en tant que conteneurs indépendants. Vous pouvez avoir un programme qui s’appuie sur un utilitaire d’assistance en arrière-plan ou une application monolithique qui effectue sa propre gestion des processus individuels. Les techniques présentées ci-dessus peuvent vous aider à conteneuriser ces types de logiciels.
L’exécution de plusieurs processus dans un conteneur doit toujours être évitée dans la mesure du possible. S’en tenir à un seul processus de premier plan maximise l’isolement, empêche les composants d’interférer les uns avec les autres et améliore votre capacité à déboguer et tester des éléments spécifiques. Vous pouvez mettre à l’échelle les composants individuellement à l’aide d’orchestrateurs de conteneurs, ce qui vous donne la possibilité d’exécuter davantage d’instances de vos processus les plus gourmands en ressources.
Conclusion
Les conteneurs ont généralement un processus de premier plan et s’exécutent aussi longtemps qu’il est actif. Ce modèle s’aligne sur les meilleures pratiques de conteneurisation et vous permet de tirer le meilleur parti de la technologie.
Dans certaines situations, vous pouvez avoir besoin de plusieurs processus pour s’exécuter dans un conteneur. Comme toutes les images ont finalement un seul point d’entrée, vous devez écrire un script wrapper ou ajouter un gestionnaire de processus qui se charge de démarrer vos binaires cibles.
Les gestionnaires de processus vous donnent tout ce dont vous avez besoin, mais gonflent vos images avec des packages et une configuration supplémentaires. Les scripts wrapper sont plus simples mais peuvent devoir être associés à Docker --init
drapeau pour empêcher la prolifération des processus zombies.