🟡 Intermediate

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.mod pred 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 images a docker history
  • Zvážte scratch base 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.