Ecrire un Dockerfile
Mise à jour :
Dans la section précédente, nous avons vu ce qu’est une image de conteneur. Nous allons voir maintenant comment les construire avec le fichier Dockerfile.
La syntaxe d’un Dockerfile
Comme dit précédemment la syntaxe d’un Dockerfile
est assez simple, car elle ne
fait appel qu’à une dizaine d’instructions. Chaque instruction possède des
arguments.
Les instructions Dockerfile
L’instruction FROM
Pour qu’un fichier Dockerfile
soit valide, il doit commencer avec
l’instruction FROM
qui définit l’image de base. Cette image de base peut être
n’importe quelle image valide.
ou
ou
L’argument facultatif --platform
permet de spécifier la plate-forme de
l’image dans le cas où FROM
fait référence à une image multiplateforme. Par
exemple, linux/amd64
. Par défaut, la plateforme utilisée est celle où est
effectuée la construction de l’image.
Les valeurs tag
ou digest
sont facultatives. Si vous omettez l’un ou l’autre, le
générateur suppose que vous voulez récupérer l’image possédant le tag latest
.
L’instruction FROM
peut apparaître plusieurs fois dans un Dockerfile
. Nous
verrons plus tard ce principe qui permet d’optimiser la taille des images
produites avec ce qu’on appelle le multi-stage.
L’instruction LABEL
L’instruction LABEL
permet d’ajouter des informations, des métadonnées, à
l’image sous forme de clés / valeurs.
Les étiquettes incluses dans les images de base sont transmises aux images produites. Si une étiquette existe, la valeur appliquée sera la plus récente.
L’instruction ARG
L’instruction ARG
est la seule instruction qui peut précéder l’instruction
FROM
. Elle permet de définir des variables qui peuvent être transmises au
moment de la construction de l’image.
Il est possible de définir des valeurs par défaut avec l’opérateur =
suivi de
cette valeur.
Pour utiliser la variable, on utilise la même syntaxe qu’on utilise dans les
scripts shell
:
Attention à la portée des variables ARG
. En effet, un variable entre en
vigueur à partir de la ligne sur laquelle elle est définie !
Les instructions FROM
peuvent utiliser des variables déclarées avant elle.
L’instruction ENV
Contrairement à ARG
, l’instruction ENV
permet de définir des variables
d’environnement qui seront utilisés dans les commandes exécutées avec
l’instruction RUN
que nous verrons juste après. Ces variables sont
persistantes et seront disponibles au moment de l’exécution de l’image de
conteneur.
Cela peut être très utile configurer des services faisant appel à des variables
d’environnement. Par exemple pour une image proposant un service de Base De
Données Postgres la variable d’environnement PGDATA
qui indique où se trouvent
les données des bases.
Elles peuvent utiliser des variables définies avec ARG
.
Les variables d’environnement définies avec ENV
seront disponibles au moment
de l’exécution de l’image du conteneur. Une étape hérite de toutes les variables
d’environnement définies dans l’étape parent. Donc attention cela peut provoquer
des comportements inattendus.
Si une variable d’environnement n’est nécessaire que lors de la construction, et non dans l’image finale, envisagez plutôt de définir une valeur pour une seule commande :
ou en utilisant l’instruction ARG
vu précédemment
L’instruction RUN
L’instruction RUN
permet de lancer des commandes aux moments de la
construction de l’image.
Par exemple pour installer des packages depuis une image de base Alpine :
Pour optimiser la taille des images, car chaque instruction RUN ajoute une
couche à l’image résultante, il est conseillé d’enchainer les commandes en les
séparant avec la séquence &&
.
Lorsque beaucoup de commande s’enchainent, on peut utiliser un antislash \
pour poursuivre les commandes de l’instruction RUN sur la ligne suivante.
L’instruction COPY
L’instruction COPY
permet d’intégrer des fichiers et ou des dossiers pour les
ajouter au système de fichiers de l’image dans le répertoire <dest>
.
La seconde forme est à utiliser si vous avez des espaces dans les noms de fichiers. Comme vous pouvez le remarquer, on peut indiquer plusieurs sources dans une seule instruction.
L’instruction ADD
L’instruction ADD
fonctionne comme l’instruction COPY
sauf qu’il permet
d’intégrer des URL de fichiers distants et/ou des archives qui seront
décompressés à la volée et les ajoute au système de fichiers de l’image dans le
répertoire <dest>
.
L’instruction USER
L’instruction USER
définit l’utilisateur ou l’UID et éventuellement le groupe
d’utilisateurs ou le GID à utiliser pour le reste de l’étape en cours.
L’utilisateur spécifié est utilisé pour les instructions RUN
et, au moment de
l’exécution de l’image de conteneur.
Un exemple permettant de spécifier l’UID et le GID via des ARG’s :
L’instruction WORKDIR
L’instruction WORKDIR
définit le répertoire de travail pour toutes les
instructions qui la suivent dans le Dockerfile. Si le répertoire n’existe pas, il
sera créé.
L’instruction VOLUME
L’instruction VOLUME
crée un point de montage avec le nom spécifié et le
marque comme contenant des volumes montés en externe à partir d’un hôte natif ou
d’autres conteneurs.
Les volumes sont utiles pour stocker des données qui doivent persister même si le conteneur est arrêté ou supprimé.
L’instruction EXPOSE
L’instruction EXPOSE
informe le moteur de conteneur que le conteneur écoute
sur les ports réseau spécifiés au moment de l’exécution. Vous pouvez spécifier
le protocole TCP ou UDP, TCP étant la valeur par défaut.
Les instructions CMD et ENTRYPOINT
Ces deux instructions permettent de définir les commandes qui seront exécutées au moment du lancement de l’image de conteneur.
La principale différence entre CMD
et ENTRYPOINT
est que les commandes
fournies par CMD peuvent être remplacés, alors que celles fournies par ENTRYPOINT
ne le peuvent pas à moins de les forcer avec le bon argument dans la CLI de
votre moteur de conteneur.
Exemple :
Notre première image de conteneur
Je vous propose un exemple complet de Dockerfile faisant appel à un bon nombre de ces instructions.
Cet exemple illustre le concept de ce qu’on appelle le multi-stage en utilisant
deux étapes, deux instructions FROM
. La première permet de construire l’image
en intégrant tout ce qui est nécessaire à la construction de l’image, la seconde
ne copie que le nécessaire à son exécution. Cela permet d’optimiser la taille de
l’image résultante.
Parmi les points importants :
- Les variables définies avec les instructions
ENV
dans la première étape sont disponibles dans la seconde. - On copie des données de la première étape dans la seconde en utilisant
l’argument
--from=<nom de l'étape>
. - La commande qui sera lancée au moment du lancement de l’image sera celle
définie par l’instruction
ENTRYPOINT
.
Maintenant que vous avez vu tous ces concepts et ses définitions, vous devriez être prêt pour créer des Dockerfile de qualité. Voyons à présent quelques outils qui vont vous aider dans cette tâche.
Des outils de contrôle
Je vous propose quelques outils qui vont vous permettre de progresser dans la création des Dockerfile.
Hadolint
Hadolint est l’outil qui va vous aider à progresser dans l’écriture de vos Dockerfile. Cet outil de lint va vous donner plein de conseils qui vont vous permettre de respecter un très grand nombre de bonnes pratiques. J’ai documenté son utilisation dans ce billet.
Dive
dive ↗ est l’outil d’analyse de conteneur. J’ai documenté son utilisation dans la partie parlant de l’optimisation de la taille des images de conteneurs.
conteneur-structure-test
L’outil conteneur-structure-test
permet de valider la structure d’une image
de conteneur. Il peut être utilisé pour vérifier le résultat des commandes d’une
image, ainsi que pour vérifier ses métadonnées et le contenu du système de
fichiers. Tout est expliqué dans ce billet
Conclusion
Vous êtes fin prêt pour créer des Dockerfile de grande qualité. Vous pouvez aussi passer à la suite en voyant comment optimiser la taille des images ou abordant ce qu’on appelle les moteurs de conteneurs.