E-NO
DevOps 10 min de lecture

Architecture du cache de construction Docker : exemples pratiques et optimisation des performances

calendar_today Publié : 2026-09-11
update Dernière mise à jour : 2026-09-11
analytics Efficacité SEO : 100%
Illustration du guide technique pour « Architecture du cache de construction Docker : exemples pratiques et optimisation des performances ».

Introduction

Les builds Docker lents érodent silencieusement la productivité des développeurs et le débit des pipelines CI. Le cache de build peut réduire considérablement les temps de construction, mais seulement si vous comprenez son architecture, quand il est invalidé et comment le partager entre les builds. Ce guide explique les fondamentaux du cache de build Docker avec des exemples pratiques que vous pouvez exécuter localement : inspecter les succès et échecs de cache, structurer les Dockerfiles pour une mise en cache optimale des couches, utiliser les caches de montage BuildKit pour les dépendances de paquets et partager le cache entre les exécutions CI. À la fin, vous serez capable de diagnostiquer l'invalidation du cache, de récupérer des erreurs courantes et de rendre les builds plus rapides de manière fiable.

Nous nous concentrerons sur le constructeur moderne BuildKit, que Docker Desktop active par défaut, et couvrirons également le comportement hérité lorsque cela est pertinent. Vous apprendrez quelles instructions Dockerfile affectent le cache, comment vérifier si une couche a été mise en cache et comment éviter les échecs de cache qui entraînent des téléchargements ou des compilations redondants.

Inventaire des versions et de l'environnement

Avant de changer quoi que ce soit, observez ce que vous exécutez. Vérifiez la version de Docker et confirmez que BuildKit est activé. Exécutez docker version et recherchez Server: Docker Engine et Client: Docker Engine. Pour vérifier BuildKit, exécutez docker buildx version. Si la sortie affiche github.com/docker/buildx, vous utilisez BuildKit. Sinon, utilisez docker system info --format '{{ .Builder }}'; sur les anciennes versions, cela peut afficher vide pour le constructeur hérité. Vous pouvez définir DOCKER_BUILDKIT=1 dans votre environnement pour activer explicitement BuildKit sur les versions prises en charge, ou le configurer dans le démon Docker (/etc/docker/daemon.json) avec "features": {"buildkit": true}.

Notez le pilote de stockage, qui affecte la gestion des couches : docker info --format '{{ .Driver }}'. Les pilotes courants sont overlay2 sur Linux moderne, mais sur certains systèmes, vous pouvez voir aufs ou devicemapper. Ce n'est généralement pas un problème de cache en soi, mais utile lorsque vous devez inspecter les tailles des couches ou purger les données du cache.

Avant chaque build, capturez l'état actuel : docker system df montre l'utilisation de l'espace récupérable par les images, conteneurs, volumes et cache de build. Pour un inventaire rapide du cache, utilisez docker buildx du (BuildKit) pour afficher l'espace disque occupé par le cache du constructeur. Exemple de sortie :

Total:      1.234GB
  Reclaimable:  234.5MB

Cela vous indique la quantité de cache dont vous disposez et combien peut être récupéré sans casser les builds en cours. Ne purgez pas le cache avant de comprendre ce qu'il contient ; utilisez docker buildx du --verbose pour lister les entrées du cache par type et taille, y compris les couches régulières et les caches de montage.

Pour la sécurité des données, évitez les montages bind pour les répertoires de cache dans les builds de production. Les montages bind exposent des chemins spécifiques à l'hôte et peuvent fuiter l'état entre les builds. Préférez les volumes nommés ou les caches de montage BuildKit, qui sont gérés par Docker et isolés. Un test de redémarrage simple pour un service qui écrit des fichiers locaux : arrêtez et recréez le conteneur, puis vérifiez que les données persistent si elles sont dans un volume. Si les données disparaissent, elles ont probablement été écrites dans la couche inscriptible du conteneur.

Question rapide 1 sur 2

Selon le passage, quel est l'objectif principal de la commande docker system df ?

Le passage indique : « docker system df affiche l'utilisation de l'espace récupéré par les images, les conteneurs, les volumes et le cache de build. »

Chemin de configuration sûr

Le comportement du cache de build est principalement contrôlé par la structure du Dockerfile et les arguments de build. Les changements les plus sûrs sont d'abord des observations en lecture seule, puis des modifications à portée unique avec un build de vérification.

Règles de cache des instructions Dockerfile

