Vai al contenuto principale

Docker Buildx: come creare immagini container multi-piattaforma

Scopri come Docker Buildx estende la build tradizionale dei container con supporto multi-piattaforma, strategie di caching avanzate e ottimizzazioni delle performance. Questa guida copre dai concetti base alle tecniche avanzate.
· 14 min leggi

Scopri con l'IA

Creare container per più piattaforme può sembrare intimidatorio e dispendioso in termini di tempo, ma tra poco vedrai che in realtà non lo è affatto.

Il comando docker buildx risolve questa sfida estendendo le capacità di build di Docker con funzionalità avanzate come la creazione di immagini multi-piattaforma, il caching migliorato e l’elaborazione in parallelo delle build. Integra il motore di build di nuova generazione BuildKit direttamente nella CLI di Docker. Con il comando buildx creerai immagini container più piccole, veloci e sicure senza dover imparare un set di strumenti completamente nuovo.

Negli ultimi anni, Buildx è diventato più o meno essenziale per le best practice DevOps e lo sviluppo di applicazioni cloud-native. Snellisce le pipeline CI/CD e ti aiuta a distribuire le applicazioni in modo coerente su target eterogenei, dai dispositivi IoT basati su ARM ai cluster di server nel cloud.

> Nuovo a Docker? La nostra guida pratica per chi parte da zero ti farà iniziare in un attimo.

In questo articolo ti guiderò attraverso tecniche base e avanzate di docker buildx.

Capire Docker Buildx

Probabilmente usi già Docker, quindi conosci il comando standard docker build. Prima o poi, però, inizierà a sembrarti limitante, soprattutto quando i progetti diventano più complessi.

> Docker Buildx presuppone che Docker sia installato. Se non lo è e stai eseguendo Linux, segui questa guida per un'installazione semplice.

Docker Buildx ti offre un'esperienza di build migliorata che funziona con ciò che già conosci. Non è uno strumento separato da installare: è già incluso in Docker Desktop ed Engine dalla versione 19.03. Buildx usa BuildKit sotto al cofano, il builder di nuova generazione di Docker che riscrive il modo in cui si creano le immagini. Noterai build più veloci, immagini più piccole e il supporto a ulteriori funzionalità.

Il salto da docker build a docker buildx build può sembrare piccolo — è solo una parola in più dopotutto — ma le capacità che guadagni sono enormi.

Vediamo come funziona davvero Buildx e cosa lo rende diverso dal builder legacy.

Fondamenti architetturali di Buildx

La “magia” di Buildx deriva dal suo intelligente design client-server.

Quando esegui un comando Buildx, usi la CLI di Docker come client che comunica con il demone BuildKit — la componente server che fa il lavoro pesante. Questa separazione consente a BuildKit di fare cose che il builder legacy non può, come eseguire le fasi di build in parallelo invece che in sequenza. Le istruzioni nel tuo Dockerfile non devono più essere eseguite una dopo l’altra, riducendo sensibilmente i tempi di build quando ci sono fasi indipendenti.

Il modello client-server permette anche l'esecuzione remota delle build. Puoi puntare la tua CLI Docker locale a un'istanza BuildKit remota in esecuzione ovunque — su un potente server di build, nel cloud o persino in un cluster Kubernetes. Questa flessibilità significa che non devi saturare le risorse del tuo laptop per build massicce né preoccuparti di problemi di compatibilità architetturale.

Il design modulare di BuildKit permette anche di collegare diversi parser frontend. La sintassi Dockerfile è quella predefinita, ma puoi usare formati alternativi di definizione della build se si adattano meglio al tuo workflow.

Flusso del processo di build

Quando esegui docker buildx build, la CLI seleziona prima un'istanza builder, quella predefinita o una che hai specificato. Il tuo contesto di build e il Dockerfile vengono inviati al demone BuildKit, che analizza le istruzioni e crea un grafo aciclico diretto (DAG) dei passaggi di build. A differenza del builder legacy che elabora ogni istruzione in sequenza, BuildKit analizza questo grafo per determinare quali passaggi possono essere eseguiti in parallelo.

