Buildx
đŹ Introduction
Buildx est la grande sĆur de la commande build. Elle en reprend les concepts tout en offrant des fonctionnalitĂ©s plus avancĂ©es et puissantes.
Elle est la commande CLI permettant dâutiliser les fonctionnalitĂ©s du nouveau moteur de construction : BuildKit. Les principales innovations proviennent de BuildKit, tandis que Buildx sert Ă les exposer.
De nombreuses fonctionnalités ont été apportées avec la création de BuildKit et Buildx :
- amélioration de la gestion du cache
- accélération des temps de build
- meilleure isolation
- prise en charge des secrets et des connexions SSH
- capacité de construire des images multi-architectures.
Profitez de cette partie pour découvrir plusieurs de ces nouveautés et ce que cela peut vous offrir par rapport à la commande build !
Evolution fréquentes
Buildx Ă©volue encore beaucoup ; si la commande vous intĂ©resse, nâhĂ©sitez pas Ă suivre lâactualitĂ© sur le site de Docker.
đ ContrĂŽle
Vérifiez que la commande est disponible sur votre poste :
Docker buildx est disponible
âčïž La version courante est la v0.30.1.
Docker compose n'est pas disponible
Besoin dâinstaller la commande ? La documentation relative Ă son installation est disponible iciâŻ: Install buildx
đ C'est parti
Documentation
NâhĂ©sitez pas Ă aller faire un tour sur la documentation : Documentation buildx
đŁ Mon premier builder / build
Buildx utilise des builders pour construire des images Docker. Un builder est une instance de BuildKit configurée pour réaliser les builds.
Celui fourni par dĂ©faut par Docker fonctionne pour des builds simples, mais ne prend pas en charge les fonctionnalitĂ©s avancĂ©es de Buildx, comme le multi-architecture, la gestion avancĂ©e du cache, les secrets ou le SBOM. Ce builder est donc davantage adaptĂ© Ă docker build quâĂ docker buildx.
Vous voulez voir ce qui se passe avec le builder par défaut ? Voici un exemple de build avec un Dockerfile que nous utiliserons un peu plus tard et qui contient du multiplateforme.
docker buildx build -f Dockerfile.multi.yml --platform linux/amd64,linux/arm64 -t localhost:5000/nginx-test:multi --push .
[+] Building 0.0s (0/0) docker:default
ERROR: failed to build: Multi-platform build is not supported for the docker driver.
Switch to a different driver, or turn on the containerd image store, and try again.
Learn more at https://docs.docker.com/go/build-multi-platform/
Maintenant, il est temps de crĂ©er notre propre builder. Buildx nĂ©cessite que le builder soit configurĂ© avec des informations prĂ©cises sur lâOS et lâarchitecture que nous allons utiliser.
Question
Depuis votre terminal, créer votre builder
- donnezâlui un nom
- on souhaite un builder de type docker-container
- ajouter l'option --driver-opt network=host pour la gestion d'un registry local
- lancez directement son exécution
Le build a été réalisé avec succÚs
[+] Building 170.5s (1/1) FINISHED
=> [internal] booting buildkit 170.5s
=> => pulling image moby/buildkit:buildx-stable-1 169.2s
=> => creating container buildx_buildkit_mybuilder0 1.4s
mybuilder
Vous pouvez vérifier que votre builder s'est bien ajouté à la liste.
La solution est lĂ ... —ïž
Il est lâheure de construire notre image pour la partie backend de notre application et de tester notre builder. SĂ©lectionner le builder que nous avons créé avec la commande.
Question
Placezâvous dans backend et rĂ©alisez le build du Dockerfile avec Buildx :
- construisez l'image, la nommer app-backend et la tagger buildx
- utilisez le Dockerfile présent
backend/Dockerfile
Vous pouvez exécuter la commande suivante pour visualiser le moteur utilisé pour la construction :
Le build est bien réalisé
[+] Building 1.5s (20/20) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 824B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3 1.0s
=> [internal] load metadata for docker.io/library/golang:1.25.0-alpine 1.1s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 132B 0.0s
=> [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfd 0.1s
=> => resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6 0.1s
=> [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2 0.1s
=> => resolve docker.io/library/alpine:3@sha256:4b7ce07002c69e8f3d704a9c5d6fd3053be500b7f1c69fc0d80990c2ad8dd412 0.1s
=> [internal] load build context 0.0s
=> => transferring context: 748B 0.0s
=> CACHED [stage-1 2/6] WORKDIR /app 0.0s
=> CACHED [stage-1 3/6] RUN apk --no-cache add ca-certificates 0.0s
=> CACHED [build 2/7] WORKDIR /app 0.0s
=> CACHED [build 3/7] COPY go.mod go.sum ./ 0.0s
=> CACHED [build 4/7] RUN go mod download 0.0s
=> CACHED [build 5/7] COPY . . 0.0s
=> CACHED [build 6/7] RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server 0.0s
=> CACHED [build 7/7] RUN mkdir -p /app/uploads 0.0s
=> CACHED [stage-1 4/6] COPY --from=build /app/server /app/ 0.0s
=> CACHED [stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.0s
=> CACHED [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.0s
On va maintenant regarder les images que nous avons Ă disposition en local.
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
moby/buildkit buildx-stable-1 de10faf919fc 6 weeks ago 333MB
Surprise, il n'y a pas notre image app-backend:buildxâŻ!
Par dĂ©faut, Buildx ne crĂ©e pas dâimage Docker locale. On peut cependant lui demander dâexporter lâimage vers Docker Engine avec lâoption --load.
REPOSITORY TAG IMAGE ID CREATED SIZE
app-backend buildx fdd8dd3fe59a 2 minutes ago 49.3MB
moby/buildkit buildx-stable-1 de10faf919fc 6 weeks ago 333MB
Dâaccord, mais pourquoi ce changement par rapport Ă build ?
Buildx et BuildKit portent un intĂ©rĂȘt plus important Ă l'approche CI/CD et GitOps. Lâobjectif est de disposer dâune source de vĂ©ritĂ© commune et de limiter les builds locaux et isolĂ©s, pour garantir des builds reproductibles.
Cette option a des limites et n'est pas compatible avec certaines autres fonctionnalités (multi-architecture, builder distant).
Builder et registry local
Pour quâil soit possible de push sur notre registry local, il est nĂ©cessaire que le builder que lâon utilise le permette. Câest Ă cela que lâoption --driver-opt network=host servait lors de la construction de notre builder.
Pour profiter pleinement de buildx, nous allons créer un registry !
Question
Lancer un conteneur avec un registry en local
- utiliser l'image
registry:2 - exposer sur le port
5000
Visualiser l'ID du conteneur Registry
La solution est lĂ ... —ïž
Comme on a fait pour charger l'image en local, on va maintenant utiliser l'autre option pour push l'image dans notre nouvelle registry locale
Pusher l'image dans le registry local
- tagger l'image avec l'adresse du registry local
localhost:5000/app-backend:buildx - utiliser l'option
--pushpour envoyer l'image vers le registry
L'image est bien poussée dans le registry
La solution est lĂ ... —ïž
đ·ïž MĂ©tadonnĂ©es
Avec Buildx, il est possible dâajouter et de gĂ©nĂ©rer des mĂ©tadonnĂ©es pour les images Docker, comme des fichiers SBOM ou des attestations de provenance. Ces informations permettent de tracer, auditer et sĂ©curiser les builds. Pour les mĂ©tadonnĂ©es, toutes les informations ne sont pas disponibles avec des builds en local (load).
đ Provenance
Documentation
NâhĂ©sitez pas Ă aller faire un tour sur la documentation : Documentation attestation
L'argument --attest type=provenance fait partie des fonctionnalités supplémentaires de Buildx.
Il fournit une attestation de provenance, qui contient le builder utilisé, la source (hash des fichiers copiés), les dépendances du build (Go modules, packages systÚme), etc.
Ces informations sont attachĂ©es au registry, mais Buildx peut aussi les exposer via le cache Docker, sans quâil y ait une image en local. Par exemple, si vous rĂ©alisez un build sans prĂ©ciser si vous voulez faire un push (distant) ou un load (local).
On peut donc récupérer des infos sans push/pull, mais pas toutes : le cache est exploitable localement pour certaines vérifications.
đ SBOM
Documentation
NâhĂ©sitez pas Ă aller faire un tour sur la documentation : Documentation SBOM
L'argument --attest=type=sbom permet, lui, de lister toutes les dépendances et composants utilisés dans l'image. Cela permet un inventaire automatisé des composants logiciels !
Les métadonnées avancées comme le SBOM ou les attestations de provenance sont attachées aux manifests dans le registry et ne sont pas directement lisibles avec les commandes Docker classiques. Pour y accéder, il faut soit générer le SBOM en local via Buildx, soit utiliser un outil comme Cosign pour récupérer et vérifier les attestations stockées dans le registry. Pour simplifier les choses, on va réaliser nos tests en local.
Question
Lancer le build de l'image Docker avec les arguments suivants :
- utiliser l'argument
**--attest type=provenance**en mode min et avec la version v1 - utiliser le Dockerfile de backend
- utiliser l'argument
--sbom=true
L'image build
[+] Building 17.3s (25/25) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 825B 0.0s
=> resolve image config for docker-image://docker.io/docker/buildkit-syft-scanner:stable-1 0.8s
=> [auth] docker/buildkit-syft-scanner:pull token for registry-1.docker.io 0.0s
=> [internal] load metadata for docker.io/library/alpine:3 0.3s
=> [internal] load metadata for docker.io/library/golang:1.25.0-alpine 0.5s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 132B 0.0s
=> docker-image://docker.io/docker/buildkit-syft-scanner:stable-1 0.2s
=> => resolve docker.io/docker/buildkit-syft-scanner:stable-1 0.2s
=> [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> => resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> => resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> [internal] load build context 0.3s
=> => transferring context: 484.40kB 0.3s
=> CACHED [build 2/7] WORKDIR /app 0.0s
=> CACHED [build 3/7] COPY go.mod go.sum ./ 0.0s
=> CACHED [build 4/7] RUN go mod download 0.0s
=> [build 5/7] COPY . . 1.1s
=> [build 6/7] RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server 13.5s
=> [build 7/7] RUN mkdir -p /app/uploads 0.2s
=> CACHED [stage-1 2/6] WORKDIR /app 0.0s
=> CACHED [stage-1 3/6] RUN apk --no-cache add ca-certificates 0.0s
=> CACHED [stage-1 4/6] COPY --from=build /app/server /app/ 0.0s
=> CACHED [stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.0s
=> CACHED [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.0s
=> CACHED [linux/amd64] generating sbom using docker.io/docker/buildkit-syft-scanner:stable-1 0.0s
=> exporting to client directory 0.6s
=> => copying files 32.87MB
La solution est lĂ ... —ïž
Il est temps de visualiser les métadonnées.
Pour le SBOM, on affiche le contenu du fichier sbom.spdx.json créé localement.
Exemple de SBOM
{
"_type": "https://in-toto.io/Statement/v0.1", # Type dâattestation in-toto, version 0.1, permet de tracer et de sĂ©curiser la chaĂźne dâapprovisionnement logicielle
"predicateType": "https://spdx.dev/Document", # Type du document attaché : ici un SBOM au format SPDX
"subject": [ # Liste des artefacts/fichiers contenus dans lâimage
{
"name": "app/server", # Chemin du fichier dans lâimage
"digest": {
"sha256": "033f5694e78ac79b0521d5c7f385369a3b9b16bf61ec0fed843e4dd46c035839" # Hash SHA256 du fichier pour vérifier son intégrité
}
},
{
"name": "bin/busybox",
"digest": {
"sha256": "f3547b3d78d08a028a4833ddb83b77cf012838c078bfd2b76355f53d1d8bba62"
}
},
{
"name": "etc/alpine-release",
"digest": {
"sha256": "6edb469729fc9d6c726e124e76ec6eb816493f0416605ce2c4d13fb38ae7417e"
}
},
{
"name": "etc/apk/arch",
"digest": {
"sha256": "aaf631698ae5160ceb04a97681a14887fdcab47cd6e0f163c87485b3b1340b62"
}
Pour la partie provenance, on va utiliser le cache de Docker :âŻ
Exemple de provenance
Name: localhost:5000/app-backend:buildx
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:c92fd2ae3abf5130648332498d74daea583e437a7cb7877d282a1ed882157b36
Manifests:
Name: localhost:5000/app-backend:buildx@sha256:e752a830f983c70286ff4402329ed69015050ec452522c27e401e9e0019199cf
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/amd64 # Plateforme ciblée par ce manifest
Name: localhost:5000/app-backend:buildx@sha256:f7ad49ffab5b595e1996b2e1b3e3219ccb8d84fd556380e4bc9bed34c8d4d92f
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations: # Métadonnées attachées au manifest
vnd.docker.reference.type: attestation-manifest # Indique que ce manifest est une attestation (provenance ou SBOM)
vnd.docker.reference.digest: sha256:e752a830f983c70286ff4402329ed69015050ec452522c27e401e9e0019199cf # Digest du contenu de lâattestation
En fonction de vos besoins, un usage local ou via un registre offre diffĂ©rentes possibilitĂ©s, avec plus ou moins de simplicitĂ© ou de capacitĂ©s dâanalyse.
đ Multi-architecture
Documentation
NâhĂ©sitez pas Ă aller faire un tour sur la documentation : Documentation Multi plateforme
Le multi-architecture vise à rendre les images Docker utilisables sur différentes architectures systÚme.
Avec la commande docker build classique, la gestion du multi-architecture Ă©tait complexe. Elle nĂ©cessitait de construire les images sur un environnement correspondant Ă lâarchitecture cible.
Par exemple, pour produire une image linux/arm64, le build devait ĂȘtre rĂ©alisĂ© sur un environnement linux/arm64. En clair, la construction pour une architecture diffĂ©rente de celle de lâhĂŽte nâĂ©tait pas supportĂ©e nativement.
Buildx propose plusieurs solutions. Il permet de construire des images pour plusieurs architectures en un seul build.
Auparavant, les images étaient dites single-plateforme. Elles contenaient un seul manifest, qui pointait vers une seule configuration et un seul ensemble de couches.
Buildx propose de changer cette vision. Les images multi-plateforme contiennent un manifest list, qui peut contenir plusieurs manifests, chacun correspondant à une architecture ou un OS différent. Chaque manifest pointe à son tour vers sa propre configuration et son propre ensemble de couches.
Le schéma de la documentation Docker représente trÚs bien ce changement :

Docker recommande de fournir au minimum des images pour les architectures linux/amd64 et linux/arm64. Lors du pull dâune image, Docker sĂ©lectionne automatiquement la version Ă tĂ©lĂ©charger en fonction de lâarchitecture que vous utilisez.
Pour indiquer les différentes architectures que l'on souhaite couvrir, on crée une liste à l'aide de la commande --platform. Vous pouvez aussi utiliser cette option lors d'un pull/run pour forcer la récupération d'une architecture particuliÚre.
Question
Réaliser un pull de l'image nginx avec comme base OS Linux et avec une architecture arm64.
- Utiliser
nginx:latestcomme image de base. - Suivre la nomenclature
/ . - Utiliser
--platformpour sélectionner l'architecture. - Vérifier les informations avec un
inspectsur l'image.
Visualiser l'architecture utilisée
[
{
"Id": "sha256:de437b5614ad7ef640175c1204414667adecd421752f7ddf3388edd063403a6e",
"RepoTags": [
"nginx:latest"
],
"RepoDigests": [
"nginx@sha256:fb01117203ff38c2f9af91db1a7409459182a37c87cced5cb442d1d8fcc66d19"
],
"Comment": "buildkit.dockerfile.v0",
"Created": "2025-12-09T22:50:18.400741057Z",
"Config": {
"ExposedPorts": {
"80/tcp": {}
},
"Env": [
"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"NGINX_VERSION=1.29.4",
"NJS_VERSION=0.9.4",
"NJS_RELEASE=1~trixie",
"PKG_RELEASE=1~trixie",
"DYNPKG_RELEASE=1~trixie"
],
"Entrypoint": [
"/docker-entrypoint.sh"
],
"Cmd": [
"nginx",
"-g",
"daemon off;"
],
"Labels": {
"maintainer": "NGINX Docker Maintainers <docker-maint@nginx.com>"
},
"StopSignal": "SIGQUIT"
},
"Architecture": "arm64", #arch
"Variant": "v8",
"Os": "linux", #OS
"Size": 172317468,
"GraphDriver": {
"Data": {
"LowerDir": "/var/lib/docker/overlay2/93a3e73e07ef2bf5feaf1d68742b6044186a2d2742ac10a985c5e182ca11ba77/diff:/var/lib/docker/overlay2/118c2cdb5db370acafc09ce720fe218e009f87f1e35e060dc6e772713e25146d/diff:/var/lib/docker/overlay2/4278585c2f5143248eae828e3cd399fb510a937a38bf02894a5f021cc76ee2db/diff:/var/lib/docker/overlay2/bc25746068e65c3d7c1e2646ea0d310e25bf4b40061fb114d3dcceb4c7c4a441/diff:/var/lib/docker/overlay2/f2dd9aaadd731ce991e6eb840982a10d3661a55be858f3410bd26116130464b4/diff:/var/lib/docker/overlay2/a1600e615321bcb963f9d411b4276a11e9e4a9b87d9f25b5bf91100211ef6881/diff",
"MergedDir": "/var/lib/docker/overlay2/2792481f5a29a0def5f68a0d2c735026637d8e082f0041a1c73044c1d2922a7a/merged",
"UpperDir": "/var/lib/docker/overlay2/2792481f5a29a0def5f68a0d2c735026637d8e082f0041a1c73044c1d2922a7a/diff",
"WorkDir": "/var/lib/docker/overlay2/2792481f5a29a0def5f68a0d2c735026637d8e082f0041a1c73044c1d2922a7a/work"
},
"Name": "overlay2"
},
"RootFS": {
"Type": "layers",
"Layers": [
"sha256:742b5304df6eda388fec80a0fc0a7a95d3e920e61c8d3b9dd32efb0fd8f4c3b7",
"sha256:894e925a9e6174d827393ab132a8a8b71d8f6d2b909bf424e72971a7b274a072",
"sha256:45c64a060d887b50118bf29249bd31e43d45da5d96fe425439eefa347aee10e8",
"sha256:b432142ba4b189d00a37c9d2a90f1cb167f30da37d6bf4929442950856050881",
"sha256:f09e81e666a662c79463ac4821318d4b3f9ba005dd7185047e3976458adb7e01",
"sha256:440f865dff31a72e6b7f6663f1aff1e32d8767c5912cc7c3851c4304d09ce2cb",
"sha256:968b8b0456d84792d2e1215a7a91dac84ad8e63375c6075679c64c45d13a0c3b"
]
},
"Metadata": {
"LastTagTime": "0001-01-01T00:00:00Z"
}
}
]
La solution est lĂ ... —ïž
Il existe trois méthodes pour créer des images disponibles pour différentes plateformes :
- QEMU : Ă©mule lâarchitecture cible, quelle que soit lâarchitecture locale.
- Plusieurs nĆuds natifs : rĂ©partit le build sur plusieurs machines, chacune exĂ©cutant son architecture native.
- Compilation croisĂ©e : lorsque le langage et lâoutil de build le permettent (comme Go ou Rust), il est possible de compiler des binaires pour une architecture cible depuis une machine source diffĂ©rente.
Pour la suite, je vous propose de nous appuyer sur la cross-compilation, notre application étant développée en Go.
On va débuter avec une image simple pour comprendre certains concepts, puis on passera sur l'image backend de l'application.
Docker met Ă notre disposition plusieurs variables pour nous aider Ă rendre nos Dockerfile plus flexibles :
- TARGETARCH: CPU cible
- TARGETPLATFORM: OS cible
- BUILDARCH: CPU d'origine
- BUILDPLATFORM: OS d'origine
Note
BUILDPLATFORM peut ĂȘtre utilisĂ© sous la forme --platform=$BUILDPLATFORM pour forcer le stage de build Ă sâexĂ©cuter sur lâarchitecture native et Ă©viter lâĂ©mulation.
Chacune de ces variables doit ĂȘtre dĂ©clarĂ©e dans l'image par le biais de la commande ARG. La construction multi-architecture nĂ©cessite d'utiliser un registry pour le push des images.
Question
Dans un nouveau Dockerfile, crĂ©er une image avec deux arguments, TARGETARCH et BUILDPLATFORM, qui vont nous permettre respectivement de connaĂźtre lâarchitecture CPU utilisĂ©e et la plateforme que lâon cible.
- utiliser
--platform=$BUILDPLATFORMetnginx:alpinecomme image de base - créer une commande CMD qui affiche la valeur de
BUILDPLATFORMetTARGETARCH - construire l'image pour
linux/amd64etlinux/arm64 - push l'image sur le registry local
Image build et push
[+] Building 1.9s (8/8) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 273B 0.0s
=> resolve image config for docker-image://docker.io/docker/dockerfile:1 0.4s
=> CACHED docker-image://docker.io/docker/dockerfile:1@sha256:b6afd42430b15f2d2a4c5a02b919e98a525b785b1aaff16747 0.0s
=> => resolve docker.io/docker/dockerfile:1@sha256:b6afd42430b15f2d2a4c5a02b919e98a525b785b1aaff16747d2f623364e3 0.0s
=> [linux/amd64 internal] load metadata for docker.io/library/nginx:alpine 0.2s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 2B 0.0s
=> [linux/amd64 1/2] FROM docker.io/library/nginx:alpine@sha256:8491795299c8e739b7fcc6285d531d9812ce2666e07bd3dd 0.0s
=> => resolve docker.io/library/nginx:alpine@sha256:8491795299c8e739b7fcc6285d531d9812ce2666e07bd3dd8db00020ad13 0.0s
=> CACHED [linux/amd64 2/2] RUN echo "Build exécuté sur : linux/amd64" && echo "Image construite pour : $TARG 0.0s
=> exporting to image 0.7s
=> => exporting layers 0.0s
=> => exporting manifest sha256:c67bee8b14b3bc2d1d4d56ec6e8af5d2a425f8fd91005b0b1245354b262b6f41 0.0s
=> => exporting config sha256:33871b51637a2427c58c2f6f9b474e06fb57771321aac4ed4b8b570d22c17964 0.0s
=> => exporting attestation manifest sha256:933a893740aa1b3098e53336a91d7f25fc62d2a87ca453031510a10ad9f7004c 0.1s
=> => exporting manifest sha256:e05be1717a1e9ce493ef6b33091bb72128a9a134ba320807ba9d526b35a8f7e0 0.0s
=> => exporting config sha256:9ef21216501d95b291223b11f50ebffa0e666edfb24151cffcf6f09478fa6efb 0.0s
=> => exporting attestation manifest sha256:fc56a0d2b82cc011d5db3fbfee51c97eef6fcb4a73a3ae0fa946dcef9456e477 0.1s
=> => exporting manifest list sha256:971a10b1fe13e47305ee8825db8bb1212a5e790fc1cd8c3d3bce4a5fbe147b37 0.0s
=> => pushing layers 0.2s
=> => pushing manifest for localhost:5000/nginx-test:multi@sha256:971a10b1fe13e47305ee8825db8bb1212a5e790fc1cd8c 0.1s
La solution est lĂ ... —ïž
# syntax=docker/dockerfile:1
# Définit la version de la syntaxe Dockerfile à utiliser.
FROM --platform=$BUILDPLATFORM nginx:alpine
ARG BUILDPLATFORM
ARG TARGETTARGETARCHPLATFORM
RUN echo "Build exécuté sur : $BUILDPLATFORM" \
&& echo "Image construite pour : $TARGETARCH" \
&& nginx -v
Question
Vérifier que le manifest de l'image dispose bien de: linux/amd64 et linux/arm64.
- Utiliser la commande
imagetools inspect
Visualiser le cache
Name: localhost:5000/nginx-test:multi
MediaType: application/vnd.oci.image.index.v1+json
Digest: sha256:2c99524bc93d71f3961175557dab5453583a8316606cc4ddc45300f3c50de2b7
Manifests:
Name: localhost:5000/nginx-test:multi@sha256:c6410e6eb22169edaf67dec59f6af204b97c4d2387e433f55602a3e7493de921
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/amd64
Name: localhost:5000/nginx-test:multi@sha256:a556a2b2a0633fa8d274699c27ba9ee2c0a6a8dec44241ef5b95a3c658966ca0
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: linux/arm64
Name: localhost:5000/nginx-test:multi@sha256:2f206addb988b50e4914e98586a9ac1e30efb6146d139609e8ef655711adc3f7
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.digest: sha256:c6410e6eb22169edaf67dec59f6af204b97c4d2387e433f55602a3e7493de921
vnd.docker.reference.type: attestation-manifest
Name: localhost:5000/nginx-test:multi@sha256:3ddaa3f904fa19ac4f69d3fc30e0abdde2184ade76675475e71cd20b0734f7b6
MediaType: application/vnd.oci.image.manifest.v1+json
Platform: unknown/unknown
Annotations:
vnd.docker.reference.digest: sha256:a556a2b2a0633fa8d274699c27ba9ee2c0a6a8dec44241ef5b95a3c658966ca0
vnd.docker.reference.type: attestation-manifest
La solution est lĂ ... —ïž
Pour la prochaine étape, nous allons reprendre notre image backend et la proposer pour deux architectures différentes : linux/amd64 et linux/arm64.
Question
Dans le fichier Dockerfile existant Ă la racine du projet backend:
* Reprenez --platform=$BUILDPLATFORM
* Modifier/Utiliser GOARCH et GOOS.
Build
[+] Building 28.1s (32/32) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 923B 0.0s
=> [linux/amd64 internal] load metadata for docker.io/library/golang:1.25.0-alpine 0.9s
=> [linux/amd64 internal] load metadata for docker.io/library/alpine:3 0.9s
=> [linux/arm64 internal] load metadata for docker.io/library/alpine:3 1.4s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 132B 0.0s
=> [internal] load build context 0.4s
=> => transferring context: 484.40kB 0.4s
=> [linux/amd64 stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> => resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> [linux/amd64 build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> => resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> [linux/arm64 stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 1.0s
=> => resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> => sha256:f6b4fb9446345fcad2db26eac181fef6c0a919c8a4fcccd3bea5deb7f6dff67e 4.20MB / 4.20MB 0.6s
=> => extracting sha256:f6b4fb9446345fcad2db26eac181fef6c0a919c8a4fcccd3bea5deb7f6dff67e 0.2s
=> CACHED [linux/amd64 build 2/7] WORKDIR /app 0.0s
=> CACHED [linux/amd64 build 3/7] COPY go.mod go.sum ./ 0.0s
=> [linux/amd64->arm64 build 4/7] RUN go mod download 3.9s
=> [linux/amd64 build 4/7] RUN go mod download 3.8s
=> [linux/arm64 stage-1 2/6] WORKDIR /app 0.1s
=> [linux/arm64 stage-1 3/6] RUN apk --no-cache add ca-certificates 3.2s
=> [linux/amd64 build 5/7] COPY . . 1.9s
=> [linux/amd64->arm64 build 5/7] COPY . . 1.8s
=> [linux/amd64 build 6/7] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server ./cmd/server 16.6s
=> [linux/amd64->arm64 build 6/7] RUN CGO_ENABLED=0 GOOS=linux GOARCH=arm64 go build -o server ./cmd/server 16.6s
=> [linux/amd64 build 7/7] RUN mkdir -p /app/uploads 0.4s
=> [linux/amd64->arm64 build 7/7] RUN mkdir -p /app/uploads 0.4s
=> [linux/arm64 stage-1 4/6] COPY --from=build /app/server /app/ 0.2s
=> CACHED [linux/amd64 stage-1 2/6] WORKDIR /app 0.0s
=> CACHED [linux/amd64 stage-1 3/6] RUN apk --no-cache add ca-certificates 0.0s
=> CACHED [linux/amd64 stage-1 4/6] COPY --from=build /app/server /app/ 0.0s
=> CACHED [linux/amd64 stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.0s
=> CACHED [linux/amd64 stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.0s
=> [linux/arm64 stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.1s
=> [linux/arm64 stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.3s
=> exporting to image 2.4s
=> => exporting layers 1.4s
=> => exporting manifest sha256:e752a830f983c70286ff4402329ed69015050ec452522c27e401e9e0019199cf 0.0s
=> => exporting config sha256:613ad69bdbb4448a697fb9ebb359f81dfc6cd478ae6632486c909db2fb15609a 0.0s
=> => exporting attestation manifest sha256:6e8383d142725374f44192f3bf56429a059d7499f476cf0873328b845814d606 0.2s
=> => exporting manifest sha256:790af95f1430560517beceb0fd9635e8e356f33f859a8310dd058d72d7ffc2c2 0.1s
=> => exporting config sha256:5b0908ba3e36725e3c92481c1d14fd51c0ed444b31b8a1776f666b2f490cfa87 0.1s
=> => exporting attestation manifest sha256:c9e4d2c0b5213bc4ab47723f34b98e79e3b5d7c07373bba9b6c345dd0f8eabc9 0.1s
=> => exporting manifest list sha256:22c701c3f83b0a917ea3827e17efa5de672677183cc736234ad5aa4b34b7f98d 0.0s
=> => pushing layers 0.3s
=> => pushing manifest for localhost:5000/nginx-test:multi@sha256:22c701c3f83b0a917ea3827e17efa5de672677183cc736234ad5aa4b34b7f98d 0.1s
La solution est lĂ ... —ïž
# Build stage
FROM --platform=$BUILDPLATFORM golang:1.25.0-alpine AS build
WORKDIR /app
# Arg
ARG TARGETOS
ARG TARGETARCH
# Copy go mod and sum files
COPY go.mod go.sum ./
# Download dependencies
RUN go mod download
# Copy the source code
COPY . .
# Build the application
RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -o server ./cmd/server
# Create uploads directory
RUN mkdir -p /app/uploads
# Runtime stage
FROM alpine:3
WORKDIR /app
# Install necessary runtime dependencies
# hadolint ignore=DL3018
RUN apk --no-cache add ca-certificates
# Copy the binary from the build stage
COPY --from=build /app/server /app/
COPY --from=build /app/uploads /app/uploads
# Ensure the uploads directory exists and is writable
RUN mkdir -p /app/uploads && \
chmod -R 755 /app/uploads
# Expose the port
EXPOSE 8080
# Run the server
CMD ["./server"]
đœ Cache avec Buildx : un ocĂ©an de possibilitĂ©s
Buildx vient chambouler les possibilitĂ©s offertes par le cache dans Docker. Dans cette partie, dĂ©couvrez comment il a fait Ă©voluer son architecture. Câest orientĂ© vers la CI/CD, avec entre autres, la prise en charge du cache distant.
Rappel sur le fonctionnement du cache avec la commande build
La gestion du cache est rĂ©alisĂ©e par couches et suit la structure du Dockerfile. La premiĂšre couche correspond au FROM, puis le Dockerfile est parcouru commande par commande jusquâĂ la fin du fichier.
Chaque instruction (CMD, COPY, RUN, etc) crĂ©e une couche qui est construite indĂ©pendamment et dispose de son propre cache. Lorsquâune modification est effectuĂ©e, le cache de la couche concernĂ©e doit ĂȘtre recréé, ainsi que celui de toutes les couches qui la suivent.
Avec Buildx, la gestion du cache est modifiĂ©e. Le Dockerfile nâest plus interprĂ©tĂ© de maniĂšre strictement linĂ©aire, mais converti en un graphe dâopĂ©rations. BuildKit permet de parallĂ©liser les exĂ©cutions. Le cache reste sensible Ă lâordre des instructionsâŻ: modifier lâordre dâune section modifie le graphe et invalide le cache de lâopĂ©ration ainsi que celui des suivantes.
En ce qui concerne la granularitĂ© du cache, elle est beaucoup plus fine quâavec le build classique. Buildx permet lâutilisation de solutions de cache externes. Dans le cas dâun fichier requirements.txt, apporter une modification (ajout ou suppression de librairies) peut invalider lâĂ©tape de construction. Cette dĂ©cision ne dĂ©pend plus uniquement de Docker, mais Ă©galement de pip.
GrĂące au cache de pip et aux wheels, lâinstallation devient plus efficace :
â si une dĂ©pendance existante est modifiĂ©e, pip rĂ©utilise les wheels dĂ©jĂ construits et reconstruit uniquement les parties concernĂ©es ; â si une dĂ©pendance est ajoutĂ©e, seule son installation est effectuĂ©e, sans refaire lâintĂ©gralitĂ© de lâinstallation.
Auparavant, Docker travaillait seul et, en cas de modification, ne conservait rien de lâexistant. LâintĂ©gration du cache pip + wheels permet donc de gagner du temps et des ressources, tout en conservant les dĂ©pendances dĂ©jĂ installĂ©es.
De notre cĂŽtĂ©, notre application est en Go, mais on va pouvoir utiliser le mĂȘme concept : jouer avec le cache, rĂ©aliser un premier build, ajouter une librairie dans le fichier go.mod et voir comment se comporte le cache.
Nettoyage
Pour bien voir la gestion du cache, on va nettoyer le cache existant, ce qui nous permet de parler de la commande prune qui permet de faire cela.
Ici, on nettoie "brutalement" le cache, mais la commande prune permet de faire du nettoyage intelligent. Pour cela, vous pouvez vous référencer à la documentation official de prune
Question
- réaliser un premier build de l'image
backendet observer les temps des étapes - ajouter
github.com/fatih/color v1.16.0dans le fichiergo.mod - rebuild l'image et observer le comportement du cache et les temps des étapes
âčïž Utiliser le paramĂštre --progress=plain pour avoir un affichage plus lisible.
Premier build, aprĂšs nettoyage
#0 building with "mybuilder" instance using docker-container driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 909B done
#1 DONE 0.0s
#2 [internal] load metadata for docker.io/library/golang:1.25.0-alpine
#2 DONE 0.9s
#3 [internal] load metadata for docker.io/library/alpine:3
#3 DONE 0.9s
#4 [internal] load .dockerignore
#4 transferring context: 132B done
#4 DONE 0.0s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.0s done
#5 DONE 0.1s
#6 [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
#6 resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.0s done
#6 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0B / 3.86MB 0.2s
#6 sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 3.86MB / 3.86MB 0.3s done
#6 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612
#6 extracting sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.4s done
#6 DONE 0.8s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 32B / 32B 0.3s done
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 11.53MB / 60.05MB 0.8s
#5 sha256:18414ed0f6669fd1d6e137922f2a57e37aaf0a63ae6968c499fe69b17d148d14 124B / 124B 0.4s done
#5 sha256:ec7d4ca09441bdb9129d5708d2aa8802e233b2d11d1797317158c4095e9df8fc 282.44kB / 282.44kB 0.3s done
#5 sha256:9824c27679d3b27c5e1cb00a73adb6f4f8d556994111c12db3c5d61a0c843df8 3.80MB / 3.80MB 0.4s done
#5 ...
#7 [stage-1 2/6] WORKDIR /app
#7 DONE 0.1s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 17.83MB / 60.05MB 0.9s
#5 extracting sha256:9824c27679d3b27c5e1cb00a73adb6f4f8d556994111c12db3c5d61a0c843df8
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 28.31MB / 60.05MB 1.1s
#5 ...
#8 [internal] load build context
#8 transferring context: 32.91MB 1.1s done
#8 DONE 1.2s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 extracting sha256:9824c27679d3b27c5e1cb00a73adb6f4f8d556994111c12db3c5d61a0c843df8 0.3s done
#5 extracting sha256:ec7d4ca09441bdb9129d5708d2aa8802e233b2d11d1797317158c4095e9df8fc 0.1s done
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 40.89MB / 60.05MB 1.4s
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 49.28MB / 60.05MB 1.5s
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 58.72MB / 60.05MB 1.7s
#5 sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 60.05MB / 60.05MB 1.7s done
#5 extracting sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2
#5 ...
#9 [stage-1 3/6] RUN apk --no-cache add ca-certificates
#9 0.984 (1/1) Installing ca-certificates (20251003-r0)
#9 1.029 Executing busybox-1.37.0-r30.trigger
#9 1.038 Executing ca-certificates-20251003-r0.trigger
#9 1.132 OK: 8473 KiB in 17 packages
#9 DONE 1.2s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 extracting sha256:8286cb4ece30afb97c398c2b5ac1f35e8f502f758d4ea2fc69e179efdf471ea2 5.5s done
#5 DONE 7.3s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 extracting sha256:18414ed0f6669fd1d6e137922f2a57e37aaf0a63ae6968c499fe69b17d148d14 done
#5 extracting sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 done
#5 DONE 7.3s
#10 [build 2/7] WORKDIR /app
#10 DONE 0.4s
#11 [build 3/7] COPY go.mod go.sum ./
#11 DONE 0.0s
#12 [build 4/7] RUN go mod download
#12 DONE 7.3s
#13 [build 5/7] COPY . .
#13 DONE 0.2s
#14 [build 6/7] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server ./cmd/server
#14 DONE 23.7s
#15 [build 7/7] RUN mkdir -p /app/uploads
#15 DONE 0.1s
#16 [stage-1 4/6] COPY --from=build /app/server /app/
#16 DONE 0.1s
#17 [stage-1 5/6] COPY --from=build /app/uploads /app/uploads
#17 DONE 0.0s
#18 [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads
#18 DONE 0.1s
Second build avec l'ajout de la dépendance go
On voit bien que seules les étapes impactées par le changement du fichier go.mod sont exécutées, les autres sont extraites du cache
#0 building with "mybuilder" instance using docker-container driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 909B done
#1 DONE 0.0s
#2 [internal] load metadata for docker.io/library/alpine:3
#2 ...
#3 [internal] load metadata for docker.io/library/golang:1.25.0-alpine
#3 DONE 0.3s
#2 [internal] load metadata for docker.io/library/alpine:3
#2 DONE 0.3s
#4 [internal] load .dockerignore
#4 transferring context: 132B done
#4 DONE 0.0s
#5 [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440
#5 resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.0s done
#5 DONE 0.0s
#6 [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62
#6 resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.0s done
#6 DONE 0.0s
#7 [internal] load build context
#7 transferring context: 78.13kB 0.1s done
#7 DONE 0.1s
#8 [build 2/7] WORKDIR /app
#8 CACHED
#9 [build 3/7] COPY go.mod go.sum ./
#9 DONE 0.0s
#10 [build 4/7] RUN go mod download
#10 DONE 7.9s
#11 [build 5/7] COPY . .
#11 DONE 0.3s
#12 [build 6/7] RUN CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -o server ./cmd/server
#12 DONE 23.5s
#13 [build 7/7] RUN mkdir -p /app/uploads
#13 DONE 0.1s
#14 [stage-1 5/6] COPY --from=build /app/uploads /app/uploads
#14 CACHED
#15 [stage-1 2/6] WORKDIR /app
#15 CACHED
#16 [stage-1 3/6] RUN apk --no-cache add ca-certificates
#16 CACHED
#17 [stage-1 4/6] COPY --from=build /app/server /app/
#17 CACHED
#18 [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads
#18 CACHED
La solution est lĂ ... —ïž
âȘïž Proposition orientĂ© CI/CD, gestion du cache distant
CĂŽtĂ© CI/CD, les runners sont souvent Ă©phĂ©mĂšres et, Ă chaque pipeline, lâenvironnement de build repart de zĂ©ro.
Pour compenser cette problématique, on comptait souvent sur des outils externes. Certains registries proposent des options qui permettent de réutiliser des layers déjà existants (Harbor par exemple).
Il est maintenant possible de le faire nativement avec Buildx ! La réutilisation du cache entre pipelines permet de réduire le temps de build et de limiter la charge sur les ressources. Cette fonctionnalité, couplée à la nouvelle construction du cache, permet une réelle maximisation de l'usage du cache.
Buildx permet dâexporter et dâimporter le cache vers des backends externes (registry, stockage local...). On va pouvoir poursuivre nos expĂ©rimentations avec notre registry.
Question
Pousser le cache de notre image sur notre registry locale.
- Réaliser un premier build de l'image backend
- Ajouter
--cache-toĂ la commande pour donner la cible du cache
Visualiser le cache
[+] Building 1.6s (22/22) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 824B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3 0.7s
=> [internal] load metadata for docker.io/library/golang:1.25.0-alpine 0.7s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 132B 0.0s
=> [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> => resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> [internal] load build context 0.2s
=> => transferring context: 114.06kB 0.1s
=> [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> => resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> CACHED [stage-1 2/6] WORKDIR /app 0.0s
=> CACHED [stage-1 3/6] RUN apk --no-cache add ca-certificates 0.0s
=> CACHED [build 2/7] WORKDIR /app 0.0s
=> CACHED [build 3/7] COPY go.mod go.sum ./ 0.0s
=> CACHED [build 4/7] RUN go mod download 0.0s
=> CACHED [build 5/7] COPY . . 0.0s
=> CACHED [build 6/7] RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server 0.0s
=> CACHED [build 7/7] RUN mkdir -p /app/uploads 0.0s
=> CACHED [stage-1 4/6] COPY --from=build /app/server /app/ 0.0s
=> CACHED [stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.0s
=> CACHED [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.0s
=> exporting to image 0.3s
=> => exporting layers 0.0s
=> => exporting manifest sha256:e752a830f983c70286ff4402329ed69015050ec452522c27e401e9e0019199cf 0.0s
=> => exporting config sha256:613ad69bdbb4448a697fb9ebb359f81dfc6cd478ae6632486c909db2fb15609a 0.0s
=> => exporting attestation manifest sha256:e123012b93b0a5e44fa9ed75e410b78b4b4d2cfa02bb81c4101a420469f06076 0.1s
=> => exporting manifest list sha256:6aa6ff0937b9f27f95f56f6d5155a36e72431f99f4007badd9a30fc30b4e7454 0.0s
=> => pushing layers 0.1s
=> => pushing manifest for localhost:5000/app-backend:bluidx@sha256:6aa6ff0937b9f27f95f56f6d5155a36e72431f99f4007badd9a30fc30b4e7454 0.0s
=> exporting cache to registry 0.1s
=> => preparing build cache for export 0.1s
=> => writing layer sha256:1074353eec0db2c1d81d5af2671e56e00cf5738486f5762609ea33d606f88612 0.0s
=> => writing layer sha256:229720617a9e81a0cb80f2fff21b68366fcc9a864a86ec5a7a16521db28e4abf 0.0s
=> => writing layer sha256:4f4fb700ef54461cfa02571ae0db9a0dc1e0cdb5577484a6d75e68dc38e8acc1 0.0s
=> => writing layer sha256:6eb7a6e2535de9885952c82c4559f483aa8b578c65b4a6022181970afbb8cbf2 0.0s
=> => writing layer sha256:b7482504c00153cf21c9b3ab8563cff5b589a4e06eb2ac726dc48e1b478d9323 0.0s
=> => writing layer sha256:ba7a13890897cdddcda58502146b448a8424891a5d43f5dbf2fbf6011949a823 0.0s
=> => writing config sha256:16972018a7f1f30bd95dbd55619fda102d79497d8af043eb21e4b78b8c4caf2c 0.0s
=> => writing cache image manifest sha256:e0da55c5c966e05afd950162a7e7dd4f5e6ba4f8658be43a3cd80c0642980675 0.0s
La solution est lĂ ... —ïž
Si vous souhaitez conserver le cache avec votre image, il est possible dâutiliser un build inline. Cette approche consiste Ă intĂ©grer les mĂ©tadonnĂ©es du cache directement dans lâimage Docker lors du build, ce qui permet de le rĂ©utiliser lors des builds suivants sans dĂ©pendre dâun cache externe. Elle est particuliĂšrement adaptĂ©e aux rebuilds rĂ©guliers.
Question
Pousser le cache de notre image, dans notre image.
- Ajouter
--cache-to=type=inlineĂ la commande - Tagger l'image avec
inline
Visualiser le cache
[+] Building 1.7s (22/22) FINISHED docker-container:mybuilder
=> [internal] load build definition from Dockerfile 0.0s
=> => transferring dockerfile: 824B 0.0s
=> [internal] load metadata for docker.io/library/alpine:3 0.9s
=> [internal] load metadata for docker.io/library/golang:1.25.0-alpine 0.9s
=> [auth] library/alpine:pull token for registry-1.docker.io 0.0s
=> [auth] library/golang:pull token for registry-1.docker.io 0.0s
=> [internal] load .dockerignore 0.0s
=> => transferring context: 132B 0.0s
=> [build 1/7] FROM docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> => resolve docker.io/library/golang:1.25.0-alpine@sha256:f18a072054848d87a8077455f0ac8a25886f2397f88bfdd222d6fafbb5bba440 0.1s
=> [stage-1 1/6] FROM docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> => resolve docker.io/library/alpine:3@sha256:865b95f46d98cf867a156fe4a135ad3fe50d2056aa3f25ed31662dff6da4eb62 0.1s
=> [internal] load build context 0.3s
=> => transferring context: 114.06kB 0.2s
=> CACHED [stage-1 2/6] WORKDIR /app 0.0s
=> CACHED [stage-1 3/6] RUN apk --no-cache add ca-certificates 0.0s
=> CACHED [build 2/7] WORKDIR /app 0.0s
=> CACHED [build 3/7] COPY go.mod go.sum ./ 0.0s
=> CACHED [build 4/7] RUN go mod download 0.0s
=> CACHED [build 5/7] COPY . . 0.0s
=> CACHED [build 6/7] RUN CGO_ENABLED=0 GOOS=linux go build -o server ./cmd/server 0.0s
=> CACHED [build 7/7] RUN mkdir -p /app/uploads 0.0s
=> CACHED [stage-1 4/6] COPY --from=build /app/server /app/ 0.0s
=> CACHED [stage-1 5/6] COPY --from=build /app/uploads /app/uploads 0.0s
=> CACHED [stage-1 6/6] RUN mkdir -p /app/uploads && chmod -R 755 /app/uploads 0.0s
=> exporting to docker image format 0.2s
=> => exporting layers 0.0s
=> => preparing layers for inline cache 0.0s
=> => exporting manifest sha256:e7cb215da9ffbc906326b27ba1c75e47e3fd555ca669572c28d1d5a9e2a5615e 0.0s
=> => exporting config sha256:4ed367a543f77877860c93a81479f0a326f3c2c0c87d58613e664c749df56957 0.0s
=> => sending tarball 0.1s
=> importing to docker
La solution est lĂ ... —ïž
â Comparaison Build / buildx et quand favoriser build
Buildx apporte de nombreuses nouvelles fonctionnalitĂ©s qui rĂ©duisent le besoin dâoutils externes. Câest une Ă©volution majeure de Docker, qui permet de rĂ©pondre Ă des besoins actuels : utilisation de la CI/CD et orientation vers des pratiques GitOps.
Buildx peut ĂȘtre plus complexe Ă prendre en main si vous nâĂȘtes pas encore Ă lâaise avec les concepts fondamentaux de Docker. Pour des projets simples, sans CI avancĂ©e ni besoin de multi-architecture, la commande docker build reste une solution fiable et suffisante.
DĂšs que lâon vise des builds reproductibles et industrialisĂ©s, Buildx devient incontournable.