Chaque instruction Dockerfile crée une couche, et le cache de couche est indexé par le type d'instruction, les arguments et la couche parente. Les règles les plus importantes :

  • FROM base:tag est mis en cache par l'ID de l'image ; changer le tag peut ou non changer l'ID.
  • Les commandes RUN sont mises en cache par la chaîne exacte de la commande. Toute différence, y compris un commentaire ou un espace, invalide le cache.
  • COPY et ADD sont mis en cache en fonction des sommes de contrôle du contenu des fichiers, pas des horodatages. Les changements de métadonnées de fichiers comme les permissions ou la propriété affectent également la somme de contrôle.
  • ENV, LABEL, EXPOSE et CMD ne créent généralement pas de grandes couches mais affectent quand même les couches suivantes s'ils changent.

Pour vérifier qu'une couche a été réutilisée, construisez avec --progress=plain (BuildKit) au lieu de la progression fantaisiste par défaut. Pour chaque étape, la sortie affiche CACHED si la couche a été réutilisée. Exemple :

#2 [1/4] FROM python:3.11-slim
#2 CACHED
#3 [2/4] RUN apt-get update && apt-get install -y curl
#3 CACHED
#4 [3/4] COPY requirements.txt .
#4 sha256:1234...
#5 [4/4] RUN pip install -r requirements.txt
#5 0.532 done

Dans cet exemple, les étapes FROM et RUN apt-get sont mises en cache, mais l'étape COPY ne l'est pas car requirements.txt a changé, donc le pip install suivant s'est également exécuté à nouveau. Si vous voyez CACHED à chaque étape, l'image entière a été réutilisée depuis le cache.

Le constructeur hérité (non-BuildKit) affiche le statut du cache différemment : ---> Using cache pour une couche mise en cache et ---> Running in ... pour une couche reconstruite.

Optimisation pratique : l'ordre compte

Placez les instructions qui changent moins fréquemment avant celles qui changent fréquemment. Pour une application Python, un ordre optimal typique est :