Il builder esegue quindi questi passaggi usando algoritmi di caching efficienti e molto più intelligenti della vecchia cache basata sui layer. BuildKit traccia gli input e gli output esatti di ogni passaggio, evitando ricompilazioni non necessarie quando nulla di rilevante è cambiato. Supporta anche la distribuzione della build su più nodi worker per un'elaborazione ancora più rapida.

Dopo la build, Buildx può esportare i risultati in diversi formati, non solo come immagini Docker. Puoi eseguire l’output in formati OCI, directory locali o tarball, o addirittura saltare del tutto la creazione dell’immagine se vuoi solo testare il processo di build.

Hai ragione: questa sezione trarrebbe sicuramente beneficio da esempi pratici e contenuti visuali per mostrare come Buildx funziona in scenari reali. Ecco come la arricchirei con più esempi di codice e suggerimenti per le immagini:

Funzionalità principali

Docker Buildx non serve solo a costruire immagini più velocemente, anche se sicuramente lo fa. Serve ad ampliare ciò che è possibile fare con le pipeline di build.

Vediamo le funzionalità di spicco che rendono Buildx una scelta da considerare per il tuo prossimo progetto.

> Cerchi idee per progetti Docker? Queste 10 metteranno in riga il tuo portfolio DevOps.

Applicazione Python utilizzata

Per questo articolo ho creato una semplice applicazione Python Flask. Per seguire passo passo, crea 3 file: app.py, requirements.txt e Dockerfile.

Ecco i contenuti per ciascuno:

app.py

from flask import Flask, render_template_string
import platform
import socket
import psutil
import datetime

app = Flask(__name__)


@app.route("/")
def home():
    html = """
    <!DOCTYPE html>
    <html>
      <head>
        <title>Docker Buildx Python Demo</title>
        <style>
          body {
            
            max-width: 800px;
            
            
          }
          .container {
            border: 1px solid #ddd;
            border-radius: 5px;
            
            background-
          }
          .info {
            
          }
          .platform {
            font-weight: bold;
            
          }
        </style>
      </head>
      <body>
        <h1>Docker Buildx Multi-Platform Demo (Python)</h1>
        <div class="container">
          <div class="info">Hostname: {{ hostname }}</div>
          <div class="info">Platform: <span class="platform">{{ os_platform }} ({{ architecture }})</span></div>
          <div class="info">CPUs: {{ cpu_count }}</div>
          <div class="info">Total Memory: {{ memory_mb }} MB</div>
          <div class="info">Server Time: {{ server_time }}</div>
        </div>
      </body>
    </html>
    """
    return render_template_string(
        html,
        hostname=socket.gethostname(),
        os_platform=platform.system(),
        architecture=platform.machine(),
        cpu_count=psutil.cpu_count(),
        memory_mb=round(psutil.virtual_memory().total / (1024 * 1024)),
        server_time=datetime.datetime.now().isoformat(),
    )


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

requirements.txt

flask==3.1.0
psutil==7.0.0

Dockerfile

FROM python:3.13-slim

WORKDIR /app

COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

COPY app.py .

EXPOSE 5000

CMD ["python", "app.py"]

Una volta fatto, apri una nuova finestra del Terminale e vai nella cartella del progetto.

Costruzione di immagini multi-piattaforma

Creare immagini che funzionano su architetture CPU diverse sembra un incubo, ma Buildx lo rende sorprendentemente semplice.

Guarda questo comando:

docker buildx build --platform linux/amd64,linux/arm64 -t myapp:latest .

Image 1 - Using Docker Buildx

Immagine 1 - Utilizzo di Docker Buildx

In breve, ti permette di creare immagini per più architetture contemporaneamente. Buildx lo gestisce con tre approcci intelligenti: può usare QEMU per l’emulazione dell’architettura (consentendoti di creare immagini ARM su una macchina x86), connettersi a nodi builder nativi per ogni piattaforma target oppure combinare entrambi i metodi per prestazioni ottimali. Il risultato è una manifest list multi-architettura — a volte chiamata “fat manifest” — che contiene le varianti della tua immagine per ciascuna piattaforma.

Se distribuisci su ambienti diversi come istanze AWS Graviton, cluster Raspberry Pi o infrastrutture miste, questo supporto multi-piattaforma è fondamentale.

