Build d'images multi-plateformes avec Buildkit
Voici une feature de Docker builtx des plus sympathiques. On peut en une seule commande lancer la construction d’images Docker à destination de plusieurs architectures comme les raspberry p1 et même les instances AWS A1.
Pour rappel buildkit est le nouveau moteur de construction d’images intégrant pas mal de nouvelles fonctionnalités.
Et celle-ci vaut le détour. Surtout si vous utilisez plusieurs
architectures, linux/amd64
, linux/arm64
, ou darwin/amd64
, … au sein de votre
infrastructure.
Mise en place du builder
Le générateur est en fait une image, utilisant les fonctionnalités QEMU, qui tourne au sein d’une instance Docker. Une feature que l’on retrouve sur la version de Docker Desktop d’ailleurs mais caché.
Faisons le test, bien sûr dans une machine vagrant. En premier, il faut lancer une image permettant d’installer l’outillage nécessaire sur la machine hôte.
docker run --privileged --rm tonistiigi/binfmt --install all
Unable to find image 'tonistiigi/binfmt:latest' locallylatest: Pulling from tonistiigi/binfmt981e1f26977e: Pull complete6269e8ad230e: Pull completeDigest: sha256:11128304bc582dc7dbaa35947ff3e52e2610d23cecb410ddfa381a6ce74fa763Status: Downloaded newer image for tonistiigi/binfmt:latestinstalling: arm64 OKinstalling: mips64 OKinstalling: mips64le OKinstalling: arm OKinstalling: s390x OKinstalling: ppc64le OKinstalling: riscv64 OK{ "supported": [ "linux/amd64", "linux/arm64", "linux/riscv64", "linux/ppc64le", "linux/s390x", "linux/386", "linux/arm/v7", "linux/arm/v6" ], "emulators": [ "qemu-aarch64", "qemu-arm", "qemu-mips64", "qemu-mips64el", "qemu-ppc64le", "qemu-riscv64", "qemu-s390x" ]}
La messe est dite en sortie, on pourra avoir des builds à destination de toutes ces archis.
Ensuite vient la création du builder. Pour utiliser une registry perso, il faudra
utiliser un fichier de config. Plus d’infos
ici ↗ Pour
appeler ce fichier, il faudra ajouter --config=/path/to/config.toml
Impact : Je n’utiliserai donc pas l’option --push
car pour le moment je
n’ai pas réussi à le faire tourner en local. L’option --load
n’accepte pas
pour le moment de lancer plusieurs builds en //.
docker buildx create --driver-opt network=host --driver docker-container --name mybuilder --usemybuilderdocker buildx inspect --bootstrap[+] Building 78.2s (1/1) FINISHED => [internal] booting buildkit 78.2s => => pulling image moby/buildkit:buildx-stable-1 77.6s => => creating container buildx_buildkit_mybuilder0 0.6sName: mybuilderDriver: docker-container
Nodes:Name: mybuilder0Endpoint: unix:///var/run/docker.sockStatus: runningPlatforms: linux/amd64, linux/arm64, linux/riscv64, linux/ppc64le, linux/s390x, linux/386, linux/mips64le, linux/mips64, linux/arm/v7, linux/arm/v6
Nous allons utiliser une image plutôt simple :
FROM --platform=$BUILDPLATFORM golang:alpine AS build ARG TARGETPLATFORM ARG BUILDPLATFORM RUN echo "Je cours sur $BUILDPLATFORM, je construis pour $TARGETPLATFORM" > /log FROM alpine COPY --from=build /log /log
Allez, on lance le build (ca va prendre un peu de temps la première fois):
docker buildx build --platform linux/arm64 -t localhost:5000/test-arm64 --load .
[+] Building 0.6s (10/10) FINISHED => [internal] load build definition from Dockerfile 0.1s => => transferring dockerfile: 315B 0.0s => [internal] load .dockerignore 0.1s => => transferring context: 2B 0.0s => [internal] load metadata for docker.io/library/alpine:latest 0.3s => [internal] load metadata for docker.io/library/golang:alpine 0.3s => [build 1/2] FROM docker.io/library/golang:alpine@sha256:5519c8752f6b53fc8818dc46e9fda628c99c4e8fd2d2f1df71e1f184e71f47dc 0.0s => => resolve docker.io/library/golang:alpine@sha256:5519c8752f6b53fc8818dc46e9fda628c99c4e8fd2d2f1df71e1f184e71f47dc 0.0s => [stage-1 1/2] FROM docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a 0.1s => => resolve docker.io/library/alpine@sha256:e1c082e3d3c45cccac829840a25941e679c25d438cc8412c2fa221cf1a824e6a 0.0s => CACHED [build 2/2] RUN echo "Je cours sur linux/amd64, je construis pour linux/arm64" > /log 0.0s => CACHED [stage-1 2/2] COPY --from=build /log /log 0.0s => exporting to oci image format 0.2s => => exporting layers 0.0s => => exporting manifest sha256:17e7bcf7fcb6895660bb46c5c6a5b520eadec6406c07b4b2bf310942d6485e0d 0.0s => => exporting config sha256:0a8db5b1ffe94f49fe3be55c3d12b68c96f3fd0deda6bedfa034ecc4d7763ba4 0.0s => => sending tarball 0.1s => importing to docker 0.0s
On lance une deuxième plateforme :
docker buildx build --platform linux/amd64 -t localhost:5000/test-amd64 --load .
=> => exporting config sha256:8216a415ef7aa768684334e16ef91fda415f56d15cfd0277306d31b8d4e71d4a 0.0s => => sending tarball 0.2s => importing to docker
Allez, on vérifie :
docker images
REPOSITORY TAG IMAGE ID CREATED SIZElocalhost:5000/test-amd64 latest 8216a415ef7a 34 seconds ago 5.59MBlocalhost:5000/test-arm64 latest 0a8db5b1ffe9 7 minutes ago 5.33MB
Si vous avez une registry, vous pouvez utiliser l’option --push
avec plusieurs
plateformes dans la même ligne de commande. Pour les autres un simple script fera
l’affaire.
Pour améliorer les perfs on peut ajouter plusieurs nœuds à votre builder
avec la fonction --append
.
Franchement ça déchire.
Sources :