Wat zijn Multi-Stage Docker Builds?

Multi-stage Docker builds zijn een functie geïntroduceerd in Docker 17.05 die u toelaat om meerdere statements te gebruiken binnen een enkele Dockerfile. Elke instructie begint een nieuwe fase, die zijn eigen basisbeeld, afhankelijkheden en commando's kan hebben. Artefacten kunnen selectief worden gekopieerd van de ene fase naar de andere, terwijl de uiteindelijke afbeelding alleen behoudt wat strikt noodzakelijk is voor het uitvoeren van de toepassing. Deze aanpak elimineert de noodzaak om handmatig keten Dockerfiles of vertrouwen op complexe bouwscripts, en het drastisch vermindert de grootte van de afbeelding door het uitsluiten van compilers, ontwikkeling bibliotheken en tussenliggende bestanden.

Het kernidee is om de bouwomgeving te scheiden van de runtime omgeving. In een typische single-stage build installeert een ontwikkelaar alle bouwgereedschappen (bijv. compilers, pakketmanagers, testkaders) in hetzelfde beeld dat gebruikt zal worden voor de productie. Dat blaast het beeld op en verhoogt het aanvalsoppervlak. Multi-stage builds lost dit op door gebruik te maken van een dikke, feature-rijke afbeelding voor compilatie en vervolgens alleen de resulterende artefacten te kopiëren in een minimale runtime afbeelding zoals of .

Voordelen van Multi-Stage Builds

De voordelen van de invoering van meerfasenbouw gaan verder dan eenvoudige groottevermindering. Ze hebben een grote impact op de veiligheid, de houdbaarheid en de inzetsnelheid.

1. Verminderde afbeeldingsgrootte

Door bouw-tijd afhankelijkheden weg te gooien, kan multi-stage builds vaak beelden met 50% tot 90% verkleinen. Bijvoorbeeld, een Node.js-toepassing die is gebouwd met behulp van de volledige afbeelding (meer dan 300MB) kan worden geslankt tot minder dan 20MB door alleen de ingebouwde map te kopiëren in een basis. Deze opslagbesparing vertaalt zich direct naar snellere trektijden, minder netwerkbandbreedte en lagere registerkosten.

2. Verbeterde beveiliging

Elk geïnstalleerd pakket of gereedschap in een container image is een potentiële kwetsbaarheid. Meertraps builds kunt u compilers, debuggers en ontwikkeling bibliotheken uitsluiten van de uiteindelijke afbeelding, waardoor het aanvalsoppervlak aanzienlijk wordt verminderd. U kunt zelfs afbeeldingen gebruiken zoals of voor de runtime fase, die slechts het absolute minimum bevatten om de toepassing binair uit te voeren.

3. Gestroomlijnd gebouwd proces

Alle bouwstappen worden gedefinieerd in één Dockerfile, waardoor het proces zelfstandig en eenvoudig te versturen is. CI/CD-pijpleidingen profiteren van één ingangspunt: het Dockerfile. Het is niet nodig om aparte bouwscripts of handmatige opruimstappen te behouden.

4. Verbeterde herproduceerbaarheid en samenhang

Omdat de gehele bouw in één Dockerfile is vastgelegd, kan elke ontwikkelaar of systeem exact dezelfde lagen reproduceren. Het gebruik van specifieke versietags voor basisafbeeldingen garandeert een consistente opbouw in verschillende omgevingen.

Bouwen van een multi-stage-dockerbestand: Stap voor stap

Deze doorloop omvat de creatie van een productie-ready meertraps Dockerfile voor een Node.js en React applicatie. Dezelfde principes gelden voor elke gecompileerde taal.

1. Plan je fases

Voordat u code schrijft, kunt u de gewenste etappes in kaart brengen. Een typische multi-stage bouw heeft minstens twee fasen:

  • Builder stage
  • Tijdstrap

Voor complexe projecten kunt u tussenstadia toevoegen voor tests, statische analyse, of activa compressie.

2. Schrijf het bouwstadium

Begin met een basisafbeelding die de benodigde gereedschapsketen bevat. Gebruik genoemde stadia met om ze later te verwijzen. Voor Node.js:

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

Belangrijkste punten:

  • Gebruik voor deterministische, snellere afhankelijkheidsinstallatie.
  • Houd commando's als aparte lagen indien mogelijk om caching te gebruiken.
  • Installeer bouwgereedschappen (zoals TypeScript, webpack) in deze fase.

