Multi-stage Builds — Optimalizácia Docker obrazov
Multi-stage builds sú technika v Dockerfile, ktorá umožňuje drasticky zmenšiť výsledné Docker images tým, že oddelí build prostredie od runtime prostredia. Výsledok: menšie, bezpečnejšie a rýchlejšie obrazy.
Čo je Multi-stage Build?
Tradičný Dockerfile obsahuje všetko v jednom image — kompilátor, build nástroje, zdrojový kód aj finálnu aplikáciu. Multi-stage build rozdeľuje tento proces do viacerých fáz (stages). Každá fáza začína vlastným FROM a z predchádzajúcej fázy si skopíruje len to, čo potrebuje.
Princíp je jednoduchý: builduj v jednom kontajneri, spúšťaj v druhom.
Ako funguje
Príklad pre Go aplikáciu:
# Fáza 1: Build
FROM golang:1.22 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app
# Fáza 2: Runtime
FROM alpine:3.19
RUN apk add --no-cache ca-certificates
COPY --from=builder /app /app
ENTRYPOINT ["/app"]
Build fáza používa plný Go image (800 MB), ale finálny image obsahuje len Alpine (5 MB) a skompilovanú binárku. Výsledok: image pod 15 MB namiesto 800+ MB.
Príklad pre Node.js:
# Build
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Runtime
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --production
COPY --from=build /app/dist ./dist
CMD ["node", "dist/index.js"]
Tu sa dev dependencies (TypeScript, webpack, testing framework) nenachádzajú vo výslednom image — len produkčné závislosti a skompilovaný kód.
Praktické použitie
Builder pattern pred multi-stage builds vyžadoval dva samostatné Dockerfile súbory a shell skript, ktorý extrahoval artefakty. Multi-stage to rieši elegantne v jednom súbore.
Porovnanie veľkostí obrazov:
| Prístup | Node.js app | Go app |
|---|---|---|
| Jednoduchý Dockerfile | ~1.1 GB | ~850 MB |
| Multi-stage | ~180 MB | ~12 MB |
| Multi-stage + distroless | ~130 MB | ~8 MB |
Distroless images od Google (gcr.io/distroless) idú ešte ďalej — neobsahujú shell, package manager ani žiadne nepotrebné utility. Maximálna minimalizácia attack surface.
Môžete buildiť konkrétnu fázu:
docker build --target builder -t myapp:build .
Best Practices
- Vždy oddeľte build a runtime fázy — menej vrstiev = menší image
- Kopírujte
package.json/go.modpred zdrojovým kódom — lepší layer caching - Používajte Alpine alebo distroless base images pre runtime fázu
- Pomenúvajte fázy (
AS builder) pre čitateľnosť a možnosť targetovaného buildu - Pravidelne kontrolujte veľkosť images pomocou
docker imagesadocker history - Zvážte
scratchbase image pre staticky linkované binárky (Go, Rust)
Multi-stage builds sú štandard v modernom Docker workflow. Investícia do optimalizácie Dockerfile sa vráti v rýchlejších deployoch, nižších nákladoch na storage a lepšej bezpečnosti.