{{indexmenu_n>25}} # Utiliser un système d'initialisation Si vous utilisez un script shell comme entrypoint, la documentation sur [[technique:docker:good_practices:multi|les entrypoints et les processus multiples]] sera utile en premier lieu. ## Problématique Parfois, le `Dockerfile` spécifie une commande (`CMD`) qui s'exécute en arrière-plan (comme un démon). Or Docker a besoin que le premier processus qui s'exécute dans le conteneur s'exécute en premier plan, sans quoi il s'éteint. Autre problème, même si la commande s'exécute en premier plan, elle porte le PID 1. Le premier processus d'un conteneur (de PID 1) est souvent référencé comme `init`, en référence [aux systèmes Unix](https://fr.wikipedia.org/wiki/Init). Ce processus est le parent de tous les autres, et doit transmettre les signaux qu'il reçoit à ses enfants (par exemple, un signal de terminaison). Un peu d'explications : un **signal**, au sens Linux, est une sorte de notification asynchrone que l'on peut envoyer à un processus. Il existe de nombreux signaux, par exemple : * `SIGTERM`, pour demander à un processus de se terminer * `SIGINT`, envoyé avec un `Ctrl+C`, par exemple * `SIGKILL`, pour tuer un processus * `SIGHUP`, souvent utilisé pour recharger la configuration d'un service Ces signaux peuvent être envoyés avec la commande `kill`. Les processus peuvent enregistrer des *handlers*, qui sont exécutés lorsqu'un signal d'un certain type est reçu. Si jamais un processus n'enregistre pas de *handler* pour un signal particulier, le noyau passe au comportement par défaut : tuer le processus. Sauf... pour le processus de PID 1. Dans ce cas, il n'y a pas de comportement par défaut. Concrètement, lorsque l'on fait un `docker stop`, un `SIGTERM` est envoyé au processus de PID 1. Si celui-ci n'a pas de *handler* pour `SIGTERM`, il ne se passe rien car il n'y a pas de comportement par défaut, et au bout d'un timeout assez long (~30 secondes), Docker envoie un `SIGKILL`. Or, la plupart des applications lancées avec le PID 1 (par exemple Python) n'ont pas de *handlers*. ## Solution Compose, depuis la version 3.7, adresse ce problème avec une directive très simple : ```yaml services: exemple: init: true ``` Cette directive a pour effet d'exécuter [tini](https://github.com/krallin/tini) en PID 1, puis la commande ou l'entrypoint en tant qu'enfant. Tini va : * S'exécuter en premier plan. * S'assurer qu'il n'y a pas de [processus zombie](https://en.wikipedia.org/wiki/Zombie_process), qui peuvent à forcer remplir la table des processus sur l'hôte. * Transmettre les signaux aux enfants : comme ils n'ont pas le PID 1, alors le fonctionnement par défaut (à savoir tuer le processus s'il n'a pas installé de *handler*) fonctionne. * Attendre la terminaison de son enfant pour terminer, même si celui-ci s'exécute en arrière plan. * Terminer avec le code de retour de son enfant, ce qui permet de savoir s'il y a eu une erreur ou non. Un rôle subsidiaire du processus `init`, sur les systèmes Linux, est justement de faire le ménage dans les processus zombie.