Strategie di caching avanzate

Buildx trasforma completamente il funzionamento della cache di build e in generale rende le build più veloci.

Il sistema implementa una strategia di caching a tre livelli che va oltre il semplice caching dei layer delle build Docker tradizionali:

  1. Cache inline incorporata: per prima cosa, Buildx usa una cache inline incorporata nelle immagini, permettendoti di sfruttare i layer in cache da build precedenti anche in ambienti “freschi”.
  2. Cache di build locale: in secondo luogo, supporta una cache locale gestita in modo intelligente in base agli input delle istruzioni di build e non solo al loro ordine.
  3. Caching basato su registry: in terzo luogo, offre un caching basato su registry che ti permette di condividere la cache di build tra macchine, perfetto per pipeline CI/CD o team distribuiti.

Con la nostra app Python, vediamo come usare strategie di cache locali:

# Crea una directory per la cache locale
mkdir -p buildx-cache

# Prima build - esporta la cache nella directory locale
docker buildx build --cache-to type=local,dest=./buildx-cache -t myapp:latest .

# Fai una piccola modifica a app.py
echo "# Small comment change" >> app.py

# Seconda build - usa la cache locale
docker buildx build --cache-from type=local,src=./buildx-cache -t myapp:latest .

La seconda build sarà molto più veloce perché riutilizza i layer in cache dalla prima build.

Image 2 - Local caching strategies

Immagine 2 - Strategie di caching locale

Puoi anche usare la cache inline, che incorpora i metadati della cache direttamente nell’immagine:

docker buildx build --cache-to type=inline -t myapp:latest .

Puoi configurare questi backend di cache con semplici flag come --cache-to e --cache-from, puntando a directory locali, repository su registry o perfino servizi di cache specializzati. Questa flessibilità mantiene le build veloci in ambienti diversi senza sacrificare la riproducibilità.

Funzionalità di sicurezza

Buildx include strumenti che ti faranno dimenticare le preoccupazioni sulla sicurezza.

Mettiamo che la tua app Python debba accedere a una weather API durante il processo di build. Invece di inserire in chiaro la tua API key nel Dockerfile, puoi usare i build secret:

# Archivia la tua API key in un file locale
echo "abc123yourweatherapikey" > ./api_key.txt

# Build con il secret
docker buildx build --secret id=weather_api_key,src=./api_key.txt -t myapp:latest .

Poi, nel Dockerfile, puoi accedere al secret solo quando serve:

FROM python:3.13-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY app.py .
# Crea un file di configurazione usando il secret in fase di build
RUN --mount=type=secret,id=weather_api_key \
    echo "WEATHER_API_KEY=$(cat /run/secrets/weather_api_key)" > .env
EXPOSE 5000
CMD ["python", "app.py"]

Puoi verificare che l’API key non sia nella tua immagine finale controllando la cronologia dell’immagine o eseguendo:

docker run --rm myapp:latest cat .env

Image 3 - Managing environment variables

Immagine 3 - Gestione delle variabili d'ambiente

Nel tuo app.py, potresti caricare l’API key così:

import os
from dotenv import load_dotenv

load_dotenv()  # Load variables from .env file
api_key = os.getenv("WEATHER_API_KEY", "")
# ...

Questo approccio fa sì che la tua API key sensibile sia disponibile solo durante lo specifico step di build in cui serve, ma non venga salvata in nessuno dei layer dell’immagine. Chiunque scarichi la tua immagine non potrà estrarre la tua API key, anche ispezionando i layer.

Per più sicurezza, puoi anche usare container di build temporanei che vengono rimossi automaticamente dopo la build:

docker buildx build --secret id=weather_api_key,src=./api_key.txt --rm -t myapp:latest .

Il flag --rm assicura che eventuali container intermedi creati durante la build vengano rimossi, riducendo ulteriormente il rischio di fughe di credenziali.

Configurazione operativa

Configurare Buildx per il tuo workflow richiede solo pochi comandi, ma capire le opzioni ti aiuta a sfruttarlo al massimo.

Vediamo come configurare e gestire Buildx in locale in base alle tue esigenze specifiche.

