TP : Docker Buildx et Multi-Architecture
Objectifs pédagogiques
Section titled “Objectifs pédagogiques”- Comprendre les enjeux du multi-architecture
- Maîtriser Docker Buildx pour créer des images multi-plateforme
- Savoir builder et pousser des images pour AMD64 et ARM64
- Utiliser les build contexts et les builders personnalisés
Introduction : Pourquoi le multi-architecture ?
Section titled “Introduction : Pourquoi le multi-architecture ?”Dans le monde des conteneurs, différentes architectures de processeurs coexistent :
- AMD64 (x86_64) : Architecture dominante des serveurs et PC
- ARM64 (aarch64) : Utilisée par les Mac M1/M2/M3, Raspberry Pi, serveurs ARM (AWS Graviton)
- ARM/v7 : Raspberry Pi 3 et anciens modèles
Les enjeux du multi-architecture
Section titled “Les enjeux du multi-architecture”- Portabilité : Une seule image fonctionne sur toutes les architectures
- Performance : Les images natives sont plus rapides que l’émulation
- Coût : Les instances ARM sont souvent 20-40% moins chères (AWS Graviton, etc.)
- Développement : Les développeurs sur Mac M1/M2 ont besoin d’images ARM
Problème : Par défaut, docker build crée une image uniquement pour l’architecture de la machine hôte.
Docker Buildx : Le builder multi-architecture
Section titled “Docker Buildx : Le builder multi-architecture”Docker Buildx est un plugin CLI qui étend les capacités de build de Docker. Il permet notamment :
- Le build multi-architecture en une seule commande
- Le build distribué et la mise en cache avancée
- L’utilisation de nouveaux backends (BuildKit)
Vérifier Buildx
Section titled “Vérifier Buildx”# Vérifier que buildx est disponibledocker buildx version
# Lister les builders existantsdocker buildx lsSortie typique :
NAME/NODE DRIVER/ENDPOINT STATUS BUILDKIT PLATFORMSdefault * docker default default running v0.11.6 linux/amd64, linux/386Créer un builder multi-architecture
Section titled “Créer un builder multi-architecture”# Créer un nouveau builder capable de multi-archdocker buildx create --name multiarch-builder --use
# Initialiser le builder (télécharge les outils nécessaires)docker buildx inspect --bootstrap
# Vérifier les plateformes supportéesdocker buildx lsVous devriez voir plusieurs plateformes disponibles :
NAME/NODE DRIVER/ENDPOINT STATUS PLATFORMSmultiarch-builder * docker-container multiarch-builder0 unix:///var/run/docker.sock running linux/amd64, linux/arm64, linux/arm/v7, ...Comment ça marche : QEMU et émulation
Section titled “Comment ça marche : QEMU et émulation”Docker Buildx utilise QEMU pour émuler différentes architectures :
# Installer les émulateurs QEMU (généralement déjà fait par Docker Desktop)docker run --privileged --rm tonistiigi/binfmt --install all
# Vérifier les architectures disponiblesls -la /proc/sys/fs/binfmt_misc/Note : L’émulation est plus lente que le build natif, mais elle permet de builder pour n’importe quelle architecture depuis n’importe quelle machine.
Builder une image multi-architecture
Section titled “Builder une image multi-architecture”Exemple simple : Hello World
Section titled “Exemple simple : Hello World”FROM alpine:latestRUN apk add --no-cache curlCMD ["echo", "Hello from $(uname -m)"]# Build pour plusieurs architecturesdocker buildx build \ --platform linux/amd64,linux/arm64 \ --tag myuser/hello-multiarch:latest \ --push \ .Options importantes :
--platform: Spécifie les architectures cibles (séparées par des virgules)--push: Pousse directement vers un registry (obligatoire pour multi-arch)--load: Charge l’image dans le daemon local (incompatible avec multi-arch)
Variantes de commandes
Section titled “Variantes de commandes”# Build sans push (enregistre dans le builder cache)docker buildx build --platform linux/amd64,linux/arm64 -t myuser/app:latest .
# Build avec push automatiquedocker buildx build --platform linux/amd64,linux/arm64 -t myuser/app:latest --push .
# Build et export en local (une seule architecture à la fois)docker buildx build --platform linux/amd64 -t myapp:latest --load .
# Build avec plusieurs tagsdocker buildx build \ --platform linux/amd64,linux/arm64 \ -t myuser/app:latest \ -t myuser/app:1.0.0 \ --push \ .Les manifests multi-architecture
Section titled “Les manifests multi-architecture”Quand vous poussez une image multi-architecture, Docker crée automatiquement un manifest list :
# Inspecter un manifest multi-architecturedocker buildx imagetools inspect nginx:latest
# Sortie exemple :# Name: docker.io/library/nginx:latest# MediaType: application/vnd.docker.distribution.manifest.list.v2+json# Digest: sha256:abc123...## Manifests:# Name: docker.io/library/nginx:latest@sha256:def456...# MediaType: application/vnd.docker.distribution.manifest.v2+json# Platform: linux/amd64## Name: docker.io/library/nginx:latest@sha256:ghi789...# MediaType: application/vnd.docker.distribution.manifest.v2+json# Platform: linux/arm64Quand vous faites docker pull nginx:latest, Docker sélectionne automatiquement la bonne architecture.
Optimisations et bonnes pratiques
Section titled “Optimisations et bonnes pratiques”1. Utiliser des images de base multi-arch
Section titled “1. Utiliser des images de base multi-arch”Choisissez des images de base qui supportent déjà plusieurs architectures :
# ✅ Ces images supportent amd64 et arm64FROM python:3.11-slimFROM node:20-alpineFROM golang:1.21FROM nginx:alpine
# ❌ Vérifiez toujours la compatibilité des images tiercesFROM some-custom-image:latest # Peut ne pas être multi-arch2. Gérer les dépendances spécifiques à l’architecture
Section titled “2. Gérer les dépendances spécifiques à l’architecture”Certaines dépendances peuvent nécessiter des ajustements :
FROM python:3.11-slim
# Installer des dépendances qui peuvent varier selon l'archiRUN apt-get update && \ apt-get install -y --no-install-recommends \ build-essential \ && rm -rf /var/lib/apt/lists/*
# Les wheels Python peuvent nécessiter une compilationCOPY requirements.txt .RUN pip install --no-cache-dir -r requirements.txt3. Utiliser des ARGs pour l’architecture
Section titled “3. Utiliser des ARGs pour l’architecture”Docker injecte automatiquement des variables d’architecture :
FROM alpine:latest
# Variables automatiques disponiblesARG TARGETPLATFORMARG TARGETARCHARG TARGETVARIANT
RUN echo "Building for platform: ${TARGETPLATFORM}" && \ echo "Architecture: ${TARGETARCH}" && \ echo "Variant: ${TARGETVARIANT}"
# Exemple : télécharger le bon binaire selon l'architectureRUN wget https://example.com/app-${TARGETARCH}.tar.gzVariables disponibles :
TARGETPLATFORM: Ex.linux/amd64,linux/arm64TARGETARCH: Ex.amd64,arm64TARGETVARIANT: Ex.v7pour ARMTARGETOS: Ex.linux,windows
4. Cache et performance
Section titled “4. Cache et performance”# Utiliser un cache registry pour accélérer les buildsdocker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=registry,ref=myuser/app:buildcache \ --cache-to type=registry,ref=myuser/app:buildcache,mode=max \ -t myuser/app:latest \ --push \ .5. Builds multistage pour réduire la taille
Section titled “5. Builds multistage pour réduire la taille”# Stage 1 : BuildFROM node:20-alpine AS builderWORKDIR /appCOPY package*.json ./RUN npm ci --only=productionCOPY . .RUN npm run build
# Stage 2 : Production (plus léger)FROM nginx:alpineCOPY --from=builder /app/dist /usr/share/nginx/htmlEXPOSE 80CMD ["nginx", "-g", "daemon off;"]TP : Builder et déployer une application multi-architecture
Section titled “TP : Builder et déployer une application multi-architecture”Contexte
Section titled “Contexte”Vous allez travailler avec une application complète comprenant :
- Backend : API FastAPI (Python) qui expose des informations sur l’architecture
- Frontend : Application Svelte qui consomme l’API
L’objectif est de builder ces deux images pour AMD64 et ARM64, puis de les pousser sur un registry.
Étape 1 : Explorer le code
Section titled “Étape 1 : Explorer le code”# Structure du projetcd app/ls -la backend/ frontend/
# Examiner les Dockerfilescat backend/Dockerfilecat frontend/DockerfileQuestions :
- Quelles sont les images de base utilisées ?
- Ces images supportent-elles le multi-architecture ?
- Y a-t-il des multistage builds ?
Étape 2 : Tester en local (architecture native uniquement)
Section titled “Étape 2 : Tester en local (architecture native uniquement)”# Lancer l'application avec docker-composedocker-compose up --build
# Dans un autre terminal, tester l'APIcurl http://localhost:8000/api/info
# Ouvrir le frontend dans un navigateur# http://localhostObservation : Notez l’architecture retournée par l’API. C’est l’architecture de votre machine.
Étape 3 : Configurer Buildx
Section titled “Étape 3 : Configurer Buildx”# Créer un builder multi-architecturedocker buildx create --name tp-multiarch --use
# Initialiser et vérifierdocker buildx inspect --bootstrapdocker buildx lsQuestion : Quelles plateformes sont disponibles pour votre builder ?
Étape 4 : Builder le backend en multi-architecture
Section titled “Étape 4 : Builder le backend en multi-architecture”# Se connecter au registry (Docker Hub ou autre)docker login
# Remplacer 'votreusername' par votre username Docker Hubexport DOCKER_USERNAME=votreusername
# Builder le backend pour AMD64 et ARM64docker buildx build \ --platform linux/amd64,linux/arm64 \ --tag ${DOCKER_USERNAME}/multiarch-backend:latest \ --file app/backend/Dockerfile \ --push \ app/backend/
# Vérifier l'image multi-archdocker buildx imagetools inspect ${DOCKER_USERNAME}/multiarch-backend:latestÀ observer :
- Le temps de build (plus long car deux architectures)
- Les deux manifests dans l’output de
imagetools inspect - Les tailles d’image pour chaque architecture
Étape 5 : Builder le frontend en multi-architecture
Section titled “Étape 5 : Builder le frontend en multi-architecture”# Builder le frontenddocker buildx build \ --platform linux/amd64,linux/arm64 \ --tag ${DOCKER_USERNAME}/multiarch-frontend:latest \ --file app/frontend/Dockerfile \ --push \ app/frontend/Challenge : Le frontend utilise un build multistage. Identifiez les deux stages et expliquez leur rôle.
Étape 6 : Utiliser le script de build
Section titled “Étape 6 : Utiliser le script de build”Un script build-multiarch.sh est fourni pour automatiser le processus :
# Rendre le script exécutablechmod +x build-multiarch.sh
# Configurer les variablesexport DOCKER_USERNAME=votreusernameexport VERSION=1.0.0
# Lancer le build./build-multiarch.shExercice : Ouvrez et étudiez le script. Quelles sont les étapes automatisées ?
Étape 7 : Tester sur différentes architectures (Optionnel)
Section titled “Étape 7 : Tester sur différentes architectures (Optionnel)”Si vous avez accès à une machine ARM (Mac M1/M2, Raspberry Pi, instance AWS Graviton) :
# Sur la machine ARM, pull l'imagedocker pull ${DOCKER_USERNAME}/multiarch-backend:latest
# Docker sélectionne automatiquement l'architecture ARM64docker run --rm ${DOCKER_USERNAME}/multiarch-backend:latest \ python -c "import platform; print(platform.machine())"Sans machine ARM : Vous pouvez utiliser l’émulation :
# Forcer l'utilisation d'une image ARM64 avec émulationdocker run --rm --platform linux/arm64 \ ${DOCKER_USERNAME}/multiarch-backend:latest \ python -c "import platform; print(platform.machine())"⚠️ Attention : L’émulation est beaucoup plus lente que l’exécution native.
Étape 8 : Inspecter les images
Section titled “Étape 8 : Inspecter les images”# Voir les détails des manifestsdocker buildx imagetools inspect ${DOCKER_USERNAME}/multiarch-backend:latest
# Comparer les tailles d'images# Noter les différences de taille entre AMD64 et ARM64Questions d’analyse :
- Quelle architecture a l’image la plus grande ? Pourquoi ?
- Combien de layers ont été créés pour chaque architecture ?
- Y a-t-il des layers partagés entre les architectures ?
Commandes de référence
Section titled “Commandes de référence”Gestion des builders
Section titled “Gestion des builders”# Créer un nouveau builderdocker buildx create --name mybuilder --driver docker-container
# Utiliser un builderdocker buildx use mybuilder
# Lister les buildersdocker buildx ls
# Inspecter un builderdocker buildx inspect mybuilder
# Supprimer un builderdocker buildx rm mybuilderBuild multi-architecture
Section titled “Build multi-architecture”# Build simple multi-arch avec pushdocker buildx build --platform linux/amd64,linux/arm64 -t user/app:tag --push .
# Build avec cachedocker buildx build \ --platform linux/amd64,linux/arm64 \ --cache-from type=registry,ref=user/app:cache \ --cache-to type=registry,ref=user/app:cache \ -t user/app:tag \ --push .
# Build une seule architecture et charger en localdocker buildx build --platform linux/amd64 -t app:latest --load .Inspection des images
Section titled “Inspection des images”# Inspecter un manifest multi-archdocker buildx imagetools inspect nginx:latest
# Voir les layers d'une architecture spécifiquedocker buildx imagetools inspect --raw nginx:latest | jq .
# Créer un nouveau tag à partir d'un manifest existantdocker buildx imagetools create -t user/app:newtag user/app:oldtagPour aller plus loin
Section titled “Pour aller plus loin”1. GitHub Actions pour le CI/CD multi-arch
Section titled “1. GitHub Actions pour le CI/CD multi-arch”Exemple de workflow GitHub Actions :
name: Build Multi-Arch
on: push: branches: [ main ]
jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3
- name: Set up QEMU uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push uses: docker/build-push-action@v4 with: context: . platforms: linux/amd64,linux/arm64 push: true tags: user/app:latest2. Registries alternatifs
Section titled “2. Registries alternatifs”# GitHub Container Registrydocker buildx build --platform linux/amd64,linux/arm64 \ -t ghcr.io/username/app:latest --push .
# AWS ECR (nécessite authentication)docker buildx build --platform linux/amd64,linux/arm64 \ -t 123456789.dkr.ecr.us-east-1.amazonaws.com/app:latest --push .
# GitLab Container Registrydocker buildx build --platform linux/amd64,linux/arm64 \ -t registry.gitlab.com/username/project/app:latest --push .3. Architectures supplémentaires
Section titled “3. Architectures supplémentaires”# Ajouter ARM v7 (Raspberry Pi 3)docker buildx build \ --platform linux/amd64,linux/arm64,linux/arm/v7 \ -t user/app:latest --push .
# Windows containers (nécessite Windows builders)docker buildx build \ --platform windows/amd64 \ -t user/app:latest --push .Ressources
Section titled “Ressources”- Docker Buildx Documentation
- Multi-platform builds
- BuildKit Documentation
- QEMU Documentation
- Docker Hub Multi-Arch
Troubleshooting
Section titled “Troubleshooting”Erreur : “multiple platforms feature is currently not supported”
Section titled “Erreur : “multiple platforms feature is currently not supported””Solution : Utilisez --push ou --output type=registry au lieu de --load.
# ❌ Ne fonctionne pas avec multi-archdocker buildx build --platform linux/amd64,linux/arm64 -t app --load .
# ✅ Fonctionnedocker buildx build --platform linux/amd64,linux/arm64 -t app --push .Erreur : “exec user process caused: exec format error”
Section titled “Erreur : “exec user process caused: exec format error””Cause : Vous essayez d’exécuter une image d’une architecture différente sans émulation.
Solution :
# Installer QEMUdocker run --privileged --rm tonistiigi/binfmt --install allBuild très lent
Section titled “Build très lent”Causes :
- Émulation QEMU (normal pour architectures non-natives)
- Pas de cache configuré
Solutions :
# Utiliser le cache registrydocker buildx build \ --cache-from type=registry,ref=user/app:cache \ --cache-to type=registry,ref=user/app:cache \ --platform linux/amd64,linux/arm64 \ -t user/app:latest --push .
# Ou builder chaque architecture séparément sur des machines nativesPermission denied lors du push
Section titled “Permission denied lors du push”Solution :
# Se connecter au registrydocker login
# Ou avec un tokenecho $DOCKER_TOKEN | docker login -u username --password-stdinConclusion
Section titled “Conclusion”Docker Buildx permet de créer facilement des images multi-architecture, rendant vos applications portables sur différents types de matériel. Bien que le build soit plus long, les bénéfices en termes de compatibilité et de flexibilité de déploiement sont considérables.
Points clés à retenir :
- ✅ Utilisez
--platformpour spécifier les architectures cibles - ✅ Les images multi-arch nécessitent
--push(pas de--load) - ✅ Docker utilise QEMU pour émuler les architectures non-natives
- ✅ Les manifest lists permettent à Docker de choisir automatiquement la bonne architecture
- ✅ Les images de base doivent supporter le multi-architecture