Skip to content

Publier automatiquement des images multi-arch sur le DockerHub

Pour l’un de mes side projects (une petite webapp), je suis arrivĂ© Ă  l’étape oĂč je devais construire mon image Docker pour embarquer l’application. L’objectif Ă©tait de la rendre publique pour que n’importe qui puisse l’utiliser facilement.

PlutĂŽt que de la builder uniquement pour l’architecture AMD, je me suis dit : « Pourquoi ne pas la rendre aussi compatible ARM ?”, comme ça pas de jaloux, tout le monde pourra l’utiliser, mĂȘme ceux sous Mac M1/M2
 😛

Je me suis donc penché sur la question du build multi-platform.

Comprendre le build multi-platform

Avant d’aller plus loin, revenons plus en dĂ©tail sur le fonctionnement d’un build multi-platform. 

Depuis quelques annĂ©es maintenant, on voit de plus en plus de machines tourner sous ARM que ce soit des Raspberry, des Macs M1/M2/M3/M4 ou des instances AWS Graviton. Mais en parallĂšle, la majoritĂ© des PC et serveurs tournent encore sur de l’AMD64.

Ce sont deux architectures CPU diffĂ©rentes. Je ne vais pas vous faire un cours d’architecture processeur, je suis incapable de vous l’expliquer correctement mdr. Mais retenez juste que ce n’est pas du tout la mĂȘme chose đŸ€·â€â™‚ïž.

Sinon, voici la réponse de ChatGPT

ARM : utilise une architecture appelĂ©e RISC (Reduced Instruction Set Computing).
→ C’est une architecture plus simple, optimisĂ©e pour consommer peu d’énergie.
→ TrĂšs utilisĂ©e dans les smartphones, tablettes, objets connectĂ©s, et maintenant certains PC (comme les Mac M1/M2/M3).

AMD : fabrique des processeurs avec l’architecture x86 (ou x86-64, plus prĂ©cisĂ©ment).
→ Plus complexe, mais puissante, adaptĂ©e aux PC, consoles de jeux, et serveurs.

Et plus les plus curieux je vous laisserai creuser le sujet 😂

Cela Ă©tant dit, si vous avez dĂ©jĂ  un peu jouĂ© avec Docker, vous voyez peut-ĂȘtre venir le problĂšme. 😏

Docker partage le kernel de l’hĂŽte. Du coup, si vous construisez une image pour AMD64, vous ne pouvez pas la faire tourner directement sur une machine ARM. Sauf passer par de l’émulation mais c’est pas ouf.

C’est là que le build multi-platform entre en scùne. 💃

L’idĂ©e c’est de packager plusieurs versions de votre application dans une seule image Docker. En gros, 1 version = 1 arch CPU.

Doooooonc, quand un utilisateur exĂ©cute docker pull depuis sa machine, le client Docker choisit automatiquement la bonne version de l’image en fonction de son architecture (ARM ou AMD). Et ça, c’est franchement top parce-que l’on a plus besoin de maintenir deux images (ou plus), ni de forcer les gens Ă  savoir laquelle tĂ©lĂ©charger.

Ok, donc on peut avoir plusieurs images dans une seule image ? Comment c’est possible ton truc ? đŸ€”

Une image Docker « classique » contient un seul manifest qui lui mĂȘme contient son fichier de config + son jeu de layers (les instructions du Dockerfile).

Dans le cas d’une image multi-platform, elle contient un index, qui pointe vers plusieurs manifests. Chaque manifest est spĂ©cifique Ă  une architecture (ARM64, AMD64, etc.).

C’est cette structure qui permet à Docker de faire le tri automatiquement et de tirer la bonne version selon la machine de l’utilisateur.

Si on schématise, ça donne ça :

Fonctionnement des index

Si vous voulez comprendre un peu plus le fonctionnement des index je vous laisse avec la doc de docker qui est tipetop.

Et si on automatisait tout ça ?