Gestione delle istanze builder

Docker Buildx usa il concetto di “builder” — istanze BuildKit separate con diverse capacità e configurazioni. Puoi creare più builder per scopi differenti.

Per prima cosa, vediamo quali builder hai già:

docker buildx ls

Vedrai un output simile a questo:

Image 4 - Available builders

Immagine 4 - Builder disponibili

Per creare una nuova istanza builder, esegui i seguenti comandi:

# Crea un nuovo builder
docker buildx create --name mybuilder

# Passa a usare quel builder
docker buildx use mybuilder

# Avvia il builder (bootstrap)
docker buildx inspect --bootstrap

Puoi verificare che stia funzionando con:

# Controlla lo stato
docker buildx ls

Image 5 - Switching to a custom builder

Immagine 5 - Passaggio a un builder personalizzato

Se devi rimuovere un builder, esegui semplicemente:

docker buildx rm mybuilder

Gestione dell'output

Buildx ti offre opzioni flessibili su cosa fare con le immagini che compili. Puoi caricarle direttamente nel tuo demone Docker locale, esportarle come tarball o salvarle in una directory locale.

Vediamo come usare queste opzioni con la nostra app Python:

# Carica l'immagine direttamente in Docker (comportamento predefinito)
docker buildx build --load -t myapp:latest .

# Esporta l'immagine come tarball
docker buildx build --output type=docker,dest=myapp.tar -t myapp:latest .

# Salva i contenuti dell'immagine in una directory locale
docker buildx build --output type=local,dest=./image-output -t myapp:latest .

Dopo l’esportazione come tarball, puoi caricarla in Docker con:

docker load < myapp.tar

Image 6 - Loading an image from a tarball export

Immagine 6 - Caricamento di un'immagine da un'esportazione tarball

L’output in directory locale è particolarmente utile per l’ispezione. Vediamo cosa viene creato:

ls -la ./image-output

Vedrai il filesystem grezzo dell’immagine:

Image 7 - Local directory export contents

Immagine 7 - Contenuti dell'export in directory locale

Puoi persino eseguire specifiche fasi di build senza creare un’immagine finale. È utile per il debug o per testare step di build:

# Crea un Dockerfile multi-stage
cat > Dockerfile.multi << 'EOF'
FROM python:3.13-slim AS base
WORKDIR /app
COPY requirements.txt .

FROM base AS dev-deps
RUN pip install --no-cache-dir -r requirements.txt
RUN pip install pytest

FROM base AS prod-deps
RUN pip install --no-cache-dir -r requirements.txt

FROM prod-deps AS final
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
EOF

# Esegui solo lo stage dev-deps ed esportane il filesystem
docker buildx build --file Dockerfile.multi --target dev-deps --output type=local,dest=./dev-deps-output .

Ora puoi ispezionare quali pacchetti sono stati installati nell’ambiente di sviluppo:

cat ./dev-deps-output/usr/local/lib/python3.13/site-packages/pytest/__init__.py

Image 8 - File contents from dev-deps stage

Immagine 8 - Contenuti di file dallo stage dev-deps

In sintesi, queste opzioni di output ti danno il controllo completo su dove inviare le immagini create, che tu stia facendo debug in locale o preparando immagini da condividere con il team.

Casi d'uso avanzati

Finora ti ho mostrato comandi e casi d’uso base di Buildx. Buildx può fare molto di più, e alcune funzionalità sono impossibili da implementare con il builder classico.

Vediamo alcune tecniche avanzate per portare il tuo workflow di containerizzazione al livello successivo.

Ottimizzazione delle build multi-stage

Le build multi-stage sono una delle caratteristiche più potenti di Docker per creare immagini efficienti, e Buildx le rende ancora migliori.

Per dimostrare, creiamo un’applicazione Python ottimizzata con più stage:

# Dockerfile.optimized
FROM python:3.13-slim AS base
WORKDIR /app
COPY requirements.txt .

FROM base AS builder
RUN pip install --no-cache-dir --target=/install -r requirements.txt

FROM base AS linter
COPY --from=builder /install /usr/local/lib/python3.13/site-packages
COPY app.py .
RUN pip install pylint && pylint app.py || exit 0

