Introduction
Un laboratoire local de cache de build Docker vous permet de reproduire le comportement de build en toute sécurité avant de modifier les pipelines de production. L'objectif est de passer d'un problème observé à un résultat vérifié dans un environnement contrôlé où vous pouvez inspecter le cache, tester les modifications et apprendre les procédures de récupération sans affecter l'infrastructure partagée.
Ce guide couvre un flux de travail complet : vérification des versions de Docker et de BuildKit installées, compréhension de votre topologie, vérification des prérequis, observation de l'état actuel du cache, apport de modifications limitées et confirmation du résultat. Il s'adresse aux développeurs, consultants DevOps et équipes techniques de startups qui ont besoin d'exemples pratiques et concrets.
Tout au long de ce guide, nous gardons à l'esprit la sécurité opérationnelle : observer avant de modifier, limiter le rayon d'impact, utiliser des espaces réservés au lieu de secrets, vérifier les résultats et documenter comment récupérer si l'état attendu n'est pas atteint.
Inventaire des versions et de l'environnement
Avant de toucher à toute configuration de build, établissez exactement avec quoi vous travaillez. Exécutez les commandes en lecture seule suivantes et enregistrez la sortie avec des horodatages.
# Versions de Docker et BuildKit
docker version
docker buildx version
# Informations sur le démon Docker
docker info --format '{{.ServerVersion}}'
docker info --format '{{json .Driver}}'
# Builder actuel et support de buildkit
docker buildx ls
La sortie attendue pour docker version comprend une section client et serveur. Notez la version de l'API et l'OS/Arch. Pour BuildKit, le builder par défaut doit être listé avec un driver comme docker ou docker-container.
Exemple de sortie (Docker 24.0.7) :
Client: Docker Engine - Community
Version: 24.0.7
API version: 1.43
Go version: go1.20.10
Git commit: afdd53b
Built: Thu Oct 26 09:08:14 2023
OS/Arch: linux/amd64
Context: default
Server: Docker Engine - Community
Engine:
Version: 24.0.7
API version: 1.43 (minimum version 1.12)
Go version: go1.20.10
Git commit: 311b9ff
Built: Thu Oct 26 09:07:50 2023
OS/Arch: linux/amd64
Experimental: false
Point clé : Docker 23.0+ active BuildKit par défaut pour la commande docker build. Si vous utilisez une version plus ancienne, vous devrez peut-être définir DOCKER_BUILDKIT=1 ou utiliser explicitement docker buildx build.
Vérifier le stockage du cache de build
Les données du cache peuvent se trouver à différents endroits selon le builder. Pour le driver docker par défaut utilisant BuildKit, le cache est stocké dans le répertoire de données Docker, généralement /var/lib/docker. Pour le driver docker-container, un volume dédié stocke le cache et l'état de build.
# Lister le builder actuel et inspecter sa configuration
docker buildx inspect --bootstrap
# Pour le driver docker-container, vérifier le conteneur sous-jacent
docker ps --filter "name=buildx_buildkit"
Exemple de sortie de docker buildx inspect --bootstrap :
Name: default
Driver: docker
Nodes:
Name: default
Endpoint: default
Status: running
Buildkit: v0.12.4
Platforms: linux/amd64, linux/arm64, linux/386
Si vous devez isoler le cache pour les tests de laboratoire, créez un builder dédié :
# Créer un nouveau builder utilisant le driver docker-container
docker buildx create --name lab-builder --driver docker-container --use
# Vérifier que le builder est actif
docker buildx ls
Maintenant, docker buildx inspect --bootstrap lab-builder affichera le nom du volume de cache (généralement buildx_buildkit_lab-builder0_cache) et d'autres détails.
Stockage des données pour les artefacts de build
Lorsque vous testez des applications qui produisent ou consomment des fichiers, décidez où les données doivent résider avant de démarrer les conteneurs. Un volume nommé est géré par Docker et est plus facile à réutiliser entre les reconstructions de conteneurs. Un montage bind mappe directement un répertoire hôte et est utile pour le développement local, mais il peut introduire des problèmes de permissions et de portabilité.
Exemple : exécuter un build qui écrit dans un volume nommé
# Créer un volume nommé
docker volume create build-artifacts
# Exécuter un conteneur avec le volume monté
docker run --rm -v build-artifacts:/app/data alpine sh -c 'echo hello > /app/data/greeting.txt'
# Vérifier que les données persistent après la sortie du conteneur
docker run --rm -v build-artifacts:/app/data alpine cat /app/data/greeting.txt
# Résultat attendu : hello
Exemple : utiliser un montage bind pour le développement
mkdir -p ./local-data
docker run --rm -v "$(pwd)/local-data:/app/data" alpine sh -c 'echo hello > /app/data/greeting.txt'
cat ./local-data/greeting.txt
# Résultat attendu : hello
Test de redémarrage pour la persistance des données :
- Exécutez un conteneur de service avec un volume.
- Écrivez un fichier marqueur dans le conteneur (ou laissez l'application le faire).
- Arrêtez et supprimez le conteneur.
- Recréez le conteneur avec le même volume.
- Vérifiez que le fichier marqueur existe toujours.
Si le fichier est absent, le service écrivait probablement dans la couche inscriptible du conteneur plutôt que dans le volume.
Chemin de configuration sécurisé
Le chemin sécurisé est le suivant : observer l'état actuel, sauvegarder la configuration existante le cas échéant, apporter une modification limitée, vérifier et avoir un plan de retour en arrière. Pour le cache de build Docker, les modifications de configuration les plus courantes impliquent :
- Choisir le driver BuildKit et le backend de cache
- Définir les options de montage de cache dans les Dockerfiles
- Configurer le cache distant (registre, S3, etc.)
- Ajuster le garbage collection et la rétention
Commencez par une expérience simple : activez BuildKit et comparez la réutilisation du cache.
Activer BuildKit pour Docker Build
Si vous êtes sur Docker <23.0 ou souhaitez être explicite, définissez la variable d'environnement :
# Activer BuildKit pour le shell actuel
export DOCKER_BUILDKIT=1
# Construire une image avec buildkit
docker build -t myapp:test .
Avec Docker 23.0+, BuildKit est le builder par défaut et aucune variable d'environnement n'est nécessaire. Vous pouvez également utiliser docker buildx build pour plus de contrôle :
docker buildx build -t myapp:test .
Exemple de Dockerfile avec montages de cache
Les montages de cache permettent aux étapes de build de réutiliser les caches des gestionnaires de paquets entre les builds, accélérant ainsi les builds répétés. Le Dockerfile suivant utilise un montage de cache pour les paquets apt.
# syntax=docker/dockerfile:1.4
FROM ubuntu:22.04
RUN --mount=type=cache,target=/var/cache/apt \
apt-get update && apt-get install -y curl
Construisez l'image deux fois et observez que le deuxième build est plus rapide et réutilise la couche de cache.
# Premier build
docker build -t cache-test .
# Deuxième build (le cache devrait être réutilisé)
docker build -t cache-test .
Recherchez des lignes comme => CACHED dans la sortie du build. Pour l'étape apt-get, vous devriez voir quelque chose de similaire à :
=> [2/2] RUN --mount=type=cache,target=/var/cache/apt apt-get update && apt-get install -y curl 0.5s
Lors des builds suivants, la sortie peut indiquer => CACHED pour cette étape.
Configurer le garbage collection pour BuildKit
BuildKit dispose d'un garbage collector qui supprime les données de cache inutilisées. Vous pouvez contrôler son comportement dans la configuration du builder. Pour un builder avec le driver docker-container, vous pouvez passer la configuration lors de la création du builder.
# Créer un builder avec une politique de GC personnalisée
docker buildx create --name lab-gc --driver docker-container \
--driver-opt env.BUILDKIT_STEP_EXECUTOR_DISABLE_CACHE=0 \
--config ./buildkitd.toml
Tout d'abord, créez un fichier buildkitd.toml :
[worker.oci]
gc = true
gckeepstorage = 5000 # garder le cache jusqu'à 5 Go
[[worker.oci.gcpolicy]]
keepBytes = 512000000 # 512 Mo
keepDuration = 172800 # 48 heures
filters = [ "type==source.local", "type==exec.cachemount", "type==source.git.checkout" ]
[[worker.oci.gcpolicy]]
all = true
keepBytes = 1024000000 # 1 Go
Ensuite, inspectez le builder pour confirmer que la configuration a été appliquée :
docker buildx inspect --bootstrap lab-gc
Attention : La modification des paramètres de GC peut affecter l'utilisation du disque et la rétention du cache. En laboratoire, commencez par des valeurs conservatrices et observez sur quelques builds avant d'appliquer en production.
Vérification et diagnostics
Une fois qu'un build est en cours ou terminé, vérifiez le comportement du cache avec des commandes concrètes. L'objectif est de répondre : le cache a-t-il réellement été utilisé ? Quelles couches ont été mises en cache ? Où le builder stocke-t-il les données du cache ?
Inspecter la sortie du build
Exécutez un build avec la sortie de progression définie sur plain pour voir les informations détaillées des couches :
docker buildx build --progress=plain -t myapp:test .
Recherchez des lignes comme #34 CACHED ou #34 DONE 1.2s. CACHED indique la réutilisation de la couche.
Pour forcer un build sans cache à des fins de comparaison :
docker buildx build --no-cache --progress=plain -t myapp:test .
Comparez les temps de build avec la commande time :
time docker buildx build -t myapp:test .
Exemples de sorties :
- Build avec cache :
real 0m2.345s - Build sans cache :
real 1m12.890s
Utiliser docker buildx du pour voir la taille du cache
Buildx fournit une commande pour afficher l'utilisation du disque par le cache :
docker buildx du
Exemple de sortie :
ID RECLAIMABLE SIZE LAST ACCESSED
8ldp1z5l91 true 812.5MB 3 minutes ago
3q8p0c2m4n false 1.2GB 1 hour ago
Vous pouvez libérer de l'espace avec docker buildx prune (voir la section récupération).
Inspecter une couche Docker spécifique
Pour voir quels fichiers une couche de build a ajoutés, utilisez docker history :
docker history myapp:test
Exemple de sortie :
IMAGE CREATED CREATED BY SIZE
abc123456789 2 minutes ago RUN /bin/sh -c apt-get update && apt-get in... 45MB
Ou utilisez docker image inspect pour obtenir les IDs des couches, puis docker save pour les extraire si nécessaire. Pour un débogage plus avancé, exécutez un conteneur à partir de l'image et inspectez le système de fichiers.
Vérifier les journaux du conteneur pour le démon BuildKit
Si vous utilisez un builder docker-container, vous pouvez afficher ses journaux :
docker logs buildx_buildkit_lab-builder0
Cela peut afficher des avertissements ou des erreurs concernant les opérations de cache.
Tester la persistance des données avec des conteneurs
Comme mentionné précédemment, si votre build produit des données qui doivent persister, testez avec un scénario simple. Créez un conteneur qui écrit un fichier, quittez, puis exécutez un autre conteneur avec le même volume pour lire le fichier.
# Écrire un fichier
docker run --rm -v testvol:/data alpine sh -c 'echo important > /data/file.txt'
# Le relire
docker run --rm -v testvol:/data alpine cat /data/file.txt
# Résultat attendu : important
Si la lecture renvoie une erreur, le volume n'était pas attaché ou le chemin diffère.
Modes de défaillance et récupération
Malgré une configuration soignée, des problèmes surviennent. Voici les modes de défaillance courants pour le cache de build Docker et comment récupérer.
Défaillance : Le cache n'est pas réutilisé
Symptôme : Chaque build prend autant de temps qu'un build sans cache. Vous ne voyez aucune ligne CACHED dans la sortie du build.
Causes probables :
- Les instructions du Dockerfile invalident souvent le cache (par exemple,
COPY . .après un fichier fréquemment modifié, ouRUN apt-get updatesans épinglage de version). - Le contexte de build est énorme et inclut des fichiers inutiles, provoquant des changements de couches.
- BuildKit n'est pas activé ou utilise un builder différent.
- Le cache a été purgé ou a expiré en raison du GC.
Diagnostic :
- Exécutez
docker buildx lspour confirmer le builder actif. - Vérifiez
docker buildx dupour voir si le cache existe. - Inspectez la sortie du build avec
--progress=plainpour voir quelle étape brise la chaîne de cache.
Récupération :
- Réorganisez le Dockerfile pour placer les étapes fréquemment modifiées plus tard.
- Utilisez un fichier
.dockerignorepour exclure les fichiers inutiles du contexte. - Épinglez les tags d'images de base et les dépendances (par exemple,
FROM ubuntu:22.04au lieu deubuntu:latest). - Pour les gestionnaires de paquets, utilisez des montages de cache (
--mount=type=cache) comme indiqué précédemment.
Défaillance : Épuisement de l'espace disque
Symptôme : Le build échoue avec no space left on device ou le démon Docker signale une pression disque.
Diagnostic :
- Exécutez
df -hsur l'hôte. - Exécutez
docker system dfpour voir l'utilisation du disque par les objets Docker.
Exemple de sortie :
TYPE TOTAL ACTIVE SIZE RECLAIMABLE
Images 12 2 5.32GB 2.11GB (39%)
Containers 4 1 78MB 12MB (15%)
Local Volumes 8 2 1.8GB 300MB (16%)
Build Cache 25 0 9.2GB 9.2GB (100%)
Récupération :
docker buildx prunepour supprimer le cache de build. Utilisez des filtres pour supprimer uniquement le cache ancien ou inutilisé :docker buildx prune --filter until=24h.- Supprimez les images et volumes inutilisés :
docker system prune -a(attention : supprime toutes les données inutilisées). - Si vous utilisez un builder dédié, envisagez de réduire le stockage conservé par le GC ou d'augmenter la taille du disque hôte.
Défaillance : Cache corrompu ou incohérent
Symptôme : Le build utilise parfois une couche mise en cache mais produit une sortie incorrecte, ou le build échoue avec des erreurs liées au cache.
Cause : Bug de BuildKit, build interrompu laissant un cache partiel, ou modifications manuelles des fichiers de cache.
Récupération :
- Videz tout le cache de build :
docker buildx prune --force. - Recréez le builder si vous utilisez le driver docker-container :
docker buildx rm lab-builder && docker buildx create --name lab-builder --driver docker-container. - Reconstruisez à partir de zéro sans cache :
docker buildx build --no-cache -t myapp:test ..
Défaillance : Secrets exposés dans le cache de build
Symptôme : Les secrets transmis via les arguments de build ou copiés dans les couches d'image se retrouvent dans le cache et peuvent être extraits.
Prévention :
- N'utilisez jamais les arguments de build pour les secrets. Utilisez les montages de secrets BuildKit :
RUN --mount=type=secret,id=mysecret cat /run/secrets/mysecret. - Utilisez des builds multi-étapes pour éviter de copier des fichiers sensibles dans les couches finales.
Récupération :
- Purgez le cache de build et reconstruisez. Faites pivoter tous les secrets exposés.
Liste de contrôle opérationnelle
Parcourez cette liste de contrôle dans votre laboratoire avant et après toute expérience de cache de build. Chaque élément comprend le responsable et la fréquence de révision.
| Vérification | Action | Signal attendu | Responsable | Fréquence de révision |
|---|---|---|---|---|
| Compatibilité des versions | Exécutez docker version et docker buildx version | Docker 23.0+ et BuildKit v0.12+ | Priya Shah, responsable ingénierie | Mensuelle |
| Builder actif | docker buildx ls | Builder default avec driver docker et statut en cours d'exécution | Priya Shah | Hebdomadaire |
| Stockage du cache | docker buildx du | Taille récupérable totale < 80% du disque | Alex Chen, DevOps | Hebdomadaire |
| Efficacité du cache du Dockerfile | Construisez deux fois et comparez les temps ; vérifiez les lignes CACHED | Deuxième build au moins 50% plus rapide | Développeur de garde | Par projet |
| Persistance des données | Test de redémarrage avec volume | Le fichier reste après la recréation du conteneur | Ingénieur QA | Par version |
| Gestion des secrets | Examinez le Dockerfile pour les arguments de build ou les secrets copiés | Aucun secret dans les arguments de build ; montages de secrets utilisés | Responsable sécurité | Trimestrielle |
| Préparation à la récupération | Documentez et testez la commande docker buildx prune | Cache vidé et builds toujours réussis | Alex Chen, DevOps | Mensuelle |
Effectuez ces vérifications dans un environnement de laboratoire dédié avant d'appliquer les modifications au CI/CD. Enregistrez les résultats et comparez les tendances au fil du temps.
Pièges courants et comment les éviter
- Ne pas utiliser BuildKit
- Pourquoi cela arrive : Anciennes versions de Docker ou habitude.
- Éviter : Passez à Docker 23.0+ ou définissez explicitement
DOCKER_BUILDKIT=1. Utilisez les commandesdocker buildx.
- Tag d'image de base fréquemment modifié
- Pourquoi : L'utilisation de tags
latestou flottants invalide fréquemment le cache. - Éviter : Épinglez des versions exactes, par exemple,
FROM node:18.17.1-alpine.
- Copier tout le répertoire du projet trop tôt
- Pourquoi :
COPY . .avant l'installation des dépendances invalide le cache de l'installation des dépendances à chaque modification du code source. - Éviter : Copiez d'abord uniquement les fichiers de manifeste de dépendances (package.json, requirements.txt) et installez les dépendances, puis copiez le reste.
- Exemple de Dockerfile :
FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
- Oublier
.dockerignore
- Pourquoi : Le contexte de build inclut node_modules, .git, les journaux, etc., rendant le contexte énorme et provoquant des changements de couches.
- Éviter : Créez un fichier
.dockerignoreavec au minimumnode_modules,.git,*.log.
- Ne pas utiliser de montages de cache pour les gestionnaires de paquets
- Pourquoi : Chaque build re-télécharge les paquets.
- Éviter : Utilisez
--mount=type=cachepour apt, pip, npm, etc.
- Mal comprendre
docker buildx prune
- Pourquoi : Exécuter prune sans filtres supprime tout le cache, ralentissant les prochains builds.
- Éviter : Utilisez
--filter until=24hou--filter label=...pour supprimer uniquement le cache ancien.
- Stocker des secrets dans les couches de build
- Pourquoi : Essayer de transmettre des secrets via des arguments de build ou de copier des fichiers .env.
- Éviter : Utilisez les montages de secrets BuildKit ou des variables d'environnement d'exécution (dans l'orchestration, pas dans l'image).
- Supposer que le cache est partagé entre les builders
- Pourquoi : Chaque builder a son propre stockage de cache ; utiliser des noms de builders différents pour différents projets empêche la réutilisation.
- Éviter : Utilisez un builder cohérent pour les projets liés ou configurez un cache distant.
Conclusion
Un laboratoire local de cache de build Docker vous permet de tester le comportement du cache, de diagnostiquer les défaillances et de pratiquer la récupération sans impacter la production. La clé est de travailler méthodiquement : inventorier votre environnement, apporter une modification à la fois, vérifier avec des commandes concrètes et documenter les signaux de succès et d'échec.
Commencez par une vérification à faible risque : exécutez docker buildx ls pour voir votre builder, construisez une image simple deux fois et observez la réutilisation du cache avec --progress=plain. Enregistrez les temps de build et la taille du cache avant et après.
N'oubliez pas que la gestion du cache est une responsabilité opérationnelle. Des vérifications régulières de l'utilisation du disque, de la gestion des secrets et de l'efficacité du cache maintiennent les builds rapides et sécurisés. En cas de doute, ne supposez jamais que le cache fonctionne : prouvez-le avec des commandes et gardez un plan de retour en arrière prêt.
Un flux de travail technique fiable rend les défaillances visibles, protège les valeurs sensibles, limite les modifications à la ressource prévue et définit la vérification de récupération avant qu'un incident ne force la décision.