Je n’aime pas trop trop me rĂ©pĂ©ter alors j’ai poussĂ© le truc un peu plus loin. Je me suis demandĂ© si je ne pouvais pas automatiser le build multi platform de ma petite appli avec GitLab CI (vu que j’hĂ©berge dĂ©jĂ  le code sur cette plateforme). En fouillant un peu, je suis tombĂ© sur cet article .

Franchement, niquel, ça montre qu’il est possible de faire des build multi-plateform avec GitLab CI et l’exemple de l’article fonctionne trĂšs bien ! Mais comme souvent avec les exemples “de base” tout est codĂ© en dur (les plateformes sur lesquelles on veut build, la registry dans laquelle on veut push
). Du coup, j’ai dĂ©cidĂ© de prendre cet exemple comme point de dĂ©part et de le rendre plus souple et plus rĂ©utilisable. Pour ça, j’ai variabilisĂ© au max (plateformes, tag, registry, creds) pour pouvoir intĂ©grer ce job dans n’importe quel projet. Je ne veux pas avoir Ă  toucher au script Ă  chaque build ou du moins le moins possible !

Eeeeeeeet, roulement de tambours đŸ„
ça donne ça :

.build-multi-arch:
  image: docker:27.4.1
  services:
    - docker:dind
  before_script:
    - test -z $DOCKER_HUB_PAT && echo -e "\e[31m DOCKER_HUB_PAT variable is required to login to DockerHub" && exit 1
    - test -z $DOCKER_HUB_USER && echo -e "\e[31m DOCKER_HUB_USER variable is required to login to DockerHub" && exit 1
    - echo "$DOCKER_HUB_PAT" | docker login --username "$DOCKER_HUB_USER" --password-stdin
  script:
    - docker buildx create --use
    - docker buildx build --push --platform $IMAGE_PLATFORMS --tag $PUSH_TO_REPO:$IMAGE_TAG .

Il n’y a rien de foufou au final. On fait du Docker in Docker pour avoir accĂšs aux commandes docker. Ensuite, j’ai ajoutĂ© un before_script pour m’assurer que les variables sont dĂ©finies pour ce connecter sur le DockerHub. Enfin, on build et on push en fonction des plateformes spĂ©cifiĂ©es et de la registry dĂ©finies via les variables.

J’ai tout documentĂ© ici. Pour que ce soit encore plus simple Ă  utiliser, j’ai créé un template GitLab CI. Le job peut ĂȘtre intĂ©grĂ© dans vos pipelines si vous souhaitez build et publier vos images sur le DockerHub avec plusieurs plateformes. 😎

Pour vous la faire giga courte, il suffit d’ajouter ce bloc dans vos pipelines :

include:
  - https://gitlab.com/Gribhb/am-ci-templates/-/raw/main/jobs/docker/build-multi-arch.yml

build-and-push:
  stage: build
  extends: .build-multi-arch
  variables:
    PUSH_TO_REPO: ""
    IMAGE_TAG: ""
    IMAGE_PLATFORMS: ""

Conclusion

VoilĂ , c’était un petit article sans prĂ©tention pour vous partager mon exploration autour des builds multi-plateform avec Docker et GitLab CI, suite Ă  un besoin perso.

Ça m’a permis de me challenger un peu pour arriver Ă  builder puis publier des images compatibles avec plusieurs plateformes en seulement quelques lignes dans le fichier gitlab-ci. Mission accomplie ! 🎯 (je trouve mdr)

Bon, c’est sĂ»rement perfectible, mais le rĂ©sultat est lĂ . On peut avoir des dĂ©ploiements d’images homogĂšnes prĂȘts Ă  ĂȘtre utilisĂ©es aussi bien sur Raspberry Pi que sur Mac M1/M2 ou un serveur x86.

Et oui, le plus important ! N’hĂ©sitez pas Ă  le forker, Ă  l’adapter Ă  vos besoins et Ă  faire des PR. Je suis preneur de toutes Ă©volutions 🙏

👉 Le code source du template est disponible ici

Published inNon classé