Un runner de CI neuf, c'est-à-dire la machine qui exécute votre pipeline, n'a aucun cache : chaque build refait toutes les étapes, y compris l'installation des dépendances. Le cache distant de BuildKit règle ce problème : le premier build range son cache dans un registre, et le runner suivant le récupère avec --cache-from. Le réglage --cache-to a deux modes : min n'exporte que les couches de l'image finale, max exporte aussi celles des étapes intermédiaires. Cette page mesure ce que coûte et ce que rapporte chacun.
Elle traite ensuite la promotion : envoyer vers le registre de production l'image qui a été testée, sans la reconstruire, avec docker buildx imagetools create, skopeo copy --all ou crane copy. Elle s'adresse à qui écrit ou maintient un pipeline de construction d'images, et connaît déjà docker build et le principe d'un registre.
Quelques pages complètent celle-ci. La leçon Automatiser build, tests et publication d'une image montre un script ci.sh qui construit, teste puis publie une archive accompagnée de sa provenance, mais elle ne mesure ni le cache distant ni la promotion entre registres. Les outils de copie ont leurs guides, Crane et Skopeo. Le format des tags, des digests et des index est expliqué dans Comprendre OCI, leur usage dans Publier et récupérer une image de façon maîtrisée et dans Épingler un socle, et livrer hors ligne. Les images multi-plateformes sont dans Construire pour plusieurs architectures.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Exporter le cache de build vers un registre et le réimporter sur une machine vide.
- Corriger l'échec
connection refusedd'un builderdocker-containerqui vise un registre local. - Comparer
mode=minetmode=maxen taille de cache, temps d'export et temps de rebuild. - Copier une image d'un registre à l'autre en conservant le digest de son index, puis le vérifier.
- Repérer les deux copies qui perdent des plateformes tout en réussissant :
skopeo copysans--all, et l'enchaînementdocker pull,docker tag,docker push. - Choisir entre
imagetools, Skopeo et crane selon l'outil déjà présent dans le pipeline.
Dans quel environnement ces mesures ont-elles été faites ?
Section intitulée « Dans quel environnement ces mesures ont-elles été faites ? »Toutes les sorties viennent d'une machine virtuelle Debian 13 avec Docker Engine 29.9.2, Buildx 0.38.1 et le magasin d'images containerd, qui est le magasin des nouvelles installations de Docker 29. Les registres de test sont registry:3.1.2@sha256:d4032d4cc323c1731c707931ecada07a53076eac38e3b61ae57533f170f2c6c3, joints en HTTP sur 127.0.0.1.
Deux mots reviennent dans toute la page. Un builder est l'instance de BuildKit qui exécute vos builds, et son pilote (driver) décide où elle tourne. Le builder default utilise le pilote docker, avec BuildKit v0.34.0. Le builder docker-container, créé pour les mesures, lance BuildKit v0.34.2 dans un conteneur dédié, à partir de l'image moby/buildkit:v0.34.2@sha256:c5f8862f52499773af85bc07695b2379ef08e8002352b0df2c4864c91d78dabe. Le @sha256:… est le digest de l'image, l'empreinte de son contenu : l'épingler garantit que vous obtenez exactement cette image, même si le tag est déplacé. v0.34.2 est la dernière version publiée de moby/buildkit sur Docker Hub au 2026-11-04, et son digest est aussi celui des tags latest et buildx-stable-1 à cette date.
Si votre version diffère, ce qui est mesuré ici ne vaut que pour cette combinaison. Les durées et les tailles sont des mesures uniques, à lire comme des ordres de grandeur : relevez les vôtres sur vos runners et votre registre. L'ancien magasin d'images de Docker n'a pas été testé, et rien n'est affirmé sur son comportement.
Comment partager le cache de build entre deux exécutions de CI ?
Section intitulée « Comment partager le cache de build entre deux exécutions de CI ? »Deux options de docker buildx build suffisent : --cache-to type=registry,ref=<image de cache> écrit le cache dans un registre à la fin du build, et --cache-from type=registry,ref=<image de cache> le relit au début du suivant. Le cache est publié comme une image ordinaire, dans un dépôt dédié, par exemple cache/app. Les mesures de cette page s'appuient sur ce Dockerfile, dont les sleep rendent les durées lisibles sans changer ce qui est mis en cache :
FROM alpine:3.24.3@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9a AS depsRUN apk add --no-cache build-base python3 && sleep 3FROM deps AS buildCOPY app.c /src/app.cRUN sleep 3 && gcc -o /app /src/app.cFROM alpine:3.24.3@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9aCOPY --from=build /app /appRUN sleep 2 && echo final > /etc/finalCMD ["/app"]Il a trois étapes : deps installe un compilateur, build compile app.c, l'image finale ne garde que le binaire. Seule l'étape build dépend du code source, ce qui permet de mesurer ce qu'un changement de code relance.
Pour reproduire, travaillez dans un dossier vide, ~/refcache/app, où vous enregistrez le Dockerfile ci-dessus. Créez ensuite le fichier app.c à côté, puis démarrez le registre qui recevra le cache, publié sur l'adresse locale de la machine :
mkdir -p ~/refcache/app && cd ~/refcache/appprintf '#include <stdio.h>\nint main(){puts("hello");return 0;}\n' > app.cdocker run -d --name reg-cache -p 127.0.0.1:5080:5000 \ registry:3.1.2@sha256:d4032d4cc323c1731c707931ecada07a53076eac38e3b61ae57533f170f2c6c3D'après la documentation de Docker Build, le pilote docker ne prend en charge le backend registry que si le magasin d'images containerd est activé. Avec ce magasin sur Docker 29.9.2, le builder default exporte le cache vers un registre sans erreur.
Le premier export ci-dessous utilise mode=min, la valeur par défaut d'après la documentation des backends de cache. La section sur min et max plus bas compare les deux modes :
docker buildx build \ --cache-to type=registry,ref=127.0.0.1:5080/cache/app:y,mode=min \ -t app:t .La commande rend le code 0, et le dernier bloc de la sortie annonce writing cache image manifest. L'import par --cache-from avec ce pilote est mesuré dans le guide Docker Bake, section « Comment réutiliser le cache entre deux builds ? », avec le builder default. Les comparaisons ci-dessous utilisent un builder docker-container, parce que son cache est isolé : docker buildx prune --builder le vide sans toucher au builder default.
Pourquoi un builder docker-container échoue-t-il avec connection refused ?
Section intitulée « Pourquoi un builder docker-container échoue-t-il avec connection refused ? »Parce que BuildKit s'exécute alors dans son propre conteneur, et que l'adresse 127.0.0.1 y désigne ce conteneur, pas votre machine. Un builder créé sans option exporte les couches puis échoue au moment d'écrire dans le registre local :
docker buildx create --driver docker-container \ --driver-opt image=moby/buildkit:v0.34.2@sha256:c5f8862f52499773af85bc07695b2379ef08e8002352b0df2c4864c91d78dabe \ --name bk1docker buildx build --builder bk1 --progress=plain \ --cache-to type=registry,ref=127.0.0.1:5080/cache/app:min,mode=min \ -o type=cacheonly .ERROR: failed to build: failed to solve: error writing layer blob: failed to do request: Head "http://127.0.0.1:5080/v2/cache/app/blobs/sha256:7b229517ed222597277036d94892173207d01a731ab3a88eeb1de2e963a2c788": dial tcp 127.0.0.1:5080: connect: connection refusedRegardez la fin du message : dial tcp 127.0.0.1:5080: connect: connection refused dit que la connexion est refusée sur l'adresse 127.0.0.1 vue depuis le builder. Le message ne distingue pas un registre arrêté d'un builder qui ne voit pas le réseau de la machine.
Pour les séparer, lancez curl -sS -i http://127.0.0.1:5080/v2/ depuis la machine elle-même. Si le registre répond, il tourne bien et c'est le réseau du builder qui est en cause. S'il ne répond pas, démarrez ou réparez d'abord le registre. Voici les deux réponses mesurées, en-têtes abrégés :
# registre vivantHTTP/1.1 200 OKContent-Type: application/jsonDocker-Distribution-Api-Version: registry/2.0
{}
# registre arrêté (code de retour 7)curl: (7) Failed to connect to 127.0.0.1 port 5080 after 0 ms: Could not connect to serverDans notre cas le registre tournait, et l'option --driver-opt network=host fait partager à ce conteneur le réseau de la machine, ce qui corrige l'échec :
docker buildx create --driver docker-container \ --driver-opt network=host \ --driver-opt image=moby/buildkit:v0.34.2@sha256:c5f8862f52499773af85bc07695b2379ef08e8002352b0df2c4864c91d78dabe \ --name bk2docker buildx inspect bk2 --bootstrapinspect doit afficher Status: running, BuildKit version: v0.34.2 et Driver Options avec les valeurs image="moby/buildkit:v0.34.2@sha256:c5f8862f52499773af85bc07695b2379ef08e8002352b0df2c4864c91d78dabe" et network="host". La mesure porte uniquement sur un registre local. Face à un registre distant, joignable par un nom, ce contournement n'a pas été testé.
network=host est un contournement de banc d'essai local : il expose le réseau de la machine à un conteneur BuildKit privilégié. Ne le mettez pas par défaut sur un runner de CI partagé.
Quelle différence entre mode=min et mode=max ?
Section intitulée « Quelle différence entre mode=min et mode=max ? »Le mode min exporte seulement les couches de l'image finale, le mode max exporte aussi celles des étapes intermédiaires. Le cache d'une image est décrit par un manifeste de cache, la liste des couches qu'il contient. Sur le Dockerfile ci-dessus, le manifeste min contient 3 couches pour 3,9 Mo, et le manifeste max en contient 6 pour 117,5 Mo (la même couche de 3 267 octets y figure deux fois).
Le schéma suit les trois étapes du Dockerfile. Les flèches pleines montrent l'ordre des étapes ; la flèche épaisse part de l'image finale vers ce que min exporte, et les flèches pointillées montrent que max exporte les trois étapes.
La couche de 113,6 Mo, qui n'existe qu'en max, correspond à l'étape deps, là où l'installation de build-base pèse le plus. C'est ce qui fait la différence de taille entre les deux modes.
Le tableau résume quatre mesures. Avant chaque relecture, le cache local a été vidé avec docker buildx prune -af --builder bk2. L'export se fait avec --cache-to type=registry,ref=127.0.0.1:5080/cache/app:<mode>,mode=<mode> -o type=cacheonly, et la relecture avec --cache-from type=registry,ref=127.0.0.1:5080/cache/app:<mode>.
Pour la dernière ligne, le code source est modifié par echo '/* v2 */' >> app.c, qui ajoute un commentaire à la fin de app.c. Avant de passer à l'autre mode, app.c est restauré avec la commande printf de départ (printf '#include <stdio.h>\nint main(){puts("hello");return 0;}\n' > app.c), pour que les deux modes partent de la même source.
Les durées et la taille de min viennent d'un builder créé avec l'image moby/buildkit:buildx-stable-1, qui porte le même digest c5f8862f… que v0.34.2. Celles de max viennent de --builder bk2, épinglé sur v0.34.2.
| Situation | min | max |
|---|---|---|
| Build à froid avec export (durée totale) | 18,3 s | 28,0 s |
| Étape d'export du cache seule | 0,2 s | 9,4 s |
| Cache local vidé, source identique | 955 ms, tout en CACHED | 942 ms, tout en CACHED |
Cache local vidé, app.c modifié | 16,0 s, étape deps rejouée (11,3 s) | 6,6 s, étape deps en CACHED |
Les deux lignes de durée ne mesurent pas la même chose. Pour min, 0,2 s est l'étape d'export entière. Pour max, 9,4 s est la sous-étape preparing build cache for export, qui prépare le cache avant son écriture dans le registre.
La ligne importante est la dernière. Tant que le code ne change pas, les deux modes donnent le même résultat. Dès qu'une étape en amont de l'image finale doit être rejouée, min n'a rien à offrir pour elle et le runner réinstalle le compilateur, alors que max la reprend du registre. Dans la sortie de max, la ligne de l'étape deps affiche CACHED puis une durée de 2,0 s. Il s'agit probablement du temps de récupération de la couche, mais ce point n'a pas été vérifié séparément.
Le prix de max se lit dans les deux premières lignes : il écrit 117,5 Mo au lieu de 3,9 Mo et ajoute environ 9 s à chaque export. Sur ce Dockerfile, ces 9 s sont du même ordre que ce que max fait gagner à la relecture (16,0 s contre 6,6 s), et le registre est local.
max se justifie quand une étape lourde change rarement : plus elle est longue à rejouer, plus le cache de max rapporte. Si presque toutes les étapes changent à chaque commit, min peut suffire. Le critère est donc le poids des étapes intermédiaires que vos commits ne touchent pas, que vous mesurez sur vos runners.
Comment promouvoir une image d'un registre à l'autre sans la reconstruire ?
Section intitulée « Comment promouvoir une image d'un registre à l'autre sans la reconstruire ? »Il faut copier l'index de l'image tel quel, avec toutes ses plateformes. Un manifeste décrit une image pour une plateforme : ses couches et sa configuration. Un index est la liste des manifestes d'une image multi-plateforme, avec ses attestations, des métadonnées sur la construction de l'image. Il est identifié par un digest, son empreinte SHA-256.
Si la copie conserve l'index, l'image en production a le même digest que celle qui a passé les tests, et une vérification faite sur ce digest reste valable. Cette garantie suppose que la copie parte du bon index. Un tag comme 1.0 est mobile : si quelqu'un le repousse entre les tests et la promotion, la copie envoie une autre image que celle qui a été testée. Relevez donc le digest au moment des tests, avec docker buildx imagetools inspect <image> --format '{{.Manifest.Digest}}', et promouvez à partir de ce digest plutôt que du tag, comme le montre la section « Promotion par digest en CI/CD » de Comprendre OCI.
Une signature externe (par exemple celle de cosign) reste aussi valable pour ce digest, mais elle est stockée à part, comme un référent (en anglais referrer), un objet rattaché à l'image par son digest. Il faut donc le copier lui aussi, ou re-signer l'image : ce cas n'a pas été mesuré.
Une promotion réelle se fait avec deux registres authentifiés, en lecture sur la source et en écriture sur la cible. Les mesures ci-dessous utilisent des registres locaux sans identifiants : l'authentification n'a pas été mesurée.
Le schéma part d'un même point : un index de développement qui contient les variantes linux/amd64 et linux/arm64 et deux attestations. À gauche, les trois outils de copie reproduisent l'index à l'identique. À droite, l'enchaînement docker pull, docker tag, docker push aboutit à un manifeste unique, de digest différent.
Pour reproduire, travaillez dans un second dossier vide, ~/refcache/promo, pour ne pas écraser le Dockerfile du cache. Démarrez deux registres avec l'image registry:3.1.2 épinglée plus haut, publiés sur 127.0.0.1:5081 et 127.0.0.1:5082. Écrivez ensuite le Dockerfile de promotion, une base alpine et un fichier copié, puis publiez-le dans le premier registre pour deux plateformes :
mkdir -p ~/refcache/promo && cd ~/refcache/promoREG=registry:3.1.2@sha256:d4032d4cc323c1731c707931ecada07a53076eac38e3b61ae57533f170f2c6c3docker run -d --name reg5081 -p 127.0.0.1:5081:5000 $REGdocker run -d --name reg5082 -p 127.0.0.1:5082:5000 $REG
echo hi > hello.txtcat > Dockerfile <<'EOF'FROM alpine:3.24.3@sha256:be2656061b536c1883c4034790e21d0a09c5aaaf51968b89368a3c0371ea2c9aCOPY hello.txt /hello.txtEOF
docker buildx build --platform linux/amd64,linux/arm64 \ -t 127.0.0.1:5081/app:1.0 --push .Ce build multi-plateforme ne demande pas d'émulation QEMU, parce que le Dockerfile ne contient aucune instruction RUN : rien n'est exécuté pour arm64, seul un fichier est copié.
L'index publié contient quatre entrées : linux/amd64, linux/arm64 et deux attestations (unknown/unknown). Ces attestations changent à chaque build : le même Dockerfile construit plusieurs fois a donné des index de digests différents (07b8f23c…, d8a0b216…, 3b1eee7c… dans nos essais). Le digest de la mesure principale est sha256:07b8f23c637bdcb7679fdc30b5590e1e9d74e5a0b925b982aabd8220581dbc3f, et le vôtre sera différent.
Les trois commandes ci-dessous copient 127.0.0.1:5081/app:1.0 vers 127.0.0.1:5082/app:1.0 et conservent chacune le digest de l'index d'origine, quel qu'il soit. Elles partent du tag, comme dans la mesure. Dans un pipeline, la source s'écrit plutôt 127.0.0.1:5081/app@sha256:<digest relevé pendant les tests>, une forme que ces mesures n'ont pas rejouée.
Les options --src-tls-verify=false et --dest-tls-verify=false de Skopeo ne servent qu'à joindre les registres de test en HTTP. Retirez-les face à de vrais registres en HTTPS. Pour imagetools et crane, aucune option n'est nécessaire : ils joignent 127.0.0.1 en HTTP parce que la boucle locale est traitée comme non sécurisée, ce qui n'est pas le cas d'un nom de machine. Le guide Servir un registre de confiance, et s'y authentifier détaille ce point.
# Buildx : copie l'index et ses manifestesdocker buildx imagetools create \ --tag 127.0.0.1:5082/app:1.0 127.0.0.1:5081/app:1.0
# Skopeo 1.22.3 : --all copie toutes les plateformesSKO=quay.io/skopeo/stable:v1.22.3@sha256:2681eccb8b02c495b013c2669cbf7f41d5c0b0b0e644e7c69bd3ea9bcb20641fdocker run --rm --network host $SKO copy --all \ --src-tls-verify=false --dest-tls-verify=false \ docker://127.0.0.1:5081/app:1.0 docker://127.0.0.1:5082/app:1.0
# crane : copie l'indexCRA=gcr.io/go-containerregistry/crane:v0.22.1@sha256:1f968817b95790bed063f71175aa6b8ff879fa17064020415f3e18bb6e6a36e1docker run --rm --network host $CRA copy \ 127.0.0.1:5081/app:1.0 127.0.0.1:5082/app:1.0L'image de crane est épinglée par son tag et son digest d'index. L'encadré facultatif ci-dessous détaille les versions de crane testées.
Un runner sans Docker n'a pas besoin de ces images : il installe Skopeo par le paquet de sa distribution et crane par l'archive de ses releases, comme pour les autres outils de la chaîne, et lance la même commande. Ce chemin n'a pas été mesuré ici. Debian 13 propose Skopeo 1.18.0+ds1-1+b5 (mesuré le 2026-11-03 pour la leçon Exporter une image sans démon avec Skopeo) : cette version diffère de la 1.22.3 mesurée ici, et les sorties peuvent différer.
Pour contrôler le résultat, comparez les digests des deux côtés. Ce contrôle ne prouve que la fidélité de la copie : si le tag 1.0 a été repoussé entre les tests et la promotion, les deux côtés restent égaux alors que l'image n'est plus celle qui a été testée. Comparez donc le digest de production au digest relevé au moment des tests, par la même commande lancée à ce moment-là :
# au moment des tests : relever le digest de l'image testéedocker buildx imagetools inspect 127.0.0.1:5081/app:1.0 --format '{{.Manifest.Digest}}'# après la promotion : relever le digest reçu par la productiondocker buildx imagetools inspect 127.0.0.1:5082/app:1.0 --format '{{.Manifest.Digest}}'Les deux lignes doivent afficher le même digest : sha256:07b8f23c… dans notre mesure, un autre dans la vôtre. C'est ce qui est arrivé avec les trois outils : le digest d'index est identique. imagetools et Skopeo ont laissé dans le registre de production exactement les 13 blobs du registre de développement, et crane ces 13 plus deux. Un blob est un fichier stocké dans le registre, par exemple une couche ou une configuration. Les trois outils copient donc aussi les deux attestations de l'index.
L'écart vient de crane. Avec crane copy, le registre de production contient 15 blobs. Sur ce registre de test, qui n'offre pas d'API des référents, crane écrit en plus deux petits index rangés à des tags de repli de la forme sha256-<digest d'une variante>, que sa sortie annonce par updating fallback tag … with new referrer. Le digest de l'index ne change pas, mais le dépôt de production contient deux objets de plus qu'avec les autres outils. La copie d'une signature externe n'a pas été mesurée, avec aucun des trois outils.
Que se passe-t-il si on oublie --all, ou si on utilise docker pull puis push ?
Section intitulée « Que se passe-t-il si on oublie --all, ou si on utilise docker pull puis push ? »Dans les deux cas la commande réussit, et la production reçoit une image qui n'est plus celle qui a été testée. Le piège est discret : rien n'échoue.
Sans --all, skopeo copy ne garde que la plateforme de la machine qui exécute la commande. Dans la mesure, la production a reçu un manifeste unique de digest sha256:c7ca751a…, qui est la variante amd64, et non l'index sha256:07b8f23c…. Les digests c7ca751a… et b4810a9d… de cette section sont propres à ce build : vous obtiendrez d'autres valeurs, mais le même constat.
Le contre-exemple suivant est à éviter. Il a été joué après suppression des images locales, comme sur un runner neuf :
# ❌ à éviter : ne promeut pas l'image testéedocker pull 127.0.0.1:5081/app:1.0docker tag 127.0.0.1:5081/app:1.0 127.0.0.1:5082/app:1.0docker push 127.0.0.1:5082/app:1.01.0: digest: sha256:c7ca751ac09f7569bbf4ebfaa58739e8a77f050f402bacec0f6c2541489a24f6 size: 668
Info -> Not all multiplatform-content is present and only the available single-platform image was pushed sha256:07b8f23c637bdcb7679fdc30b5590e1e9d74e5a0b925b982aabd8220581dbc3f -> sha256:c7ca751ac09f7569bbf4ebfaa58739e8a77f050f402bacec0f6c2541489a24f6Le code de retour est 0. La seule trace de la perte est la ligne Info, qui donne l'ancien digest d'index puis le nouveau. La variante arm64 et les attestations ont disparu de la production, et le digest a changé : une signature ou une vérification faite sur sha256:07b8f23c… ne s'applique plus. Avec docker pull --platform linux/arm64, le même enchaînement a publié le manifeste arm64 seul, sha256:b4810a9d….
Un premier essai, fait sur la machine qui avait construit l'image, a donné le même digest d'index : son magasin local contenait encore toutes les plateformes. Ce résultat ne se transpose pas à un runner qui part de zéro.
Sur une image à plateforme unique, le même enchaînement a également conservé le digest dans la mesure, mais cette mesure a été faite sur la machine qui avait construit l'image, après suppression de la copie locale ; ne comptez pas dessus.
Ne promouvez pas par pull, tag et push, et comparez toujours les digests après la copie.
Comment choisir entre imagetools, skopeo et crane ?
Section intitulée « Comment choisir entre imagetools, skopeo et crane ? »Les trois conservent le digest d'index, donc le choix dépend de l'outil déjà présent dans votre pipeline et de ce que vous voulez en plus. Si vous construisez déjà avec Buildx, imagetools create ne demande rien de plus. Skopeo et crane n'ont pas besoin du démon Docker pour copier ; ici, ils tournent dans leur image, par commodité.
| Outil | Point à retenir |
|---|---|
docker buildx imagetools create | Déjà présent avec Buildx : aucune image ni installation en plus dans un pipeline qui construit avec Buildx. |
skopeo copy --all | Outil autonome, exécuté ici dans son image épinglée. L'option --all est indispensable : sans elle, une seule plateforme part. |
crane copy | Écrit en plus deux index de tags de repli (updating fallback tag … with new referrer) sur un registre sans API des référents. |
Aucun des trois n'a été mesuré sur la copie d'une signature externe. Les guides Skopeo et Crane détaillent chaque outil, et Skopeo a aussi une page pour exporter une image sans démon : Exporter une image sans démon avec Skopeo.
Comment nettoyer après les essais ?
Section intitulée « Comment nettoyer après les essais ? »Les essais laissent deux builders, trois registres, des images locales et du cache de build : retirez-les pour ne rien laisser tourner sur la machine. Les noms ci-dessous sont ceux utilisés plus haut.
docker buildx rm bk1 bk2 -fdocker rm -fv reg-cache reg5081 reg5082docker rmi app:t 127.0.0.1:5081/app:1.0 127.0.0.1:5082/app:1.0docker buildx prune -afrm -r ~/refcacheSi une commande répond No such image ou « builder introuvable », ce n'est pas grave : l'objet n'a pas été créé chez vous, il n'y a rien à retirer. docker rm -fv supprime aussi le volume anonyme de chaque registre. docker buildx prune -af vide tout le cache de build de la machine, pas seulement celui de ces essais : sautez cette ligne si d'autres projets en dépendent.
Les images téléchargées pour les essais (alpine, registry, moby/buildkit, Skopeo et crane) restent aussi dans le magasin local. Listez-les avec docker images et retirez avec docker rmi celles dont vous n'avez plus l'usage. Les dossiers de travail (app.c, les Dockerfile et hello.txt) sont partis avec rm -r ~/refcache. Vérifiez avec docker ps -a et docker buildx ls qu'il ne reste que le builder default.
À retenir
Section intitulée « À retenir »Les points ci-dessous résument les mesures de cette page, sur Docker 29.9.2 et Buildx 0.38.1.
- Le cache distant de BuildKit se partage par un registre avec
--cache-to type=registry,ref=…et--cache-from type=registry,ref=…. - Un builder
docker-containerne joint pas un registre sur127.0.0.1sans--driver-opt network=host, il échoue enconnection refused. Uncurl http://127.0.0.1:5080/v2/depuis la machine dit si le registre tourne. - Sur la mesure,
maxpèse 117,5 Mo contre 3,9 Mo pourminet ajoute environ 9 s à l'export. - Sans changement de code,
minetmaxdonnent le même résultat ; quand le code change,maxa repris l'étape de dépendances du registre (6,6 s) là oùminl'a rejouée (16,0 s). - Promouvoir une image, c'est copier son index :
imagetools create,skopeo copy --alletcrane copygardent le même digest. skopeo copysans--alletdocker pull,docker tag,docker pushréussissent, mais perdent des plateformes et changent le digest.- Comparez le digest de production au digest relevé au moment des tests, et promouvez à partir de ce digest : un tag mobile peut être repoussé entre les tests et la promotion, et la comparaison des deux registres ne le verrait pas.
Prochaines étapes
Section intitulée « Prochaines étapes »Les cartes ci-dessous prolongent cette page : la chaîne de CI qui publie l'image, les outils de copie, et le déploiement du même artefact d'un environnement à l'autre.