Cosa sono i multistadio Docker Costruisce?

Le costruzioni di Docker multistadio sono una caratteristica introdotta in Docker 17.05 che consente di utilizzare più dichiarazioni all'interno di un singolo Dockerfile. Ciascuna istruzione [ inizia una nuova fase, che può avere la propria immagine di base, dipendenze e comandi.

L'idea principale è quella di separare l'ambiente di costruzione dall'ambiente runtime. In una tipica costruzione a singolo stadio, uno sviluppatore installa tutti gli strumenti di costruzione (ad esempio, compilatori, responsabili dei pacchetti, quadri di prova) nella stessa immagine che verrà utilizzata per la produzione.

Vantaggi di Multi-Stage Builds

I vantaggi dell'adozione di multi-stadio costruisce vanno oltre la riduzione delle dimensioni semplici, hanno un impatto profondo sulla sicurezza, la manutenbilità e la velocità di distribuzione.

1. Dimensioni ridotte dell'immagine

Scardando le dipendenze di tempo di costruzione, le costruzioni multistadio spesso si restringono le immagini del 50% al 90%. Ad esempio, un'applicazione Node.js costruita utilizzando l'immagine completa [ (oltre 300MB) può essere ridotta fino a meno di 20MB copiando solo i costi della banda incorporata ] in una base ].

2. Sicurezza migliorata

Ogni pacchetto o strumento installato in un'immagine del contenitore è una potenziale vulnerabilità. Le costruzioni multistadio consentono di escludere compilatori, debugger e librerie di sviluppo dall'immagine finale, riducendo significativamente la superficie di attacco. È anche possibile utilizzare immagini come o ] per la fase di runtime, che contengono solo il minimo nudo per eseguire il binario dell'applicazione.

3. Processo di costruzione semplificato

Tutti i passaggi di costruzione sono definiti in un unico Dockerfile, rendendo il processo autocontenuto e facile da versione. Le tubazioni CI/CD beneficiano di un unico punto di entrata: il Dockerfile. Non c'è bisogno di mantenere script di costruzione separati o passaggi di pulizia manuale.

4. Riproducibilità e coerenza migliorate

Poiché l'intera costruzione viene catturata in un Dockerfile, qualsiasi sviluppatore o sistema può riprodurre gli stessi livelli esatti. L'uso di tag di versione specifici per le immagini di base garantisce inoltre una struttura coerente in ambienti.

Costruire un Dockerfile multistadio: Passo dopo Passo

Questo passaggio copre la creazione di un Dockerfile multistadio di produzione per un'applicazione Node.js e React, che si applica a qualsiasi lingua compilata.

1. Pianifica le tue fasi

Prima di scrivere il codice, mappa le fasi di cui hai bisogno. Una tipica costruzione multi-stadio ha almeno due fasi:

  • Scenario di montaggio[] – installa tutti gli strumenti di costruzione, installa dipendenze e gestisce il comando di build.
  • Scedio di tempo libero[] – utilizza un'immagine di base minima, copia solo gli artefatti costruiti dalla fase del costruttore e definisce il comportamento di runtime.

Per progetti complessi si potrebbero aggiungere fasi intermedie per test, analisi statica o compressione degli asset.

2. Scrivere la fase del costruttore

Iniziare con un'immagine di base che include la porta degli strumenti richiesti. Usare []] tappe[] con ] per richiamarli più tardi.

FROM node:14-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

Punti chiave:

  • Utilizzare per l'installazione di dipendenza deterministica e più rapida.
  • Tenere comandi come strati separati quando possibile per sfruttare il caching.
  • Installare strumenti di build (come TypeScript, webpack) solo in questa fase.

3. Aggiungere una fase di prova intermedia (opzionale)

Per far rispettare la qualità del codice, aggiungere una fase che esegue i test. Questa fase può riutilizzare l'immagine del costruttore o installare strumenti aggiuntivi. Poiché non è la fase finale, i guasti di prova non saranno presenti nell'immagine finale.

FROM builder AS test
RUN npm run test

È possibile eseguire questa fase nel vostro canale CI con per catturare i guasti presto senza costruire l'intera immagine finale.

4. Definire la fase di runtime

Per un'applicazione React, l'immagine runtime può essere un server Nginx. Per un'API backend, potrebbe essere un'immagine di base distroless o un Alpine minimale con il runtime Node.js. Copia solo gli artefatti essenziali utilizzando .

FROM nginx:alpine
COPY --from=builder /app/build /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

