RUN : installer ce dont l’application a besoin
package.json est copié dans l'image, mais les dépendances qu'il décrit n'y sont pas encore installées.
RUN : exécuter une commande pendant la construction
L'instruction RUN exécute une commande à l'intérieur de l'image, pendant sa construction. Mini-Carnet dépend de la bibliothèque express, listée dans package.json mais pas encore réellement installée. La commande qui l'installe, npm install, doit donc être exécutée par une instruction RUN :
Cette ligne s'exécute une seule fois, au moment de la construction de l'image, pas à chaque démarrage d'un conteneur. Une fois l'image construite, les dépendances installées en font partie, exactement comme n'importe quel autre fichier copié.
Copier maintenant le reste du code
Il ne manque plus que server.js, le fichier qui contient réellement l'application. Ajoutez une seconde instruction COPY, cette fois pour tout le dossier :
COPY . . copie tout le contenu du dossier courant sur votre ordinateur (celui où se trouve le Dockerfile) vers le dossier de travail à l'intérieur de l'image. C'est cette ligne qui fait entrer server.js.
Pourquoi copier package.json avant le reste du code
Cet ordre précis, COPY package.json puis RUN npm install puis COPY . ., n'est pas arbitraire : c'est une pratique officiellement recommandée par Docker, liée à une notion appelée le cache de build.
À chaque reconstruction d'une image, Docker examine chaque instruction du Dockerfile et vérifie si elle a changé depuis la dernière construction. Si une instruction et ce qu'elle utilise n'ont pas changé, Docker réutilise directement le résultat déjà calculé, sans la rejouer : c'est beaucoup plus rapide.
Si package.json n'a pas changé, Docker sait que npm install produira exactement le même résultat que la fois précédente, et réutilise ce résultat sans réinstaller quoi que ce soit. Modifier uniquement server.js, ce qui va vous arriver très souvent en développement, ne déclenche donc pas une réinstallation complète des dépendances : seule la dernière ligne, COPY . ., doit être rejouée.
Copiez toujours les fichiers qui décrivent les dépendances (comme package.json) avant le reste du code, et installez ces dépendances avant de copier le reste. Cet ordre accélère considérablement les reconstructions d'image pendant le développement, sans rien changer au résultat final.
Vérifiez que vous avez compris
Vous modifiez uniquement le texte affiché dans server.js, sans toucher à package.json, puis vous reconstruisez l'image. Docker va-t-il réexécuter npm install ?
Non, ou en tout cas pas si l'ordre des instructions respecte celui de ce guide. Puisque package.json n'a pas changé, Docker réutilise le résultat déjà connu de npm install depuis le cache, et ne rejoue que les instructions situées après le fichier réellement modifié, ici COPY . ..