Introduction
La planification des capacités pour Docker BuildKit consiste à déterminer la quantité de CPU, de mémoire, de disque et de parallélisme dont votre infrastructure de build a besoin, puis à l'ajuster en toute sécurité à mesure que les charges de travail évoluent. L'objectif est d'éviter les builds lents, les pannes de mémoire insuffisante, les caches gonflés et les débogages pénibles pendant une fenêtre de release.
Ce guide s'adresse aux développeurs, consultants DevOps et équipes techniques de startups qui exécutent des builds Docker en CI ou sur des serveurs de build partagés. Il relie le dimensionnement des ressources, les limites de mise à l'échelle et le comportement du cache à des commandes réelles, des sorties attendues et des étapes de reprise. Plutôt qu'une liste de réglages abstraits, chaque section vous donne un flux de travail concret : observer l'état actuel, effectuer un changement ciblé, vérifier le résultat et savoir comment revenir en arrière.
La sécurité opérationnelle est la priorité tout au long de ce guide. Nous utiliserons d'abord des diagnostics en lecture seule, protégerons les secrets, limiterons le rayon d'impact de tout changement et documenterons la vérification de la reprise avant qu'un incident ne force une décision.
Inventaire des versions et de l'environnement
Avant de modifier un paramètre de BuildKit, confirmez ce que vous exécutez, où cela s'exécute et comment c'est configuré. Commencez par les versions de Docker et BuildKit, le mode de déploiement (démon Docker avec BuildKit intégré, démon BuildKit autonome ou builder distant) et les ressources de l'hôte disponibles.
Vérifier les versions de Docker et BuildKit
Exécutez ces commandes pour capturer l'état actuel :
docker version --format '{{.Server.Version}}'
docker buildx version
La sortie attendue montre la version du moteur Docker (par exemple, 24.0.7) et la version du plugin Buildx (par exemple, v0.12.0). Notez que les versions de Buildx antérieures à 0.9 peuvent ne pas prendre en charge toutes les fonctionnalités de BuildKit ; consultez les notes de version de votre version si vous prévoyez d'utiliser des backends de cache avancés ou des builders distants.
Déterminer le mode de déploiement de BuildKit
BuildKit s'exécute dans deux modes courants :
- Intégré au démon Docker : Par défaut,
docker buildutilise le BuildKit intégré du démon lorsqueDOCKER_BUILDKIT=1ou lorsque le démon est configuré avec"features": { "buildkit": true }. C'est simple mais partage les ressources avec les conteneurs. - Démon BuildKit autonome : Exécutez
buildkitdcomme un service séparé et connectez-vous viadocker buildx create --name mybuilder --driver docker-container --driver-opt network=host --use. Cela isole les builds du démon principal et permet des limites de ressources dédiées.
Vérifiez quel builder est actif :
docker buildx ls
Si le builder actif affiche docker sous DRIVER, les builds utilisent le BuildKit du démon. S'il affiche docker-container, les builds s'exécutent dans un conteneur séparé avec ses propres contraintes de ressources.
Confirmer les ressources de l'hôte
Enregistrez le CPU, la mémoire et le disque :
nproc
free -h
df -h /var/lib/docker
Ces chiffres sont importants car les performances de BuildKit dépendent fortement des workers parallèles et du stockage du cache. Par exemple, si nproc renvoie 4, le GOMAXPROCS par défaut peut limiter BuildKit à quatre opérations parallèles à moins d'ajuster le flag --oci-worker-parallelism ou BUILDKIT_STEP_LOG_MAX_SIZE.
Points clés de l'inventaire des versions et de l'environnement
- Exécutez toujours des vérifications en lecture seule avant tout changement.
- Capturez la sortie avec un horodatage ; les changements ultérieurs deviennent plus faciles à comparer.
- Protégez les identifiants : si vous inspectez un builder avec
docker buildx inspect --bootstrap, évitez d'imprimer les secrets de build. Utilisez--output=jsonet masquez les champs sensibles. - Un changement sûr ici consiste à enregistrer l'environnement dans un runbook, pas à le modifier. Le plus petit changement justifié pourrait être de créer un fichier texte avec
docker buildx ls > buildx-state-$(date +%Y%m%d).txt. - Vérification : après l'enregistrement,
ls -l buildx-state-*.txtmontre que le fichier existe. La reprise est triviale : supprimez le fichier s'il n'est pas nécessaire.
Chemin de configuration sûr
La modification de la configuration de BuildKit doit suivre un chemin structuré : identifier le paramètre, changer une chose à la fois, vérifier le résultat et savoir comment revenir en arrière si le build se détériore. Cette section couvre les limites de ressources, le parallélisme et les paramètres de cache avec des exemples concrets.
Étape 1 : Établir une base de référence des performances de build actuelles
Avant d'ajuster un réglage, mesurez le temps de build et l'utilisation des ressources actuels. Créez un petit Dockerfile de test avec quelques couches et une étape de longue durée (par exemple, compiler quelque chose ou exécuter sleep). Chronométrez le build :
time docker build -t test:baseline .
Enregistrez le résultat, par exemple, real 2m30.5s. Exécutez également docker stats dans un autre terminal pendant le build pour observer l'utilisation du CPU et de la mémoire. Notez les valeurs maximales.
Étape 2 : Modifier un paramètre : limites de mémoire
Un problème courant est que BuildKit dépasse la mémoire disponible et provoque des OOM kills (tués par manque de mémoire). En mode intégré, vous pouvez limiter la mémoire du démon via systemd ou en exécutant le démon avec --memory (pas directement ; à la place, le conteneur BuildKit lui-même peut être limité si vous utilisez le driver docker-container). Pour BuildKit autonome, définissez la limite de mémoire du conteneur :
docker run -d --name buildkitd --privileged --memory=4g --memory-swap=4g moby/buildkit:latest
Si vous utilisez Buildx avec le driver docker-container, définissez des limites dans la commande create :
docker buildx create --name limited-builder --driver docker-container \
--driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE=10m \
--driver-opt memory=4g --use
Après le changement, reconstruisez le test et comparez les temps et docker stats. Si le build échoue avec OOM, la limite est trop basse ; augmentez-la progressivement.
Étape 3 : Ajuster le parallélisme
BuildKit met automatiquement à l'échelle les étapes parallèles en fonction des CPU disponibles, mais vous pouvez le remplacer si vous avez de nombreuses petites étapes liées aux E/S ou si vous voulez éviter le thrashing (écrasement). Dans la configuration du démon BuildKit (/etc/buildkit/buildkitd.toml), définissez :
[worker.oci]
maxParallelism = 8
Ou via une variable d'environnement lors du démarrage de buildkitd : BUILDKIT_OCI_WORKER_MAX_PARALLELISM=8. Redémarrez le démon pour que le changement prenne effet. Réexécutez le build de test et observez si le temps global diminue ; si le CPU est saturé et que les builds ralentissent, réduisez le parallélisme.
Étape 4 : Configurer l'emplacement et la taille du stockage du cache
Le cache de BuildKit peut devenir volumineux et remplir le disque. En mode autonome, spécifiez un répertoire de cache avec une limite de taille dans buildkitd.toml :
[worker.oci]
enabled = true
gc = true
gckeepstorage = 20000 # 20 Go
Cela active le garbage collection (ramasse-miettes) et maintient le cache en dessous de 20 Go. Alternativement, pour le driver docker-container, --driver-opt env.BUILDKIT_STEP_LOG_MAX_SIZE concerne les journaux ; pour le cache, vous pouvez monter un volume et définir la politique de GC via un fichier de configuration. Vérifiez la taille du cache après les builds :
du -sh /var/lib/buildkit
Vérification et retour en arrière
Après tout changement de configuration :
- Réexécutez le build de base deux fois (pour réchauffer le cache) et comparez les temps.
- Vérifiez
docker logs buildkitdpour les avertissements ou erreurs. - Si le changement dégrade les performances, revenez à la configuration précédente. Comme vous n'avez changé qu'un seul paramètre, le retour est simple : redémarrez avec l'ancienne valeur ou recréez le builder sans l'option.
Responsable et cadence de revue : Le responsable de l'infrastructure de build (par exemple, le lead DevOps) doit approuver les changements de configuration. Revoyez les paramètres de capacité mensuellement ou après tout changement significatif de la charge de travail de build (par exemple, ajout d'un nouveau microservice).
Vérification et diagnostics
Après la fin d'un build ou pendant un long build, vous devez vérifier que BuildKit utilise les ressources comme prévu et que la sortie du build est correcte. Cette section fournit des commandes pour inspecter l'état de BuildKit, diagnostiquer les problèmes et confirmer que le build correspond au Dockerfile.
Inspecter les builds actifs et l'historique
Utilisez docker buildx du pour voir l'utilisation du cache :
docker buildx du
La sortie attendue liste les enregistrements du cache avec les tailles et les types (par exemple, Regular 34.5MB, Source 2.1MB). Si le cache est anormalement volumineux, recherchez quelles couches prennent de l'espace.
Pour voir la progression d'un build en temps réel avec plus de détails, définissez BUILDKIT_PROGRESS=plain :
BUILDKIT_PROGRESS=plain docker build -t myapp .
Cela affiche chaque étape avec son temps d'exécution, vous aidant à repérer quelle commande RUN est lente.
Vérifier les journaux du démon BuildKit
Pour BuildKit autonome, suivez les journaux :
docker logs -f buildkitd
Recherchez des messages comme error: failed to solve ou executor failed running. Si vous utilisez le driver docker-container, utilisez docker logs <nom-du-conteneur-builder> (trouvez-le via docker ps).
Valider l'utilisation des ressources pendant le build
Pendant qu'un build est en cours, ouvrez un autre terminal et exécutez :
docker stats --no-stream
Concentrez-vous sur le conteneur BuildKit (si autonome) ou le processus du démon (si intégré). Vérifiez le pourcentage de CPU et l'utilisation de la mémoire. Si la mémoire est proche de la limite, envisagez d'augmenter la limite ou de réduire le parallélisme.
Confirmer la reproductibilité du build
Un diagnostic clé consiste à s'assurer qu'un build propre produit la même image qu'un build en cache. Construisez deux fois avec --no-cache et comparez les identifiants d'image :
docker build --no-cache -t myapp:clean1 .
docker build --no-cache -t myapp:clean2 .
docker image inspect myapp:clean1 --format '{{.Id}}'
docker image inspect myapp:clean2 --format '{{.Id}}'
Si les identifiants diffèrent, le Dockerfile contient probablement des étapes non déterministes (par exemple, apt-get update sans versions épinglées, ou copie de fichiers avec des horodatages changeants). Cela affecte l'efficacité du cache et doit être corrigé.
Diagnostiquer les échecs courants
failed to solve: executor failed running [/bin/sh -c ...]: Une commande RUN a échoué. Vérifiez le code de sortie de la commande et corrigez le Dockerfile. La sortie montre généralement la commande exacte et l'erreur.error: failed to load cache key: Échec de la recherche de cache, dû à des montages de cache manquants ou incompatibles. Vérifiez que les chemins--mount=type=cachesont cohérents.ERROR: BuildKit is enabled but the buildx component is missing or broken: Installez ou réinstallezdocker-buildx-plugin. Exécutezdocker buildx versionpour confirmer.
Responsable et cadence de revue : Tout développeur peut exécuter des commandes de diagnostic, mais le responsable de l'infrastructure de build doit revoir les tendances des diagnostics chaque semaine. Utilisez un tableau de bord ou une agrégation de journaux pour suivre les temps de build et les taux d'échec.
Modes de défaillance et reprise
Même avec une planification minutieuse, les builds peuvent échouer. Comprendre les modes de défaillance courants vous aide à récupérer rapidement. Voici quelques échecs fréquents de BuildKit avec leurs causes et étapes de reprise.
Échec : espace disque insuffisant
Symptômes : Le build échoue avec no space left on device ou failed to allocate new chunk dans les journaux de BuildKit. df -h montre une utilisation à 100% sur la partition contenant le cache de BuildKit.
Pourquoi cela arrive : Le cache de BuildKit grossit sans garbage collection, ou de nombreux builds parallèles accumulent des couches.
Comment récupérer :
- Libérez de l'espace immédiatement :
docker buildx prune --filter until=24houdocker builder prune --all(attention : cela supprime tout le cache de build). - Pour une solution persistante, activez le GC avec une limite de stockage (comme dans la section Chemin de configuration sûr). Pour le driver docker-container, définissez
BUILDKIT_KEEP_STORAGEou montez un volume de cache plus petit. - Vérifiez :
df -hmontre de l'espace libre et un nouveau build réussit.
Prévention : Surveillez l'utilisation du disque et définissez des alertes à 80% de capacité. Planifiez un nettoyage régulier du cache.
Échec : le build se bloque ou expire
Symptômes : Le build semble bloqué, aucune sortie pendant longtemps, finalement le CI le tue.
Pourquoi cela arrive : Peut être un deadlock (interblocage) dans BuildKit dû à l'épuisement des ressources, un problème réseau lors du tirage des images de base, ou une étape attendant une entrée (par exemple, une commande interactive).
Comment récupérer :
- Annulez le build (Ctrl+C ou timeout CI).
- Vérifiez
docker pspour voir si un conteneur BuildKit ne répond pas ; redémarrez-le :docker restart buildkitd. - Réexécutez avec
BUILDKIT_PROGRESS=plainpour voir la dernière étape. Ajoutez--progress=plainpour obtenir des journaux étape par étape. - Si problème réseau, testez la connectivité :
docker run --rm alpine ping -c 2 registry-1.docker.io.
Prévention : Définissez des timeouts de build dans le CI, utilisez --pull pour garantir les dernières images de base, et évitez les étapes qui peuvent demander une entrée (par exemple, apt-get install sans -y).
Échec : invalidation du cache à chaque build
Symptômes : Les builds prennent autant de temps que des builds propres ; docker buildx du montre que le cache est recréé à chaque fois.
Pourquoi cela arrive : Les étapes du Dockerfile changent fréquemment (par exemple, COPY . . avant RUN npm install), ou des arguments de build avec horodatages, ou des commandes non déterministes.
Comment récupérer :
- Réorganisez le Dockerfile pour mettre les étapes stables en premier (par exemple, installation des paquets avant copie du code source).
- Utilisez
--mount=type=cachepour des répertoires comme/root/.cacheou/go/pkg/modafin de persister entre les builds. - Épinglez les versions des images de base et évitez
latest. - Vérifiez en exécutant deux builds consécutifs ; le second devrait être beaucoup plus rapide (souvent moins d'une minute pour un code inchangé).
Prévention : Éduquez les développeurs sur les bonnes pratiques de Dockerfile ; utilisez des linters comme hadolint.
Échec : le démon BuildKit plante
Symptômes : docker buildx ls affiche une erreur de builder, docker logs buildkitd montre des paniques ou des messages OOM.
Pourquoi cela arrive : Mémoire insuffisante ou un bug dans BuildKit.
Comment récupérer :
- Redémarrez le démon :
docker restart buildkitdou recréez le builder :docker buildx rm mybuilder && docker buildx create --name mybuilder --use. - Augmentez la limite de mémoire comme décrit précédemment.
- Si le plantage persiste, mettez à jour BuildKit vers la dernière version.
Prévention : Surveillez l'utilisation de la mémoire et définissez des limites en fonction de la RAM disponible de l'hôte. Gardez BuildKit à jour.
Responsable et cadence de revue : L'ingénieur d'astreinte gère la récupération immédiate. La revue post-incident doit être effectuée dans les 48 heures, et toute action préventive assignée au responsable de l'infrastructure de build.
Liste de contrôle opérationnelle
Utilisez cette liste de contrôle avant et après les changements de capacité pour vous assurer qu'aucune étape n'est manquée. Remplacez les valeurs illustratives par votre environnement réel.
Liste de contrôle avant changement
- [ ] Confirmer la version Docker actuelle et le mode BuildKit : enregistré comme v24.0.7, intégré au démon.
- [ ] Enregistrer le temps de build de base pour un projet représentatif : le build de test prend 3m20s.
- [ ] Noter les ressources actuelles de l'hôte : 8 CPU, 16 Go de RAM, 50 Go libres sur /var/lib/docker.
- [ ] Identifier le paramètre unique à changer : par exemple, augmenter la mémoire du conteneur BuildKit de 4 Go à 6 Go.
- [ ] Déterminer la commande de retour en arrière : recréer le builder avec la limite de mémoire d'origine.
- [ ] Assigner un responsable au changement : Priya Shah, Engineering Lead.
- [ ] Planifier la fenêtre de changement : période de faible trafic, par exemple dimanche 02:00 UTC.
Vérification après changement
- [ ] Reconstruire le projet représentatif deux fois et comparer les temps : après changement, temps de build 3m05s (amélioration de 5%).
- [ ] Surveiller l'utilisation des ressources pendant le build : pic de mémoire 5,2 Go, dans la limite.
- [ ] Vérifier les journaux de BuildKit pour les erreurs : aucune.
- [ ] Confirmer le taux de succès du cache :
docker buildx dumontre des enregistrements de cache réutilisés ; taille du cache stable. - [ ] Exécuter un second build non lié pour s'assurer qu'il n'y a pas de régression : petit build Node.js, temps 45s (identique à avant).
- [ ] Documenter le changement et le résultat dans le runbook : « Augmentation de la mémoire BuildKit à 6 Go le 2025-04-01, amélioration du temps de build de 5%, aucun effet indésirable. »
- [ ] Fixer la date de revue : prochaine revue de capacité dans 30 jours.
Responsabilité : Le responsable de l'infrastructure de build (Priya Shah) est chargé de compléter la liste de contrôle. Le responsable DevOps examine la liste de contrôle complétée mensuellement.
Pièges courants et comment les éviter
Même avec une planification minutieuse des capacités, les équipes commettent souvent des erreurs évitables. Voici les pièges les plus courants, pourquoi ils surviennent et comment les prévenir ou s'en remettre.
Piège 1 : Ignorer la limite de stockage du cache
Pourquoi cela arrive : Le cache de BuildKit grossit silencieusement et les équipes supposent que l'espace disque est infini.
Comment éviter : Définissez une limite de stockage et activez le GC dès le départ. Dans buildkitd.toml, utilisez gckeepstorage. Pour le driver docker-container, surveillez régulièrement docker buildx du.
Reprise : Si le disque se remplit, exécutez immédiatement docker buildx prune --all, puis définissez des limites pour éviter la récurrence.
Piège 2 : Sursouscrire le CPU avec trop de parallélisme
Pourquoi cela arrive : Les équipes définissent maxParallelism plus haut que le nombre de cœurs CPU, espérant des builds plus rapides, mais les changements de contexte et la contention E/S ralentissent tout.
Comment éviter : Définissez le parallélisme au nombre de cœurs CPU ou légèrement moins (par exemple, pour 8 CPU, définissez maxParallelism = 6 pour laisser de la marge aux autres processus). Mesurez les temps de build avec différents réglages ; choisissez le plus rapide.
Reprise : Réduisez le parallélisme et reconstruisez. Si les builds sont toujours lents, profilez le Dockerfile avec --progress=plain pour trouver le vrai goulot d'étranglement.
Piège 3 : Ne pas épingler les images de base ou les dépendances
Pourquoi cela arrive : Utiliser FROM python:3 ou apt-get update sans verrouillage de version conduit à l'invalidation du cache et à des builds non reproductibles.
Comment éviter : Utilisez des tags spécifiques comme python:3.11-slim et épinglez les versions des paquets dans les fichiers de verrouillage. Pour apt, utilisez apt-get install -y --no-install-recommends package=version.
Reprise : Mettez à jour le Dockerfile avec des versions épinglées et reconstruisez. Vérifiez avec deux builds consécutifs : le second devrait utiliser le cache pour les couches de base et de dépendances.
Piège 4 : Exécuter BuildKit en tant que root sans limites de ressources
Pourquoi cela arrive : La commodité conduit à exécuter buildkitd en tant que root sans contraintes de mémoire ou de CPU, risquant l'instabilité de l'hôte.
Comment éviter : Exécutez BuildKit dans un conteneur avec des limites de ressources explicites (par exemple, --memory=4g --cpus=2). Pour BuildKit autonome, utilisez une unité systemd avec MemoryMax et CPUQuota.
Reprise : Si un build consomme trop de mémoire et affecte d'autres services, arrêtez le build (docker stop buildkitd) et redémarrez avec des limites. Ensuite, augmentez progressivement si nécessaire.
Piège 5 : Oublier de nettoyer les builders distants
Pourquoi cela arrive : Les équipes créent des builders temporaires avec docker buildx create pour des tâches spécifiques et ne les suppriment jamais, laissant des conteneurs orphelins consommer des ressources.
Comment éviter : Adoptez une convention de nommage et exécutez périodiquement docker buildx rm pour les builders inutilisés, ou utilisez des builders éphémères en CI (par exemple, docker buildx create --name temp-$(git rev-parse --short HEAD) --use et supprimez-les à la fin du pipeline).
Reprise : Listez les builders avec docker buildx ls, supprimez ceux qui sont obsolètes et vérifiez avec docker ps que les conteneurs ont disparu.
Conclusion
La planification des capacités Docker BuildKit n'est pas une configuration unique ; c'est un processus continu d'observation, d'ajustement et de vérification. En suivant les pratiques de ce guide – cadrage des versions, changements de configuration sûrs, diagnostics détaillés et reprise après échec connue – vous pouvez garder des temps de build prévisibles et une infrastructure stable.
Commencez par une vérification à faible risque : enregistrez votre version actuelle de BuildKit et l'utilisation des ressources, exécutez un build de base avec chronométrage et examinez la taille du cache. Ensuite, effectuez un changement, comme définir une limite de stockage ou ajuster le parallélisme, et comparez les résultats. Documentez le résultat et attribuez un responsable pour revoir la capacité mensuellement.
Une infrastructure de build fiable rend les échecs visibles, protège les valeurs sensibles, limite les changements aux ressources prévues et définit la reprise avant qu'un incident ne force une décision. Avec ces exemples pratiques, vous avez les outils pour planifier et dimensionner Docker BuildKit en toute confiance.