Se avete bisogno del runtime Node.js, evitare di copiare [ dal costruttore; invece reinstallare dipendenze di produzione nella fase di runtime:

FROM node:14-alpine AS runtime
WORKDIR /app
COPY --from=builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

5. Costruisci e testa l'immagine

Costruire l'immagine finale utilizzando il comando standard:

docker build -t myapp:latest .

Per verificare la dimensione, eseguire e confrontare con una singola fase di costruzione.

docker run -d -p 8080:80 myapp:latest
curl http://localhost:8080

Migliori Pratiche per le Costruzioni Multi-Stage

  • ]Utilizzare i tag di immagine di base specifici[] – evitare [] per evitare sorprese. Preferire o .
  • Ottimizzare il cache dei livelli[[] – copia [ e [] prima del resto del codice sorgente in modo che lo strato non sia invalidato solo quando le dipendenze cambiano.
  • Leverage BuildKit[[] – permettono a BuildKit con [] per le costruzioni più veloci, il caching inline e il miglior parallelismo.
  • Crea più fasi finali per ambienti diversi[[] – ad esempio, una fase di sviluppo con strumenti di debug e una fase di produzione con un'immagine di base indurita.
  • Utilizza ] per le costruzioni di sviluppo – nello sviluppo puoi fermarti nella fase per ottenere mappe di ricarica e di origine dal vivo, poi ricostruirti con per la produzione.
  • Tenere segreti dalle immagini[[]] – utilizzare la bandiera di Docker BuildKit [] se è necessario passare le credenziali durante la costruzione; mai includerle nell'immagine finale.

Modelli comuni e casi d'uso

Lingue collegate (Va, Rust, C++)

Per i binari statici, la fase runtime può usare [ (immagine base vuota). Solo il binario e forse un file di configurazione vengono copiati. Esempio per Go:

FROM golang:1.20-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

FROM scratch
COPY --from=builder /app/myapp /myapp
ENTRYPOINT ["/myapp"]

Applicazioni Python

Utilizzare una fase di costruzione con per installare dipendenze e compilare eventuali estensioni C, quindi copiare solo i pacchetti installati in una fase runtime:

FROM python:3.11-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --user -r requirements.txt
COPY . .

FROM python:3.11-slim
COPY --from=builder /root/.local /root/.local
COPY --from=builder /app /app
ENV PATH=/root/.local/bin:$PATH
CMD ["python", "app.py"]

Fronte con server API

Costruire sia frontend che backend in un Dockerfile. Utilizzare fasi di costruttore separate per ciascuno, quindi copiare entrambi i manufatti in un'unica immagine runtime:

FROM node:14-alpine AS frontend-builder
WORKDIR /app
COPY frontend/package*.json ./
RUN npm ci
COPY frontend/ .
RUN npm run build

FROM node:14-alpine AS api-builder
WORKDIR /app
COPY api/package*.json ./
RUN npm ci
COPY api/ .
RUN npm run build

FROM node:14-alpine
WORKDIR /app
COPY --from=frontend-builder /app/build ./public
COPY --from=api-builder /app/dist ./dist
RUN npm ci --only=production
EXPOSE 3000
CMD ["node", "dist/server.js"]

Risoluzione dei problemi Multi-Stage Builds

  • Layer caching not working[[] – assicura [[]] ordina dipendenze prima del codice sorgente.
  • Artifatto non trovato[[] – verifica i percorsi nella dichiarazione [. La fase del costruttore deve produrre output nella posizione specificata.
  • Le perdite di segreto[[]] – non copiano mai interi directory che potrebbero contenere [] o []. Copiano esplicitamente solo i file necessari.
  • Le immagini finali grandi nonostante il multistadio[[]] – controlla se si copia accidentalmente o l'intera fonte.

Conclusioni

Le costruzioni multistadio Docker sono un punto cardine della moderna containerizzazione, che consente di spedire immagini magre e sicure mantenendo il processo di costruzione semplice e documentato in un unico Dockerfile. Separando le preoccupazioni tra la costruzione e il tempo di esecuzione, è possibile ridurre drasticamente le dimensioni dell'immagine, migliorare la sicurezza e ottimizzare l'efficienza CI/CD. Le tecniche qui indicate si applicano a quasi qualsiasi stack, se si stanno costruendo Node.

Per ulteriori dettagli, fare riferimento alla Docker documentazione di costruzione multistadio[ e la [] Guida di pratiche migliori di Dockerfile[[]. Gli esempi del mondo reale sono disponibili anche nella documentazione della libreria di Docker.