⚠️ Traduction non officielle - Cette documentation est une traduction communautaire non officielle de Docker.

Exécuter plusieurs processus dans un conteneur

Le processus principal en cours d'exécution d'un conteneur est l'ENTRYPOINT et/ou CMD à la fin du Dockerfile. C'est une bonne pratique de séparer les domaines de préoccupation en utilisant un service par conteneur. Ce service peut se forker en plusieurs processus (par exemple, le serveur web Apache démarre plusieurs processus worker). Il est acceptable d'avoir plusieurs processus, mais pour tirer le meilleur parti de Docker, évitez qu'un conteneur soit responsable de multiples aspects de votre application globale. Vous pouvez connecter plusieurs conteneurs en utilisant des réseaux définis par l'utilisateur et des volumes partagés.

Le processus principal du conteneur est responsable de la gestion de tous les processus qu'il démarre. Dans certains cas, le processus principal n'est pas bien conçu, et ne gère pas gracieusement la "moisson" (arrêt) des processus enfants lorsque le conteneur se ferme. Si votre processus appartient à cette catégorie, vous pouvez utiliser l'option --init lorsque vous exécutez le conteneur. Le drapeau --init insère un petit processus init dans le conteneur comme processus principal, et gère la moisson de tous les processus lorsque le conteneur se ferme. Gérer de tels processus de cette manière est supérieur à l'utilisation d'un processus init complet tel que sysvinit ou systemd pour gérer le cycle de vie des processus dans votre conteneur.

Si vous devez exécuter plus d'un service dans un conteneur, vous pouvez y parvenir de plusieurs manières différentes.

Utiliser un script wrapper

Mettez toutes vos commandes dans un script wrapper, complet avec des informations de test et de débogage. Exécutez le script wrapper comme votre CMD. Voici un exemple naïf. D'abord, le script wrapper :

#!/bin/bash

# Démarrer le premier processus
./my_first_process &

# Démarrer le second processus
./my_second_process &

# Attendre qu'un processus se termine
wait -n

# Sortir avec le statut du processus qui s'est terminé en premier
exit $?

Ensuite, le Dockerfile :

# syntax=docker/dockerfile:1
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

Utiliser les contrôles de tâches Bash

Si vous avez un processus principal qui doit démarrer en premier et rester en cours d'exécution mais vous avez temporairement besoin d'exécuter d'autres processus (peut-être pour interagir avec le processus principal) alors vous pouvez utiliser le contrôle de tâches de bash. D'abord, le script wrapper :

#!/bin/bash

# activer le contrôle de tâches de bash
set -m

# Démarrer le processus principal et le mettre en arrière-plan
./my_main_process &

# Démarrer le processus helper
./my_helper_process

# le my_helper_process pourrait avoir besoin de savoir comment attendre
# que le processus principal démarre avant de faire son travail et retourner


# maintenant nous ramenons le processus principal au premier plan
# et l'y laissons
fg %1
# syntax=docker/dockerfile:1
FROM ubuntu:latest
COPY my_main_process my_main_process
COPY my_helper_process my_helper_process
COPY my_wrapper_script.sh my_wrapper_script.sh
CMD ./my_wrapper_script.sh

Utiliser un gestionnaire de processus

Utilisez un gestionnaire de processus comme supervisord. C'est plus complexe que les autres options, car cela nécessite d'inclure supervisord et sa configuration dans votre image (ou baser votre image sur une qui inclut supervisord), ainsi que les différentes applications qu'il gère. Ensuite vous démarrez supervisord, qui gère vos processus pour vous.

L'exemple de Dockerfile suivant montre cette approche. L'exemple suppose que ces fichiers existent à la racine du contexte de build :

  • supervisord.conf
  • my_first_process
  • my_second_process
# syntax=docker/dockerfile:1
FROM ubuntu:latest
RUN apt-get update && apt-get install -y supervisor
RUN mkdir -p /var/log/supervisor
COPY supervisord.conf /etc/supervisor/conf.d/supervisord.conf
COPY my_first_process my_first_process
COPY my_second_process my_second_process
CMD ["/usr/bin/supervisord"]

Si vous voulez vous assurer que les deux processus sortent leur stdout et stderr vers les logs du conteneur, vous pouvez ajouter ce qui suit au fichier supervisord.conf :

[supervisord]
nodaemon=true
logfile=/dev/null
logfile_maxbytes=0

[program:app]
stdout_logfile=/dev/fd/1
stdout_logfile_maxbytes=0
redirect_stderr=true