**Ceci est une ancienne révision du document !**
Bonnes pratiques pour les Dockerfiles
On pourra se référer à la documentation officielle sur les bonnes pratiques.
Générales
Import d'images stables
Lors de l’import d’une image dans un Dockerfile à l’aide de la directive FROM
, il est important de spécifier la version de l’image importée ; sinon la dernière version (latest) est importée, ce qui peut poser des problèmes de stabilité.
Exécution de commandes dans un conteneur
Auparavant, l’exécution de commandes dans un conteneur était réalisée par l’utilisation de supervisord ; cette pratique ne correspond plus aux pratiques employées actuellement par l’association. L’exécution de commandes dans un conteneur est désormais réalisée par l’utilisation de l’instruction CMD
associé à un ENTRYPOINT
si nécessaire dans le Dockerfile du conteneur.
Installation de paquets par ordre alphabétique
Pour éviter d’installer deux fois un paquet, lors de l’installation de plusieurs paquets en une instruction, il convient de les installer dans l’ordre alphabétique.
Réduction du nombre de couches
Un Dockerfile est composé de différentes couches. Une couche correspond à une instruction exécutée par le Dockerfile. Lorsqu’un conteneur est lancé, il va accéder aux commandes du conteneur en remontant les différents niveaux. À la manière de l’héritage en programmation, si un conteneur cherche a appeler une commande qu’il ne connaît pas, il va remonter à sa classe mère et ainsi de suite. Or, ces accès réduisent la vitesse d’exécution de la commande. Il faut donc veiller à réduire au maximum le nombre de couches d’un conteneur et privilégier les instructions avec plusieurs commandes:
# Exemple: RUN echo "deb http://packages.dotdeb.org jessie all" > /etc/apt/sources.list.d/dotdeb.list && \ wget -O- https://www.dotdeb.org/dotdeb.gpg | apt-key add - && \ apt-get update -y && apt-get install -y php7.0 php7.0-fpm php7.0-gd php7.0-xml nginx supervisor curl tar
Passage de paramètres à un conteneur
Les images Docker de l’association comportent une instruction ENTRYPOINT
qui permet de lancer un script à l’instanciation de l’image ; le script entrypoint.sh
associé à chaque conteneur initialise dans son conteneur les variables d’environnement qui sont nécessaires.
Contrôle de la santé d'un conteneur
Afin de faciliter la supervision de l’état d’un conteneur, il convient d’inclure dans les images Docker une instruction HEALTHCHECK
contenant une commande permettant de vérifier la santé du conteneur.
Sécurité
Options lors de l'instanciation d'images
Certaines options permettent de désactiver des fonctionnalités importantes d’isolation fournies par Docker au lancement d’un conteneur. Ces options ne doivent pas être utilisées. Elles comportent :
–privileged
: donne toutes les capabilities et lui permet de dépasser les limites qui lui seraient normalement imposées par son cgroup ; cela expose l’hôte à des attaques de type déni de service par l’absence de limitation sur la consommation de ressources et cela donne accès au conteneur à des capabilities dont il n’a pas nécessairement besoin et qui sont vecteurs de risques–security-opt
: désactive l’utilisation de seccomp. seccomp est une fonctionnalité du noyau Linux permettant de limiter le nombre d’appels systèmes disponibles à un conteneur ; la désactivation de ces limiations met donc l’hôte à risque
Montage de volumes
Lors de la rédaction d’images, on peut être tenté d’exposer des volumes sur des images “temporaires”. Par exemple, un conteneur nginx auquel on va exposer le volume /var/www/html
. Le problème de cette pratique est que si l’on veut créer une image dokuwiki basée sur cette image nginx, il ne sera pas possible d’écrire par dessus le volume /var/www/html
. Même si au sein du Dockerfile on spécifie des commandes pour remplacer le contenu de l’image, au final, le contenu du dossier restera celui de l’image mère.
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.
Présence d'informations confidentielles dans un Dockerfile ou un docker-compose.yml
Il convient de ne pas saisir d’informations confidentielles, telles que des mots de passe ou des clés SSH, dans des fichiers tels que des Dockerfiles ou docker-compose.yml
; ces fichiers sont souvent versionnés et parfois moins protégés. Pour ces raisons, il convient pour passer des paramètres tels que des mots de passe à un conteneur d’utiliser des variables d’environnement comme mentionné plus haut.
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
.
Réaliser des images minimales
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. Pour ce dernier besoin, il peut être intéressant d’avoir recours à des multi-stage builds.
Documenter les paramètres nécessaires
Chaque Dockerfile peut nécessiter le passage de paramètres tels que des mots de passe ; lorsque c’est le cas, il convient de les documenter dans le point d’entrée du conteneur et de leur y assigner une valeur par défaut.