FROM base AS tester
COPY --from=builder /install /usr/local/lib/python3.9/site-packages
COPY app.py .
RUN pip install pytest && python -m pytest app.py -v || exit 0

FROM python:3.13-alpine AS final
WORKDIR /app
COPY --from=builder /install /usr/local/lib/python3.13/site-packages
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]

Con Buildx, puoi costruire il tutto in modo più efficiente:

docker buildx build --file Dockerfile.optimized -t myapp:optimized --load .

Image 9 - Multi-stage builds

Immagine 9 - Build multi-stage

Cosa rende speciale questo approccio? Buildx elabora in parallelo gli stage indipendenti. Mentre il builder legacy eseguirebbe ogni stage in sequenza, Buildx identifica che gli stage linter e tester non dipendono l’uno dall’altro e li costruisce simultaneamente.

Un ulteriore vantaggio di questa ottimizzazione è la riduzione delle dimensioni del file. Puoi verificare la dimensione dell’immagine eseguendo:

docker images myapp

Vedrai qualcosa del genere:

Image 10 - Docker image sizes

Immagine 10 - Dimensioni delle immagini Docker

L’immagine finale basata su alpine è molto più piccola.

Integrazione nelle pipeline CI/CD

Anche lavorando in locale, puoi impostare configurazioni Buildx che rispecchiano il tuo ambiente CI/CD.

Per iniziare, crea un file .dockerignore per mantenere pulite le build:

.git
__pycache__
*.pyc
*.pyo
*.pyd
.Python
env
venv
*.so
.coverage
htmlcov

Poi crea uno script di build che imita ciò che potrebbe fare la tua pipeline CI:

#!/bin/bash
# build.sh - Simulazione CI/CD locale

echo "Starting CI/CD build process..."

# Setup builder con supporto all'emulazione
echo "Setting up builder..."
docker buildx create --name cibuilder --use || true
docker buildx inspect --bootstrap

# Esegui linting
echo "Running lint stage..."
docker buildx build --file Dockerfile.optimized --target linter .

# Esegui i test
echo "Running test stage..."
docker buildx build --file Dockerfile.optimized --target tester .

# Build per più piattaforme
echo "Building multi-platform image..."
docker buildx build --file Dockerfile.optimized \
  --platform linux/amd64,linux/arm64 \
  --tag myapp:$(date +%Y%m%d) \
  --tag myapp:latest \
  --load \
  --progress=plain \
  .

echo "Build process complete!"

In parole semplici, questo script fa quanto segue:

  • Crea un builder dedicato per la CI/CD.
  • Esegue lo stage di linting.
  • Esegue lo stage di testing.
  • Compila l’immagine finale multi-piattaforma con tag versionati.

Ora viene il bello: rendi eseguibile lo script ed eseguilo:

chmod +x build.sh
./build.sh

Modifica locale

Un punto dolente comune quando si lavora con Docker è che ogni volta che cambi un file sorgente devi ricompilare l’immagine ed eseguire il container. Richiede troppo tempo.

La buona notizia è che, per lo sviluppo locale con iterazioni più rapide, puoi creare una versione di sviluppo:

# Dockerfile.dev
FROM python:3.13-slim
WORKDIR /app

RUN pip install flask psutil python-dotenv

# Installa strumenti di sviluppo
RUN pip install pytest pylint watchdog

# Monta il codice dell'app a runtime invece di copiarlo
CMD ["python", "app.py"]

Eseguila con un volume mount per il reload del codice in tempo reale:

docker buildx build -f Dockerfile.dev -t myapp:dev --load .
docker run -it --rm -p 5000:5000 -v $(pwd):/app myapp:dev

Ora puoi modificare il file app.py in locale e le modifiche saranno immediatamente riflesse nel container in esecuzione!

A seguire, parliamo di performance.

Considerazioni sulle performance

Nessuno ama un workflow di sviluppo lento, e la potenza della parallelizzazione con Docker Buildx può aiutare.

Vediamo come ottimizzare le build e sfruttare le funzionalità di performance di Buildx per creare immagini più rapidamente.

