Utiliser le cache de construction
Explication
Considérez le Dockerfile suivant que vous avez créé pour l'application getting-started.
FROM node:20-alpine
WORKDIR /app
COPY . .
RUN yarn install --production
CMD ["node", "./src/index.js"]
Lorsque vous exécutez la commande docker build
pour créer une nouvelle image, Docker exécute chaque instruction de votre Dockerfile, créant une couche pour chaque commande et dans l'ordre spécifié. Pour chaque instruction, Docker vérifie s'il peut réutiliser l'instruction d'une construction précédente. S'il trouve que vous avez déjà exécuté une instruction similaire auparavant, Docker n'a pas besoin de la refaire. Au lieu de cela, il utilisera le résultat mis en cache. De cette façon, votre processus de construction devient plus rapide et plus efficace, vous faisant économiser du temps et des ressources précieuses.
Utiliser le cache de construction efficacement vous permet d'obtenir des constructions plus rapides en réutilisant les résultats des constructions précédentes et en évitant le travail inutile. Pour maximiser l'utilisation du cache et éviter les reconstructions gourmandes en ressources et en temps, il est important de comprendre comment fonctionne l'invalidation du cache. Voici quelques exemples de situations qui peuvent causer l'invalidation du cache :
-
Tout changement à la commande d'une instruction
RUN
invalide cette couche. Docker détecte le changement et invalide le cache de construction s'il y a une modification quelconque à une commandeRUN
dans votre Dockerfile. -
Tout changement aux fichiers copiés dans l'image avec les instructions
COPY
ouADD
. Docker surveille toute altération aux fichiers dans votre répertoire de projet. Qu'il s'agisse d'un changement de contenu ou de propriétés comme les permissions, Docker considère ces modifications comme déclencheurs pour invalider le cache. -
Une fois qu'une couche est invalidée, toutes les couches suivantes sont également invalidées. Si une couche précédente quelconque, y compris l'image de base ou les couches intermédiaires, a été invalidée en raison de changements, Docker s'assure que les couches ultérieures qui en dépendent sont également invalidées. Cela maintient le processus de construction synchronisé et empêche les incohérences.
Lorsque vous écrivez ou modifiez un Dockerfile, surveillez les erreurs de cache inutiles pour vous assurer que les constructions s'exécutent aussi rapidement et efficacement que possible.
Essayez-le
Dans ce guide pratique, vous apprendrez comment utiliser le cache de construction Docker efficacement pour une application Node.js.
Construire l'application
-
Téléchargez et installez Docker Desktop.
-
Ouvrez un terminal et clonez cet exemple d'application.
$ git clone https://github.com/dockersamples/todo-list-app
-
Naviguez dans le répertoire
todo-list-app
:$ cd todo-list-app
Dans ce répertoire, vous trouverez un fichier nommé
Dockerfile
avec le contenu suivant :FROM node:20-alpine WORKDIR /app COPY . . RUN yarn install --production EXPOSE 3000 CMD ["node", "./src/index.js"]
-
Exécutez la commande suivante pour construire l'image Docker :
$ docker build .
Voici le résultat du processus de construction :
[+] Building 20.0s (10/10) FINISHED
La première ligne indique que tout le processus de construction a pris 20,0 secondes. La première construction peut prendre du temps car elle installe les dépendances.
-
Reconstruisez sans faire de changements.
Maintenant, relancez la commande
docker build
sans faire aucun changement dans le code source ou le Dockerfile comme montré :$ docker build .
Les constructions ultérieures après la première sont plus rapides grâce au mécanisme de mise en cache, tant que les commandes et le contexte restent inchangés. Docker met en cache les couches intermédiaires générées pendant le processus de construction. Lorsque vous reconstruisez l'image sans faire de changements au Dockerfile ou au code source, Docker peut réutiliser les couches mises en cache, accélérant considérablement le processus de construction.
[+] Building 1.0s (9/9) FINISHED docker:desktop-linux => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 187B 0.0s ... => [internal] load build context 0.0s => => transferring context: 8.16kB 0.0s => CACHED [2/4] WORKDIR /app 0.0s => CACHED [3/4] COPY . . 0.0s => CACHED [4/4] RUN yarn install --production 0.0s => exporting to image 0.0s => => exporting layers 0.0s => => exporting manifest
La construction ultérieure a été terminée en seulement 1,0 seconde en tirant parti des couches mises en cache. Pas besoin de répéter les étapes chronophages comme l'installation des dépendances.
Étapes Description Temps pris (1ère exécution) Temps pris (2ème exécution) 1 Charger la définition de construction depuis le Dockerfile 0,0 secondes 0,0 secondes 2 Charger les métadonnées pour docker.io/library/node:20-alpine 2,7 secondes 0,9 secondes 3 Charger .dockerignore 0,0 secondes 0,0 secondes 4 Charger le contexte de construction (Taille du contexte : 4,60 MB)
0,1 secondes 0,0 secondes 5 Définir le répertoire de travail (WORKDIR) 0,1 secondes 0,0 secondes 6 Copier le code local dans le conteneur 0,0 secondes 0,0 secondes 7 Exécuter yarn install --production 10,0 secondes 0,0 secondes 8 Exporter les couches 2,2 secondes 0,0 secondes 9 Exporter l'image finale 3,0 secondes 0,0 secondes En revenant à la sortie
docker image history
, vous voyez que chaque commande dans le Dockerfile devient une nouvelle couche dans l'image. Vous vous souvenez peut-être que lorsque vous avez fait un changement à l'image, les dépendancesyarn
ont dû être réinstallées. Y a-t-il un moyen de corriger cela ? Il n'est pas très logique de réinstaller les mêmes dépendances à chaque fois que vous construisez, n'est-ce pas ?Pour corriger cela, restructurez votre Dockerfile afin que le cache de dépendances reste valide à moins qu'il n'ait vraiment besoin d'être invalidé. Pour les applications basées sur Node, les dépendances sont définies dans le fichier
package.json
. Vous voudrez réinstaller les dépendances si ce fichier change, mais utiliser les dépendances mises en cache si le fichier est inchangé. Donc, commencez par copier seulement ce fichier d'abord, puis installez les dépendances, et enfin copiez tout le reste. Ensuite, vous n'avez besoin de recréer les dépendances yarn que s'il y a eu un changement au fichierpackage.json
. -
Mettez à jour le Dockerfile pour copier d'abord le fichier
package.json
, installer les dépendances, puis copier tout le reste.FROM node:20-alpine WORKDIR /app COPY package.json yarn.lock ./ RUN yarn install --production COPY . . EXPOSE 3000 CMD ["node", "src/index.js"]
-
Créez un fichier nommé
.dockerignore
dans le même dossier que le Dockerfile avec le contenu suivant.node_modules
-
Construisez la nouvelle image :
$ docker build .
Vous verrez alors une sortie similaire à la suivante :
[+] Building 16.1s (10/10) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 175B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/node:21-alpine 0.0s => [internal] load build context 0.8s => => transferring context: 53.37MB 0.8s => [1/5] FROM docker.io/library/node:21-alpine 0.0s => CACHED [2/5] WORKDIR /app 0.0s => [3/5] COPY package.json yarn.lock ./ 0.2s => [4/5] RUN yarn install --production 14.0s => [5/5] COPY . . 0.5s => exporting to image 0.6s => => exporting layers 0.6s => => writing image sha256:d6f819013566c54c50124ed94d5e66c452325327217f4f04399b45f94e37d25 0.0s => => naming to docker.io/library/node-app:2.0 0.0s
Vous verrez que toutes les couches ont été reconstruites. Parfaitement normal puisque vous avez modifié le Dockerfile assez.
-
Maintenant, faites un changement à la
src/static/index.html
file (comme changer le titre pour dire "The Awesome Todo App"). -
Construisez l'image Docker. Cette fois, votre sortie devrait ressembler à celle-ci :
$ docker build -t node-app:3.0 .
Vous verrez alors une sortie similaire à celle-ci :
[+] Building 1.2s (10/10) FINISHED => [internal] load build definition from Dockerfile 0.0s => => transferring dockerfile: 37B 0.0s => [internal] load .dockerignore 0.0s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/node:21-alpine 0.0s => [internal] load build context 0.2s => => transferring context: 450.43kB 0.2s => [1/5] FROM docker.io/library/node:21-alpine 0.0s => CACHED [2/5] WORKDIR /app 0.0s => CACHED [3/5] COPY package.json yarn.lock ./ 0.0s => CACHED [4/5] RUN yarn install --production 0.0s => [5/5] COPY . . 0.5s => exporting to image 0.3s => => exporting layers 0.3s => => writing image sha256:91790c87bcb096a83c2bd4eb512bc8b134c757cda0bdee4038187f98148e2eda 0.0s => => naming to docker.io/library/node-app:3.0 0.0s
Tout d'abord, vous devriez remarquer que la construction était beaucoup plus rapide. Vous verrez que plusieurs étapes utilisaient des couches mises en cache précédentes. C'est bonne nouvelle; vous utilisez le cache de construction. Pushing et pulling cette image et les mises à jour à elle seront beaucoup plus rapides également.
En suivant ces techniques d'optimisation, vous pouvez rendre vos constructions Docker plus rapides et plus efficaces, conduisant à des cycles d'itération plus rapides et à une productivité de développement améliorée.
Ressources supplémentaires
- Optimiser les constructions avec la gestion du cache
- Stockage du backend du cache
- Invalidation du cache de construction
Étapes suivantes
Maintenant que vous comprenez comment utiliser le cache de construction Docker efficacement, vous êtes prêt pour apprendre à propos des constructions Multi-stage.