3. Voeg een tussenfase (facultatief) toe

Om de codekwaliteit te handhaven, voeg een fase toe die tests uitvoert. Deze fase kan het bouwbeeld hergebruiken of extra hulpmiddelen installeren. Omdat het niet de laatste fase is, zullen testfouten niet aanwezig zijn in de uiteindelijke afbeelding.

FROM builder AS test
RUN npm run test

Je kunt deze fase in je CI-pijpleiding uitvoeren met ] om mislukkingen vroegtijdig te vangen zonder het volledige definitieve beeld te bouwen.

4. Definieer het startstadium

Voor een React-applicatie kan het runtime image een Nginx-server zijn. Voor een backend API kan het een distroloos basisimage zijn of een minimale Alpine met de Node.js runtime. Kopieer alleen de essentiële artefacten met .

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

Als u de Node.js runtime nodig heeft, vermijd het kopiëren van de bouwer; in plaats daarvan herinstalleer productieafhankelijkheden in de runtime fase:

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. Bouw en test de afbeelding

Bouw de laatste afbeelding met het standaard commando:

docker build -t myapp:latest .

Om de grootte te verifiëren, moet u uitvoeren en vergelijken met een enkele fase. Draai de container en bevestig dat de toepassing correct reageert:

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

Beste praktijken voor multi-fase gebouwen

  • Gebruik specifieke basisafbeeldingstags
  • Optimaliseer laagcaching
  • HefboombouwKit
  • Maak meerdere eindstadia voor verschillende omgevingen . Bijvoorbeeld, een ontwikkelingsfase met debuggereedschappen en een productiefase met een gehard basisbeeld.
  • Gebruik voor ontwikkelingsbouw .In ontwikkeling kun je stoppen bij om live herladen en bronkaarten te krijgen, dan herbouwen met voor productie.
  • Houd geheimen uit afbeeldingen .Binnen de vlag van Docker BuildKit als je referenties moet doorgeven tijdens de bouw; neem ze nooit op in de uiteindelijke afbeelding.

Gemeenschappelijke patronen en gebruiks gevallen

Gecompileerde talen (Go, Rust, C++)

Voor statische binaire bestanden kan de runtime-fase (leeg basisbeeld) gebruikt worden. Alleen het binaire en misschien een configuratiebestand worden gekopieerd. Voorbeeld voor 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"]

Python-toepassingen

Gebruik een bouwfase met om afhankelijkheden te installeren en eventuele C-extensies te compileren, kopieer dan alleen de geïnstalleerde pakketten naar een runtime fase:

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"]

Frontend met API-server

Bouw zowel frontend als backend in één Dockerfile. Gebruik aparte bouwfasen voor elk, kopieer vervolgens beide artefacten in één runtime image:

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"]

Problemen met het oplossen van multi-fase gebouwen

  • Laag cachen werkt niet
  • Kunst niet gevonden
  • Geheime lekkage .. Kopieer nooit volledige mappen die of bevatten. Expliciet kopiëren alleen benodigde bestanden.
  • Grote definitieve afbeeldingen ondanks multi-stage . Controleer of u per ongeluk of de gehele bron kopieert. Gebruik om de laaggrootte te zien.

Conclusie

Multi-stage Docker builds zijn een hoeksteen van moderne containerization. Ze stellen u in staat om te schip lean, veilige beelden terwijl het bouwen proces eenvoudig en gedocumenteerd in een enkele Dockerfile. Door het scheiden van zorgen tussen build en runtime, kunt u drastisch verminderen beeldgrootte, de beveiliging te verbeteren en de CI / CD-pijpleidingen stroomlijnen. De technieken die hier worden getoond zijn van toepassing op bijna elke stapel .of u bouwt Node.js, Go, Python, Java, of frontend toepassingen. Begin met het omzetten van uw bestaande Dockerfiles naar multi-stage bouwt, en u zult onmiddellijk verbeteringen in bouwsnelheid, implementatie efficiëntie en algemene infrastructuur kosten.

Zie voor meer details de officiële Docker multi-stage bouwdocumentatie en de Dokterfile best practices guide. Real-world voorbeelden zijn ook beschikbaar in de Docker Library documentation[.