Tecniche di parallelizzazione della build

Uno dei maggiori vantaggi di Buildx è la capacità di costruire gli stage in parallelo. Il builder tradizionale esegue ogni passaggio in sequenza, ma Buildx analizza il tuo Dockerfile e identifica quali step possono essere eseguiti contemporaneamente.

Per dimostrare, userò due file: Dockerfile.standard e Dockerfile.parallel. Ecco i contenuti di entrambi:

Dockerfile.standard

FROM python:3.13-slim
WORKDIR /app

# Dipendenze di sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    g++ \
    && rm -rf /var/lib/apt/lists/*

# Dipendenze Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Codice dell'applicazione
COPY app.py .

# Linting
RUN pip install pylint && pylint app.py || true

EXPOSE 5000
CMD ["python", "app.py"]

Dockerfile.parallel

FROM python:3.13-slim AS python-base
WORKDIR /app

# Stage indipendente per installare le dipendenze di sistema
FROM python-base AS system-deps
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc \
    g++ \
    && rm -rf /var/lib/apt/lists/*

# Stage indipendente per installare le dipendenze Python
FROM python-base AS python-deps
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Stage indipendente per l'analisi statica del codice
FROM python-deps AS linting
COPY app.py .
RUN pip install pylint && pylint app.py || true

# Stage finale che combina le dipendenze
FROM python-base AS final
# Copia dallo stage delle dipendenze di sistema
COPY --from=system-deps /usr/bin/gcc /usr/bin/gcc
# Copia dallo stage delle dipendenze Python
COPY --from=python-deps /usr/local/lib/python3.13/site-packages /usr/local/lib/python3.13/site-packages
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]

Misuriamo come questa struttura parallela migliori i tempi di build:

# Misura la build sequenziale standard
time docker build -t myapp:standard -f Dockerfile.standard .

# Misura la build ottimizzata in parallelo con Buildx
time docker buildx build --load -t myapp:parallel -f Dockerfile.parallel .

Per riferimento, la build standard ha impiegato 18,48 secondi mentre quella parallela solo 1,17 secondi!

Per prestazioni ancora migliori, puoi provare a usare i flag --cache-from e --cache-to per sfruttare la cache su disco locale:

# Prima build - crea la cache
docker buildx build --load -t myapp:latest --cache-to type=local,dest=./buildcache .

# Build successive - usa la cache
docker buildx build --load -t myapp:latest --cache-from type=local,src=./buildcache .

Puoi anche limitare la dimensione del contesto con file .dockerignore ben curati:

# Crea un .dockerignore completo
cat > .dockerignore << 'EOF'
.git
.github
.dockerignore
.pytest_cache
__pycache__
*.pyc
*.pyo
*.pyd
.Python
venv
env
node_modules
.coverage
htmlcov
.DS_Store
EOF

In poche parole, strutturando i Dockerfile con la parallelizzazione in mente e sfruttando il caching avanzato di Buildx, passerai meno tempo ad aspettare le build e più tempo a sviluppare funzionalità.

Integrazione nell'ecosistema

Docker Buildx non vive in isolamento. È progettato per integrarsi senza attriti con gli altri strumenti del tuo ambiente di sviluppo.

Vediamo come Buildx lavora con gli strumenti locali per sviluppatori e rende più efficiente il tuo workflow con i container.

Cluster di build Kubernetes

Kubernetes offre potenti capacità per eseguire operazioni Docker Buildx distribuite su un cluster. Integrando Buildx con Kubernetes, ottieni build più veloci e resilienti che scalano con le esigenze del progetto.

> Sei nuovo a Kubernetes? Il post Kubernetes vs Docker: differenze che ogni sviluppatore dovrebbe conoscere è la tua prossima tappa.

Usare Kubernetes per l’infrastruttura di build offre alcuni vantaggi:

  1. Scalabilità automatica: Kubernetes può scalare i nodi builder in base alla domanda, allocando efficientemente le risorse nel cluster. Puoi anche impostare regole di autoscaling basate sull’utilizzo della CPU.
  2. Ottimizzazione delle risorse: Il scheduling di Kubernetes assicura che le build ottengano le risorse necessarie senza sovraccaricare i singoli nodi. Puoi impostare limiti e richieste di risorse per prestazioni costanti.
  3. Alta disponibilità: Distribuendo le istanze BuildKit su più nodi, l’infrastruttura di build resta disponibile anche se alcuni nodi vanno in errore.
  4. Ambienti coerenti: Ogni membro del team si connette alla stessa infrastruttura di build, eliminando i problemi “sul mio PC funziona”.
  5. Esecuzione in parallelo: Build complesse con molti stage possono essere eseguite in parallelo su più nodi, riducendo sensibilmente i tempi. Un progetto che localmente richiederebbe 15 minuti può essere completato in 3-4 minuti se distribuito.

Considera questa sezione più “teorica”, perché approfondire Kubernetes è di per sé un argomento avanzato.

Per iniziare, crea un file chiamato buildkit-deployment.yaml con il seguente contenuto:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: buildkit
  namespace: buildkit
spec:
  replicas: 3
  selector:
    matchLabels:
      app: buildkit
  template:
    metadata:
      labels:
        app: buildkit
    spec:
      containers:
      - name: buildkit
        image: moby/buildkit:latest
        args:
        - --addr
        - tcp://0.0.0.0:1234
        ports:
        - containerPort: 1234
        securityContext:
          privileged: true
---
apiVersion: v1
kind: Service
metadata:
  name: buildkit
  namespace: buildkit
spec:
  type: ClusterIP
  ports:
  - port: 1234
    targetPort: 1234
  selector:
    app: buildkit

Il passo successivo è applicare questo file al tuo cluster Kubernetes:

kubectl create namespace buildkit
kubectl apply -f buildkit-deployment.yaml

Infine, connettiti a questa deployment dalla tua macchina locale:

docker buildx create --name k8s-builder \
  --driver remote \
  --driver-opt endpoint=tcp://<cluster-ip>:1234 \
  --use

E questo è tutto, sei pronto per partire!

Supporto dei plugin IDE

IDE come Visual Studio Code offrono un’eccellente integrazione con Docker Buildx tramite l’estensione Docker. Questa integrazione facilita la gestione dei workflow Buildx direttamente dall’ambiente di sviluppo.

Per iniziare con Docker Buildx in VS Code, installa l’estensione “Docker” dal marketplace di VS Code.

Una volta installata, avrai a disposizione diverse funzionalità specifiche per Buildx:

  • Clic destro su qualsiasi Dockerfile per vedere un menu contestuale con l’opzione “Build Image...” che supporta Buildx.
  • Accesso ad argomenti di build, target di piattaforma e opzioni di output tramite l’interfaccia.
  • Possibilità di gestire e passare tra diverse istanze builder.
  • Integrazione con il terminale di VS Code per eseguire comandi Buildx complessi.

Image 12 - Docker extension for VSCode

Immagine 11 - Estensione Docker per VSCode

Ecco un esempio di personalizzazione dei task di VS Code per usare Buildx creando un file .vscode/tasks.json:

{
  "version": "2.0.0",
  "tasks": [
    {
      "label": "Docker: Buildx Build",
      "type": "shell",
      "command": "docker buildx build --load -t ${input:imageName} .",
      "group": {
        "kind": "build",
        "isDefault": true
      }
    },
    {
      "label": "Docker: Buildx Multi-Platform",
      "type": "shell",
      "command": "docker buildx build --platform linux/amd64,linux/arm64 -t ${input:imageName} ."
    }
  ],
  "inputs": [
    {
      "id": "imageName",
      "description": "Image name (with tag):",
      "default": "myapp:latest",
      "type": "promptString"
    }
  ]
}

Con questa configurazione, puoi accedere rapidamente ai comandi Buildx più comuni dal menu Tasks di VS Code (Terminal > Run Task). L’estensione fornisce anche un utile syntax highlighting per i Dockerfile e l’autocompletamento per i comandi Docker più comuni, il tutto rendendo più produttivo il workflow con Buildx.

Risoluzione dei problemi e debug

Ogni strumento di sviluppo richiede talvolta (troppo spesso) una risoluzione dei problemi, e Docker Buildx non fa eccezione. In questa sezione, ti guiderò attraverso alcuni problemi comuni così potrai diagnosticarli rapidamente e tornare al lavoro.

Problemi comuni e soluzioni

Lavorando con Buildx potresti incontrare alcune sfide comuni. Ecco i problemi più frequenti e le loro soluzioni:

  • Creazione del builder fallita. Se vedi errori creando un builder con docker buildx create, controlla la versione di Docker:
docker version

Buildx richiede Docker 19.03 o successivo. Se usi una versione precedente, aggiorna Docker per accedere alle funzionalità di Buildx.

Per errori “no such plugin”, assicurati che Buildx sia installato correttamente eseguendo:

docker buildx version
  • Errore nelle build multi-piattaforma. Quando crei build per più piattaforme con errori come “exec format error” o “no matching manifest”, verifica se QEMU è installato:
docker buildx inspect --bootstrap

Se necessario, installa gli emulatori di piattaforma:

docker run --privileged --rm tonistiigi/binfmt --install all
  • Problemi legati alla cache. In caso di problemi con la cache, prova a pulire la cache di build locale:
# Rimuovi la cache di uno specifico builder
docker buildx prune -b mybuilder

# Rimuovi tutta la cache di build
docker buildx prune --all

> Cos’è esattamente il comando Docker prune? Scoprilo con una valanga di esempi pratici.

  • Problemi di connessione al demone BuildKit. Se vedi “failed to solve” o errori di connessione, riavvia il builder:
docker buildx rm mybuilder
docker buildx create --name mybuilder --use
docker buildx inspect --bootstrap
  • Problemi di performance. Per build lente, prova l’output di debug per identificare i colli di bottiglia:
docker buildx build --progress=plain --no-cache .

Questo output dettagliato aiuta a individuare quali stage impiegano più tempo, permettendoti di ottimizzare di conseguenza il Dockerfile.

  • Errori con il comando "load". Se incontri “error: docker exporter does not currently support exporting manifest lists” usando --load con build multi-piattaforma, ricorda che il caricamento di più piattaforme nel demone Docker simultaneamente non è supportato. In alternativa:
# Crea la build per la tua piattaforma corrente e caricala
docker buildx build --platform linux/amd64 --load -t myapp:latest .
  • Pratiche di debug. Per problemi più complessi, questi approcci di debug aiutano:
# Attiva i log di debug di BuildKit
BUILDKIT_DEBUG=1 docker buildx build .

# Ispeziona lo stato interno del builder
docker buildx inspect

# Verifica i requisiti di sistema
docker info

# Per errori in uno specifico stage, compila solo fino a quello stage
docker buildx build --target problem-stage .

# Verifica il tuo contesto Docker
docker context ls

Lavorando in modo sistematico attraverso questi passaggi, puoi risolvere la maggior parte dei problemi con Buildx e mantenere efficiente il workflow di build dei container.

Riepilogo della guida a Docker Buildx

Abbiamo coperto un bel po’ di terreno in questo articolo su Docker Buildx! Hai visto come questo potente strumento può rendere le build dei container più rapide e flessibili.

Ricorda i vantaggi chiave: puoi creare immagini per più piattaforme con un solo comando, accelerare le build con caching avanzato e mantenere sicure le immagini con una corretta gestione dei secret. I miglioramenti prestazionali sono reali, soprattutto se strutturi i Dockerfile per sfruttare la build in parallelo.

Io lo uso sempre sul mio Macbook con chip M, dato che non tutte le immagini sono disponibili per ARM.

Che tu sia uno sviluppatore solista o parte di un grande team, Buildx ti offre strumenti che si adattano al tuo workflow. Puoi eseguire build in locale, distribuirle tra container o persino scalare su cluster Kubernetes man mano che le esigenze crescono.

Per approfondire Docker e Docker Buildx, ti consiglio di iscriverti ai seguenti corsi DataCamp:

Dario Radečić

Autore

Dario Radečić

Senior Data Scientist con base in Croazia. Top Tech Writer con oltre 700 articoli pubblicati, per più di 10 milioni di visualizzazioni. Autore del libro Machine Learning Automation with TPOT.

Argomenti

Correlato