Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentes Révision précédente
Prochaine révision
Révision précédente
technique:docker:good_practices:multi [2020/10/13 15:14] qduchemitechnique:docker:good_practices:multi [2022/05/24 20:58] (Version actuelle) ppom
Ligne 18: Ligne 18:
  
 <bootnote question> <bootnote question>
-Quel est le risque ?+Quels sont les risques ?
 </bootnote> </bootnote>
  
Ligne 34: Ligne 34:
 ENTRYPOINT [ "/entrypoint.sh" ] ENTRYPOINT [ "/entrypoint.sh" ]
 # Notez qu'on lance nginx en premier plan # Notez qu'on lance nginx en premier plan
-CMD [ "nginx", "-g", "daemon-off" ]+CMD [ "nginx", "-g", "daemon-off;" ]
 ``` ```
  
Ligne 88: Ligne 88:
 L'entrypoint a été remplacé par nginx. Il reçoit correctement les signaux. L'entrypoint a été remplacé par nginx. Il reçoit correctement les signaux.
  
-<bootnote question>Est-ce-que c'est suffisant ?</bootnote>+## Entrypoint qui lance plusieurs services 
 + 
 +<bootnote warning>Attention, la philosophie Docker se résume généralement en : *un conteneur, un processus*. En réalité, c'est plutôt **un conteneur, un service**. Il y a donc des cas où il est légitime que plusieurs processus tournent simultanément, mais s'il s'agit de parties bien cloisonnées d'une application (*e.g.* serveur web et serveur applicatif), il est préférable de les faire tourner dans deux conteneurs séparés.</bootnote> 
 + 
 +Un entrypoint qui lance plusieurs services pourrait ressembler à ceci : 
 + 
 +```bash 
 +#!/bin/sh 
 + 
 +# Injection de secrets 
 +sed [...] 
 + 
 +# Lancement de PHP en arrière plan 
 +php-fpm & 
 + 
 +# Lancement de nginx en premier plan 
 +exec nginx -g 'daemon off;' 
 +``` 
 + 
 +Après lancement, la situation est la suivante : 
 + 
 +``` 
 +NOM               PID 
 +nginx             1 
 +  |__php-fpm      2 
 +``` 
 + 
 +Pourquoi ? Tout simplement parce que `nginx` s'est substitué au shell via `exec`, **mais** il a aussi hérité des processus enfants du shell, comme `php-fpm`. 
 + 
 +Ici, on se retrouve avec une problématique similaire : `nginx` va bien recevoir les signaux, mais ne les transmet pas à ses enfants. Et pour le coup, on ne peut pas ré-utiliser un `exec`, car `nginx` a toujours besoin de s'exécuter. 
 + 
 +Dans ce cas précis, il va falloir utiliser des astuces plus ou moins sales. 
 + 
 +<bootnote web>Docker propose une [documentation sur ce sujet](https://docs.docker.com/config/containers/multi-service_container/).</bootnote> 
 + 
 +En gros, il y a deux solutions : 
 + 
 +* Utiliser [supervisord](http://supervisord.org/). C'est plutôt la moyenne artillerie, mais ça permet de faire ce que l'on veut. `supervisord` est un processus d'initialisation, il va s'exécuter en tant que PID 1 et assumer toutes ses fonctions. C'est ce qui a été retenu pour [pica-nginx](https://gitlab.utc.fr/picasoft/projets/services/nginx). 
 +* Faire du cas par cas. Par exemple, si on sait qu'un processus enfant doit pouvoir recevoir un signal important, qu'on connaît à l'avance, on utilisera un `trap`. 
 + 
 +Les trap sont des *handlers* de signaux. On ne développe pas ce point, mais c'est la solution retenue pour [Mumble](https://gitlab.utc.fr/picasoft/projets/services/mumble). 
 + 
 +Voici un extrait de son entrypoint : 
 + 
 +```bash 
 +python3 /exporter.py & 
 + 
 +# Trap SIGUSR1 signal to reload certificates without restarting 
 +_reload() { 
 +  echo "Caught SIGUSR1 signal!" 
 +  /usr/bin/pkill -USR1 murmurd 
 +  wait 
 +
 +trap _reload SIGUSR1 
 + 
 +# Run murmur 
 +murmurd -v -ini $CONFIG_FILE 
 +wait 
 +``` 
 + 
 +<bootnote>Ici, `python` et `murmurd` sont lancés en arrière plan. Le shell attend ensuite que les processus terminent. Dès qu'un signal `USR1` est reçu, il est capté par l'instruction `trap` et la fonction `_reload` s'exécute. Elle a pour effet de transmettre le signal à Murmur, puis on attend de nouveau. C'est un peu *hackish*, mais dans ce cas spécifique, c'est suffisant car on a pas réellement besoin de transmettre tous les signaux à Murmur.</bootnote> 
 + 
 +<bootnote warning>Dans ce cas, un `docker stop` terminera **quand même** en timeout puis en `SIGKILL`, car l'entrypoint ne fait rien du `SIGTERM`. On pourrait implémenter un *handler* pour `SIGTERM` qui l'envoie aux processus enfants, et ce serait même plus propre. C'est laissé à l'appréciation de chacun·e.</bootnote> 
 + 
 +## Est-ce-que c'est suffisant ? 
 + 
 +Dans cette page, nous avons montré comment faire en sorte que les processus d'un conteneur Docker reçoivent les signaux qui leur sont destinés.  
 + 
 +En revanche, ca ne règle pas tous les problèmes, car les processus qui ont un PID 1 sont traités spécialement.  
 + 
 +<bootnote warning>En particulier, un processus avec un PID de 1 n'a pas de comportement par défaut quand il reçoit un signal qu'il ne traite pas explicitement, ce qui peut être problématique. Voir la [[technique:docker:good_practices:init|documentation sur l'utilisation d'un système d'initialisation]] pour parfaire la configuration.</bootnote>
  
-Ça ne règle pas tous les problèmes, car les processus qui ont un PID 1 sont traités spécialement. Voir la [[technique:docker:good_practices:init|documentation sur l'utilisation d'un système d'initialisation]] pour parfaire la configuration. 
  • technique/docker/good_practices/multi.1602594884.txt.gz
  • de qduchemi