Aller au contenu principal

Build d'images muh avec Buildkit

· 4 minutes de lecture
Stéphane ROBERT

logo docker

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 instance 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 sur dans une machine vagrant. En premier il faut lancer une image permettant d'installer l'outillage nécessaire sur la machine hote.


docker run --privileged --rm tonistiigi/binfmt --install all

Unable to find image 'tonistiigi/binfmt:latest' locally
latest: Pulling from tonistiigi/binfmt
981e1f26977e: Pull complete
6269e8ad230e: Pull complete
Digest: sha256:11128304bc582dc7dbaa35947ff3e52e2610d23cecb410ddfa381a6ce74fa763
Status: Downloaded newer image for tonistiigi/binfmt:latest
installing: arm64 OK
installing: mips64 OK
installing: mips64le OK
installing: arm OK
installing: s390x OK
installing: ppc64le OK
installing: 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 reussi à le faire tourner en local. L'option --load n'accepte pas pour le moment de lancer plusieurs build en //.

docker buildx create --driver-opt network=host --driver docker-container --name mybuilder --use
mybuilder
docker 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.6s
Name: mybuilder
Driver: docker-container

Nodes:
Name: mybuilder0
Endpoint: unix:///var/run/docker.sock
Status: running
Platforms: 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 :

# syntax=docker/dockerfile:1.3
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 SIZE
localhost:5000/test-amd64 latest 8216a415ef7a 34 seconds ago 5.59MB
localhost:5000/test-arm64 latest 0a8db5b1ffe9 7 minutes ago 5.33MB

Si vous avez une registry, vous pouvez utiliser l'option --push avec plusieurs platefomrs dans la meme ligne de commande. Pour les autres un simple script fera l'affaire.

Pour améliorer les perfs on peut ajouter plusieurs noeuds à votre builder avec l fonction --append.

Franchement ca déchire.

Sources: