Docker Image Optimization — Optimalizácia kontajnerových obrazov
Veľkosť Docker obrazu priamo ovplyvňuje čas nasadenia, spotrebu úložiska a bezpečnostnú plochu útoku. Menší obraz = rýchlejší deploy, menej zraniteľností a nižšie náklady. V tomto článku si ukážeme praktické techniky na zmenšenie obrazov z stoviek megabajtov na desiatky.
Prečo optimalizovať?
- Rýchlejšie buildy a deploymenty — menej dát na prenos
- Menšia attack surface — menej balíkov = menej zraniteľností
- Nižšie náklady — úložisko v registri a sieťový prenos nie sú zadarmo
- Rýchlejší cold start — dôležité pre serverless a auto-scaling
Multi-stage Builds
Multi-stage build je najúčinnejšia technika. Oddelíte build prostredie od runtime prostredia.
❌ Pred optimalizáciou (~900 MB)
FROM node:20
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
EXPOSE 3000
CMD ["node", "dist/server.js"]
✅ Po optimalizácii (~150 MB)
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
RUN npm prune --production
# Runtime stage
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./
USER node
EXPOSE 3000
CMD ["node", "dist/server.js"]
Go aplikácia — ešte dramatickejší rozdiel
# Build stage
FROM golang:1.22-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o server .
# Runtime stage (~12 MB namiesto ~800 MB)
FROM scratch
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]
Výber base image
Voľba base image má obrovský vplyv na výslednú veľkosť:
| Base Image | Veľkosť | Použitie |
|---|---|---|
ubuntu:24.04 |
~78 MB | Vývoj, debugging |
debian:bookworm-slim |
~74 MB | Stabilné prostredie |
alpine:3.20 |
~7 MB | Minimálna veľkosť |
distroless/static |
~2 MB | Statické binárky (Go, Rust) |
distroless/cc |
~20 MB | C/C++ aplikácie |
distroless/java21 |
~190 MB | Java aplikácie |
scratch |
0 MB | Len statická binárka |
Alpine vs Debian
Alpine používa musl libc namiesto glibc. To môže spôsobiť problémy s niektorými aplikáciami:
# Alpine — menší, ale pozor na kompatibilitu
FROM python:3.12-alpine
RUN apk add --no-cache gcc musl-dev # Niekedy treba kompilovať C extensions
# Debian slim — väčší, ale kompatibilnejší
FROM python:3.12-slim
Kedy Alpine: Node.js, Go, jednoduché Python aplikácie Kedy Debian slim: Python s C extensions, ML knižnice, legacy aplikácie
Distroless images
Google distroless obrazy neobsahujú shell, package manager ani žiadne utility. Obsahujú len runtime a CA certifikáty:
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 go build -o server .
FROM gcr.io/distroless/static-debian12
COPY --from=builder /app/server /
CMD ["/server"]
.dockerignore
Bez .dockerignore sa do build kontextu kopíruje všetko, vrátane node_modules, .git a testov:
.git
.gitignore
node_modules
npm-debug.log
Dockerfile
docker-compose.yml
.env
.env.*
*.md
tests/
coverage/
.vscode/
.idea/
dist/
Rozdiel môže byť dramatický — build kontext z 500 MB na 5 MB.
Layer Caching
Docker cachuje každú vrstvu. Poradie inštrukcií v Dockerfile je kľúčové:
❌ Zlé poradie — cache sa invaliduje pri každej zmene kódu
FROM node:20-alpine
WORKDIR /app
COPY . . # Zmena akéhokoľvek súboru invaliduje cache
RUN npm ci # Musí sa spustiť znovu
✅ Správne poradie — dependencies sa cachujú
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./ # Zmení sa len ak sa zmenia dependencies
RUN npm ci # Cachované ak package.json nezmenený
COPY . . # Len kód aplikácie
Ďalšie tipy pre caching
# Používajte --mount=type=cache pre build cache
RUN --mount=type=cache,target=/root/.npm npm ci
# Kombinujte RUN príkazy na redukciu vrstiev
RUN apt-get update && \
apt-get install -y --no-install-recommends curl ca-certificates && \
rm -rf /var/lib/apt/lists/*
Ďalšie optimalizačné techniky
Odstránenie nepotrebných súborov
RUN apt-get update && \
apt-get install -y --no-install-recommends build-essential && \
make build && \
apt-get purge -y build-essential && \
apt-get autoremove -y && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
Používajte konkrétne tagy
# ❌ Nepredvídateľné
FROM node:latest
# ✅ Reprodukovateľné
FROM node:20.11.1-alpine3.19
Komprimácia s docker-slim
# Automatická optimalizácia obrazu
docker-slim build --target myapp:latest --tag myapp:slim
# Typicky 5-30x zmenšenie
Security Scanning
Optimalizovaný obraz by mal byť aj bezpečný. Skenujte obrazy v CI/CD:
# Trivy — rýchly a komplexný skener
trivy image myapp:latest
# Grype — alternatíva od Anchore
grype myapp:latest
# Docker Scout — natívny v Docker Desktop
docker scout cves myapp:latest
Integrácia do CI pipeline (GitHub Actions)
- name: Build image
run: docker build -t myapp:${{ github.sha }} .
- name: Scan for vulnerabilities
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
exit-code: 1
severity: HIGH,CRITICAL
Porovnanie — pred a po
| Metrika | Pred | Po |
|---|---|---|
| Veľkosť obrazu | 950 MB | 85 MB |
| Build čas (cold) | 120s | 45s |
| Build čas (cached) | 90s | 8s |
| CVE (critical) | 12 | 0 |
| CVE (high) | 34 | 3 |
| Deploy čas | 45s | 12s |
Záver
Optimalizácia Docker obrazov nie je luxus — je to best practice. Začnite multi-stage buildmi, zvoľte správny base image, nastavte .dockerignore a dbajte na poradie vrstiev. Výsledkom budú rýchlejšie deploymenty, bezpečnejšie aplikácie a nižšie prevádzkové náklady.