FROM python:3.11-slim
WORKDIR /app
# Installer les dépendances système d'abord (change rarement)
RUN apt-get update && apt-get install -y --no-install-recommends gcc libpq-dev && rm -rf /var/lib/apt/lists/*
# Copier le manifeste des dépendances et installer les paquets Python (change modérément)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Copier le code de l'application (change fréquemment)
COPY . .
CMD ["python", "app.py"]

Chaque étape est mise en cache indépendamment. Si vous modifiez uniquement le code de l'application, les trois premières couches sont réutilisées, et seuls COPY . . et CMD (si modifié) sont reconstruits. Si vous copiez tout en une fois puis installez les dépendances, tout changement de code source invalide la couche d'installation des dépendances.

Utiliser les arguments de build sans invalider le cache

Les arguments de build (ARG) peuvent être utilisés de manière à ne pas casser le cache pour les couches suivantes. Un ARG utilisé uniquement dans une couche n'affecte pas le cache si la valeur est inchangée. Cependant, si vous utilisez ARG dans une commande RUN, la clé de cache de la couche inclut la valeur de l'argument. Pour éviter d'invalider tout le cache lors du passage d'arguments versionnés, définissez le ARG juste avant le RUN qui l'utilise, pas en haut. Exemple :

FROM node:18-alpine
...
# ARG déclaré juste avant l'utilisation
ARG NODE_ENV=production
RUN NODE_ENV=$NODE_ENV npm ci

Cela permet à la couche avant ARG d'être réutilisée même si NODE_ENV change. Si ARG était en haut, toute différence dans NODE_ENV invaliderait chaque couche suivante.

Builds multi-étapes pour l'isolation du cache

Les builds multi-étapes créent des chaînes de cache séparées par étape. L'étape finale ne contient que ce que vous copiez depuis les étapes précédentes, souvent avec COPY --from=builder. C'est puissant car vous pouvez modifier l'étape de construction sans affecter le cache de l'étape d'exécution finale. Exemple :

# Étape de compilation
FROM golang:1.21 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .

# Étape d'exécution
FROM alpine:3.19
COPY --from=builder /app/main /usr/local/bin/app
CMD ["app"]

L'étape builder peut être reconstruite souvent sans changer le cache de l'étape d'exécution. Vous pouvez également utiliser COPY --from=builder avec un cache de montage pour réutiliser le cache de build entre les builds (voir ci-dessous).

Vérification et diagnostics

Après avoir modifié un Dockerfile, vérifiez que le cache se comporte comme prévu. Construisez deux fois et comparez les temps et les statuts de cache.

Mesurer le temps de build et les succès de cache

Utilisez la commande time autour de votre build :

time docker build -t myapp .

Le premier build peut prendre des minutes ; le second build sans changement devrait se terminer en millisecondes car toutes les couches sont mises en cache. Si le second build prend encore longtemps, quelque chose a invalidé le cache. Utilisez docker build --progress=plain pour voir le statut par étape. Pour une vérification plus quantitative, utilisez docker buildx build --progress=plain --output=type=image et cherchez les lignes cache dans la sortie.

BuildKit prend en charge une option --metadata-file qui produit des métadonnées de build incluant des informations de cache. Exemple :

docker buildx build --metadata-file build-metadata.json -t myapp .
cat build-metadata.json

Le JSON contient un containerimage.buildinfo avec les digests et tailles des couches, pas directement les succès/échecs de cache, mais combiné avec un second build, vous pouvez comparer les digests des couches pour voir si les couches ont été réutilisées.

Pour le débogage CI, vous pouvez exécuter docker buildx du --verbose pour voir les entrées de cache par digest et taille de couche. Cela aide à identifier quelles couches consomment le plus d'espace de cache et si les caches de montage sont utilisés efficacement.

Simuler des tests d'invalidation de cache

Créez des changements délibérés pour voir comment le cache s'invalide :

  1. Changez une ligne dans le code source mais pas requirements.txt ni Dockerfile.
  2. Reconstruisez et observez : seule l'étape COPY . . devrait être reconstruite ; l'installation des dépendances devrait être mise en cache.
  3. Ajoutez un commentaire en haut du Dockerfile : le premier RUN après ce commentaire sera reconstruit car la couche parente change.
  4. Changez une variable d'environnement : les couches après ce ENV seront reconstruites.

En effectuant ces tests sur un projet d'exemple, vous gagnez en intuition sur les changements qui causent des échecs de cache.

Utiliser Docker Build Cloud ou des constructeurs distants

Si vous utilisez des constructeurs distants (par exemple, Docker Build Cloud, GitHub Actions avec Buildx), vous pouvez partager le cache entre machines. BuildKit prend en charge l'exportation et l'importation de cache en utilisant un registre ou des répertoires locaux. Par exemple, pour exporter le cache vers un dépôt Docker Hub :

docker buildx build --cache-to type=registry,ref=myuser/myapp:cache --cache-from type=registry,ref=myuser/myapp:cache -t myapp:latest .

Sur un runner CI frais, importez le cache avec --cache-from pour réutiliser les couches précédemment construites. C'est un changement radical pour les pipelines CI où chaque tâche part de zéro.

Diagnostiquer les échecs de cache avec BuildGraph

BuildKit a une fonctionnalité de débogage pour vider le graphe de build. Définissez BUILDKIT_PROGRESS=plain et BUILDKIT_DEBUG=1 pour voir des journaux détaillés. Sur Linux, vous pouvez utiliser docker buildx debug pour vous attacher au constructeur et exécuter des commandes. Le graphe de build montre les dépendances entre les étapes et les clés de cache. Vous pouvez installer le visualiseur buildgraph ou utiliser docker buildx imagetools pour inspecter les couches.

Modes d'échec et récupération

Échec courant : gonflement du cache et épuisement de l'espace disque

Symptômes : docker build échoue avec no space left on device, ou le disque système se remplit. Le cache de build peut croître sans limite, surtout avec des builds fréquents utilisant des caches de montage (qui stockent les caches de dépendances en dehors de l'image).

Récupération : purgez le cache de build avec docker buildx prune. Cela supprime le cache inutilisé, mais attention : si vous supprimez un cache encore nécessaire pour les builds en cours, ils reconstruiront à partir de zéro. Utilisez docker buildx prune --keep-storage 10GB pour conserver une certaine quantité. Pour un CI à fort trafic, configurez une purge périodique avec docker system prune -f --filter "until=24h".

Prévention : utilisez --cache-to et --cache-from pour stocker le cache de manière persistante et éviter de reconstruire à partir de zéro. Surveillez docker buildx du dans le cadre de vos contrôles de santé.

Échec courant : invalidation du cache due à un contexte volumineux

Si votre contexte de build inclut de nombreux fichiers ou des fichiers volumineux, l'étape COPY . . peut prendre beaucoup de temps et invalider fréquemment le cache. Utilisez un fichier .dockerignore pour exclure .git, node_modules, les journaux et autres fichiers non pertinents. Exemple de .dockerignore :

.git
node_modules
*.log
dist
.env

Le .dockerignore non seulement accélère le transfert du contexte mais empêche également les échecs de cache dus à des changements de fichiers inutiles.

Échec courant : secrets divulgués dans le cache

Ne jamais COPY ou RUN avec des secrets qui finissent dans une couche mise en cache. Par exemple, RUN curl -H "Authorization: Bearer $TOKEN" intègre le jeton dans la couche, et la couche peut être partagée dans les images de cache. Pour éviter cela, utilisez les secrets BuildKit : RUN --mount=type=secret,id=mysecret curl ... avec le secret fourni au moment du build via --secret id=mysecret,src=./secret.txt. Le secret n'est pas stocké dans l'image. Si vous avez accidentellement divulgué un secret, vous devez reconstruire l'image sans lui et considérer toutes les couches précédentes comme compromises.

Échec courant : mauvaise utilisation du cache de montage et cache orphelin

Les caches de montage (--mount=type=cache,target=/root/.cache) sont excellents pour les gestionnaires de paquets, mais s'ils ne sont pas utilisés correctement, ils peuvent causer des builds avec des dépendances périmées ou laisser des entrées de cache orphelines. Par exemple, si vous utilisez un cache de montage pour /go/pkg/mod dans un build Go, et que le go.sum change, les téléchargements de modules peuvent encore être partiellement réutilisés. Pour éviter le cache périmé, incluez toujours le fichier de verrouillage des dépendances dans la couche qui peuple le cache, ou utilisez un identifiant de cache de montage versionné comme id=gomod-${GO_VERSION}. Nettoyez les caches de montage inutilisés avec docker buildx prune --filter type=exec.cachemount.

Échec courant : confusion entre cache du constructeur hérité et BuildKit

Si vous construisez parfois avec le constructeur hérité et parfois avec BuildKit, le comportement du cache diffère. Le constructeur hérité ne met en cache que sur le démon local et n'a ni caches de montage ni exportation. Cela peut conduire à des builds incohérents sur différentes machines. Standardisez sur BuildKit pour tous les builds. Dans le CI, définissez DOCKER_BUILDKIT=1. Pour Docker Compose, utilisez COMPOSE_DOCKER_CLI_BUILD=1 et DOCKER_BUILDKIT=1 lors de la construction.

Question rapide 2 sur 2

Que permet de voir l'option --progress=plain de BuildKit pendant une construction ?

Le passage explique : « Pour vérifier qu'une couche a été réutilisée, construisez avec --progress=plain (BuildKit) au lieu de la progression fantaisiste par défaut. Pour chaque étape, la sortie indique CACHED si la couche a été réutilisée. »

Liste de contrôle opérationnelle

Voici une liste de contrôle opérationnelle mensuelle pour gérer le cache de build Docker. Mettez à jour le responsable et la date de révision selon votre environnement.

VérificationCommande ou actionRésultat attenduResponsableFréquence
Utilisation du disque du cachedocker buildx duTaille totale du cache dans le budget (par exemple, <5 Go par constructeur)DevOps Lead (Alex Rivera)Hebdomadaire
Base de temps de buildtime docker build ... sur un tag fixePas plus de 20 % de régression par rapport à la baseIngénieur Build (Priya Shah)Mensuel
Validité de l'exportation du cacheInspecter l'image de registre --cache-to (par exemple, docker pull myuser/myapp:cache)Le pull réussit et contient les couches requisesDevOps LeadHebdomadaire
Vérification des fuites de secretsAnalyser les couches avec docker history --no-trunc et grep pour les jetonsAucun secret trouvé dans aucune coucheAgent de sécurité (Jordan Lee)Trimestriel
Couverture .dockerignoreComparer la taille du contexte docker build --progress=plain avec et sans ignoreTaille du contexte réduite d'au moins 50 %Développeur (Sam Chen)Mensuel
Efficacité du cache de montageExécuter le build deux fois ; enregistrer les étapes CACHED et le temps total ; s'assurer que le cache de montage réduit le tempsSecond build sans changement entièrement mis en cache ; avec changement de dépendance, la réinstallation du paquet utilise le cache de montageIngénieur BuildMensuel
Isolation du cache multi-étapesModifier un fichier utilisé uniquement dans l'étape builder, reconstruire, vérifier que l'étape d'exécution n'est pas reconstruiteLes ID des couches de l'étape d'exécution inchangésDéveloppeurAu besoin
Réutilisation du cache CIExécuter un build sur un runner CI propre avec --cache-from, comparer au build localTemps de build proche du build local mis en cacheDevOps LeadHebdomadaire
Purger l'ancien cachedocker buildx prune --keep-storage 10GB ou cron planifiéDisque récupéré sans casser les builds actifsDevOps LeadMensuel
Revue de la documentationMettre à jour cette liste de contrôle et les runbooks liés au cacheTous les changements reflétés dans les documentsChef d'équipe (Morgan Diaz)Trimestriel

Pour chaque vérification, le responsable est chargé de vérifier le résultat et de signaler les problèmes. Révisez cette liste lors de la réunion opérationnelle mensuelle pour ajuster les budgets, les fréquences et les responsables à mesure que le projet évolue.

Pièges à éviter

  1. Placer COPY . . tôt dans le Dockerfile : Cela invalide toutes les couches suivantes à chaque changement de code. Placez toujours COPY . . le plus tard possible.
  2. Utiliser ADD pour des fichiers distants : ADD https://... télécharge toujours et casse le cache de manière imprévisible. Préférez RUN curl ou wget et vérifiez les sommes de contrôle, ou utilisez le multi-étapes avec COPY.
  3. Ignorer .dockerignore : Sans lui, le contexte de build peut inclure des fichiers sensibles et des données inutiles, causant des transferts lents et des échecs de cache fréquents.
  4. Utiliser ARG en haut pour des builds dépendant de la version : Cela peut invalider tout le cache lorsque l'argument change. Déclarez ARG juste avant l'utilisation.
  5. Ne pas utiliser les builds multi-étapes : Les images à une seule étape sont gonflées et ont une mauvaise granularité de cache. Le multi-étapes sépare les dépendances de build de l'exécution, permettant des images plus petites et une meilleure réutilisation du cache.
  6. Exécuter des installations de paquets avec des caches de montage sans contrôle de version : Si le fichier de verrouillage ne change pas, les paquets seront mis en cache, mais si le fichier de verrouillage change, le cache de montage peut encore contenir d'anciennes dépendances. Liez toujours le cache de montage à l'état du fichier de verrouillage, par exemple, --mount=type=cache,target=/root/.npm,id=npm-${{ hashFiles('package-lock.json') }} dans le CI.
  7. Utiliser le constructeur hérité par habitude : Cela renonce aux performances et fonctionnalités de BuildKit. Activez BuildKit globalement via l'environnement ou la configuration du démon.
  8. Stocker des secrets dans les couches d'image : Même s'ils sont supprimés plus tard, ils restent dans l'historique. Utilisez les secrets BuildKit ou les montages de secrets à l'exécution.
  9. Purger agressivement sans analyse : Supprimer le cache utilisé par les builds actifs peut entraîner des reconstructions pénibles. Vérifiez toujours docker buildx du et gardez une rétention sûre.
  10. Ignorer l'exportation de cache dans le CI : Sans importation/exportation de cache, chaque tâche CI part de zéro, multipliant les temps de build et l'utilisation des ressources.

Chaque piège peut être évité avec les pratiques décrites dans les sections précédentes. Lorsqu'une erreur se produit, reportez-vous à la section Modes d'échec pour les étapes de récupération.

Conclusion

L'architecture du cache de build Docker n'est pas magique ; elle suit des règles déterministes que vous pouvez observer, tester et optimiser. En maîtrisant la mise en cache par couches, les builds multi-étapes, les caches de montage et le partage de cache, vous pouvez réduire les temps de build d'un ordre de grandeur et diminuer les coûts CI. La clé est de traiter le cache comme un atout précieux : surveillez-le, structurez vos Dockerfiles pour maximiser la réutilisation et évitez les pièges courants qui l'invalident silencieusement. Commencez par une amélioration pratique de ce guide—par exemple, réorganisez un Dockerfile ou ajoutez un .dockerignore—mesurez les temps de build avant et après en utilisant les commandes fournies, et itérez jusqu'à ce que vos builds soient fiablement rapides. Rappelez-vous qu'un système de build fiable rend les échecs visibles, protège les données sensibles et vous donne la confiance que vos images Docker sont construites de manière efficace et reproductible.

Recherches connexes

Score de qualité de l’article

Utilité pour le lecteur 100%
  • check_circle Guide prêt à lire
  • check_circle Exemples pratiques inclus
  • check_circle URL d’article optimisée pour le SEO