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:general:tips [2020/10/12 14:12] qduchemitechnique:docker:general:tips [2020/10/13 18:53] (Version actuelle) – [Spécifier un utilisateur lors de l'exécution de commandes] qduchemi
Ligne 12: Ligne 12:
 Chaque élément d'une image peut être un facteur de vulnérabilité ; même un paquet en apparence inoffensif peut dépendre d'une librairie contenant une vulnérabilité. Pour cette raison, il convient de réaliser des images aussi légères que possibles en évitant d'installer des paquets superflus ou en supprimant les paquets installés pour un besoin temporaire (par exemple pour compiler un programme) une fois qu'ils sont obsolètes. Chaque élément d'une image peut être un facteur de vulnérabilité ; même un paquet en apparence inoffensif peut dépendre d'une librairie contenant une vulnérabilité. Pour cette raison, il convient de réaliser des images aussi légères que possibles en évitant d'installer des paquets superflus ou en supprimant les paquets installés pour un besoin temporaire (par exemple pour compiler un programme) une fois qu'ils sont obsolètes.
  
 +<bootnote>
 Préférez vous baser sur une image Alpine (peu de paquets, donc peu de vulnérabilités) ou Debian. Préférez vous baser sur une image Alpine (peu de paquets, donc peu de vulnérabilités) ou Debian.
 Pour Debian, préférez la version stable la plus récente possible (Buster plutôt que Stretch) pour mitiger d'emblée un grand nombre de vulnérabilités. Pour Debian, préférez la version stable la plus récente possible (Buster plutôt que Stretch) pour mitiger d'emblée un grand nombre de vulnérabilités.
 +</bootnote>
  
 Préférez également les versions `slim`, qui contiennent moins de paquets et suffisent souvent. Préférez également les versions `slim`, qui contiennent moins de paquets et suffisent souvent.
 +
 +Pour les services basés sur un langage interprété comme Python, utilisez l'image officielle en appliquant les principes précédents.
 +
 +<bootnote>
 +Il peut être intéressant d'avoir recours à des [[https://docs.docker.com/develop/develop-images/multistage-build/|multi-stage builds]]. L'idée est par exemple d'utiliser une image pour la compilation, et une image qui recevra uniquement l'exécutable et les dépendances nécessaires à l'exécution. Cette dernière sera utilisée en production.
 +</bootnote>
  
 ## Rendre les build reproductibles ## Rendre les build reproductibles
  
-L'idée derrière un build "reproductible", c'est que si je me rends sur un ancien commit de ce dépôt et que je lance un `docker build` dans un dossier, comme `pica-mattermost`, l'image finale doit être la même quel que soit le temps écoulé depuis ce commit+L'idée derrière un build "reproductible", c'est que si je lance le build d'un même `Dockerfileà deux moments différents, l'image finale doit être la même quel que soit le temps écoulé entre les deux
  
 <bootnote warning>Ce ne sont pas de **vrais** builds reproductibles, car la version des paquets installés peut avoir changé, par exemple. Mais l'idée est d'essayer de s'en rapprocher.</bootnote> <bootnote warning>Ce ne sont pas de **vrais** builds reproductibles, car la version des paquets installés peut avoir changé, par exemple. Mais l'idée est d'essayer de s'en rapprocher.</bootnote>
Ligne 34: Ligne 42:
  
 En outre il existe deux solutions pour récupérer du code existant, versionné sur un dépôt Git distant : En outre il existe deux solutions pour récupérer du code existant, versionné sur un dépôt Git distant :
 +
 +* Utiliser un `wget` sur une release particulière (Gitlab, Github), permettant de récupérer une archive contenant le code source d'une version spécifique.
 * Installer Git dans le `Dockerfile`, utiliser un `git clone` puis un `git checkout <tag>` sur la version souhaitée et copier le code dans l'image. * Installer Git dans le `Dockerfile`, utiliser un `git clone` puis un `git checkout <tag>` sur la version souhaitée et copier le code dans l'image.
-* Utiliser un [submodule](https://git-scm.com/book/fr/v2/Utilitaires-Git-Sous-modules) dans le dossier du service, en particulier si le dépôt où se trouve le code est de petite taille et qu'il n'utilise pas les tags. En effet, comme un submodule est lié à un numéro de commit, chaque commit de ce dépôt sera associé à un commit précis du dépôt distant. On peut donc retrouver l'état du code distant avec le numéro de commit du submodule associé au commit local. 
  
 <bootnote>En général, on préférera télécharger une release du code que d'utiliser Git.</bootnote> <bootnote>En général, on préférera télécharger une release du code que d'utiliser Git.</bootnote>
Ligne 41: Ligne 50:
 ## Exécution de commandes au démarrage ## Exécution de commandes au démarrage
  
-Pour lancer directement le binaire d'un service au démarrage, on utilisera la directive [CMD](https://docs.docker.com/engine/reference/builder/#cmd) avec la forme tableau (`[ "commande", "arg1", "arg2" ]`).+Pour lancer directement le binaire d'un service au démarrage, on utilisera la directive [CMD](https://docs.docker.com/engine/reference/builder/#cmd) avec la forme tableau (`[ "commande", "arg1", "arg2" ]`). En effet, cette forme permet de démarrer le processus directement, tandis que la forme sans tableau est exécutée par `/bin/sh`, ce qui pose des problèmes ([explications ici](https://engineeringblog.yelp.com/2016/01/dumb-init-an-init-for-docker.html)).
  
 Lorsque l'on a besoin d'exécuter des instructions préalables (injection de secrets, test du contact avec la base de données, etc...), on utilisera la directive [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) en conjonction avec `CMD`, toujours sous la forme tableau. Lorsque l'on a besoin d'exécuter des instructions préalables (injection de secrets, test du contact avec la base de données, etc...), on utilisera la directive [ENTRYPOINT](https://docs.docker.com/engine/reference/builder/#entrypoint) en conjonction avec `CMD`, toujours sous la forme tableau.
Ligne 75: Ligne 84:
 <bootnote warning>Souvent, les commandes comme `curl` et `wget` ne sont pas installées, il faut y penser.</bootnote> <bootnote warning>Souvent, les commandes comme `curl` et `wget` ne sont pas installées, il faut y penser.</bootnote>
  
-Notez que lorsqu'un `HEALTHCHECK` est présent, Traefik ne prend pas en compte le conteneur tant que celui-ci n'est pas noté `healthy`Si l'intervalle de vérification est d'une minute, il faudra donc au moins une minute pour que le conteneur soit accessible sur Internet.+<bootnote web>Référence pour les `HEALTHCHECK` : https://docs.docker.com/engine/reference/builder/#healthcheck</bootnote>
  
-Si le service est "critique", il faudra donc choisir un intervalle court. +## Ne pas utiliser les directives VOLUME
- +
-Référence : https://docs.docker.com/engine/reference/builder/#healthcheck +
- +
-## Montage de volumes+
  
 Lors de la rédaction d'images, on peut être tenté d'exposer des volumes sur des images "temporaires". Par exemple, une image `nginx` dans laquelle on va indiquer que `/var/www/html` doit être persistent grâce à la directive `VOLUME`. Lors de la rédaction d'images, on peut être tenté d'exposer des volumes sur des images "temporaires". Par exemple, une image `nginx` dans laquelle on va indiquer que `/var/www/html` doit être persistent grâce à la directive `VOLUME`.
Ligne 88: Ligne 93:
  
 On évitera donc les directives `VOLUME` au sein des `Dockerfile`, et on spécifiera les volumes au lancement du conteneur. On évitera donc les directives `VOLUME` au sein des `Dockerfile`, et on spécifiera les volumes au lancement du conteneur.
- 
-Il convient également de ne pas monter de volume sensible (par exemple ''/etc'') dans un conteneur, parce que les conteneurs peuvent par défaut modifier les volumes montés avec des privilèges ''root''. Ainsi, il ne faut surtout pas monter la socket Docker (''/var/run/docker/sock'') dans un conteneur (sauf raison exceptionnelle, *i.e.* Traefik). 
  
 ## Spécifier un utilisateur lors de l'exécution de commandes ## Spécifier un utilisateur lors de l'exécution de commandes
  
 Dans un `Dockerfile`, une commande exécutée par une directive ''RUN'' est exécutée par le compte root du conteneur par défaut. Il convient d'exécuter aussi peu de commandes que possible avec le compte root ; pour se faire, il est possible d'utiliser la directive ''USER''. Dans un `Dockerfile`, une commande exécutée par une directive ''RUN'' est exécutée par le compte root du conteneur par défaut. Il convient d'exécuter aussi peu de commandes que possible avec le compte root ; pour se faire, il est possible d'utiliser la directive ''USER''.
 +
 +<bootnote important>Un conteneur lancé en tant que `root` pose des risques de sécurité en cas de compromission, bien plus que quand il est lancé en tant que simple utilisateur. Pour certains services, c'est difficile, mais il faut essayer de s'en rapprocher le plus possible.</bootnote>
  
 La dernière directive `USER` utilisée correspondra à l'utilisateur qui exécutera les commandes quand le conteneur sera lancé. Il est préférable de démarrer le conteneur avec un utilisateur non-privilégié. On s'assurera qu'il a bien les droits sur les fichiers qu'il doit utiliser, par exemple avec des instructions `chown` lors de la construction de l'image. La dernière directive `USER` utilisée correspondra à l'utilisateur qui exécutera les commandes quand le conteneur sera lancé. Il est préférable de démarrer le conteneur avec un utilisateur non-privilégié. On s'assurera qu'il a bien les droits sur les fichiers qu'il doit utiliser, par exemple avec des instructions `chown` lors de la construction de l'image.
- 
-Pour les services basés sur un langage interprété comme Python, utilisez l'image officielle en appliquant les principes précédents. 
- 
-Pour ce dernier besoin, il peut être intéressant d'avoir recours à des [[https://docs.docker.com/develop/develop-images/multistage-build/|multi-stage builds]]. 
  • technique/docker/general/tips.1602504760.txt.gz
  • de qduchemi