1. Multi-stage Builds
Multi-stage builds cho phép sử dụng nhiều FROM statements trong một Dockerfile. Chỉ artifacts cần thiết được copy vào final image, giúp giảm kích thước image đáng kể.
Ví dụ: Go Application
# Stage 1: Build 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 -o /app/server .Stage 2: Production (chỉ chứa binary)
FROM scratch COPY --from=builder /app/server /server EXPOSE 8080 ENTRYPOINT ["/server"]
Kết quả: Image chỉ ~10MB thay vì ~300MB
Ví dụ: React Application
# Stage 1: Install dependencies FROM node:20-alpine AS deps WORKDIR /app COPY package*.json ./ RUN npm ciStage 2: Build
FROM node:20-alpine AS builder WORKDIR /app COPY --from=deps /app/node_modules ./node_modules COPY . . RUN npm run build
Stage 3: Production (Nginx serve static files)
FROM nginx:1.27-alpine COPY --from=builder /app/build /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 CMD ["nginx", "-g", "daemon off;"]
Kết quả: Image ~25MB thay vì ~1.2GB
Ví dụ: Java Spring Boot
# Stage 1: Build với Maven FROM maven:3.9-eclipse-temurin-21 AS build WORKDIR /app COPY pom.xml . RUN mvn dependency:go-offline -B COPY src ./src RUN mvn package -DskipTests -BStage 2: Production
FROM eclipse-temurin:21-jre-alpine RUN addgroup -S spring && adduser -S spring -G spring WORKDIR /app COPY --from=build --chown=spring:spring /app/target/*.jar app.jar USER spring EXPOSE 8080 HEALTHCHECK --interval=30s --timeout=10s --retries=3
CMD wget --spider -q http://localhost:8080/actuator/health || exit 1 ENTRYPOINT ["java", "-jar", "app.jar"]
2. Layer Caching Optimization
Docker cache mỗi layer. Nếu một layer thay đổi, tất cả layers phía sau bị invalidate.
Chiến lược tối ưu cache
# ❌ Bad: Mọi thay đổi code invalidate npm install COPY . . RUN npm ci✅ Good: Chỉ reinstall khi package.json thay đổi
COPY package*.json ./ RUN npm ci COPY . .
# ✅ Tách system dependencies và app dependencies
FROM python:3.12-slim
# Layer 1: System deps (ít thay đổi)
RUN apt-get update && \
apt-get install -y --no-install-recommends gcc libpq-dev && \
rm -rf /var/lib/apt/lists/*
# Layer 2: Python deps (thay đổi khi requirements.txt đổi)
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# Layer 3: App code (thay đổi thường xuyên)
COPY . .
3. So sánh Base Images
Alpine Linux
# ~7MB, dùng musl libc thay vì glibc FROM alpine:3.20 RUN apk add --no-cache nodejs npmƯu điểm: Rất nhỏ, ít attack surface
Nhược điểm: Có thể gặp compatibility issues với glibc-dependent packages
Distroless (Google)
# Không có shell, package manager, chỉ chứa runtime FROM gcr.io/distroless/nodejs20-debian12 COPY --from=builder /app /app CMD ["server.js"]Ưu điểm: Cực kỳ secure, nhỏ
Nhược điểm: Không thể exec vào debug
Scratch
# Empty image, 0 bytes FROM scratch COPY --from=builder /app/binary /binary ENTRYPOINT ["/binary"]Chỉ cho static binaries (Go, Rust)
4. Security Scanning
Trivy
# Scan image cho vulnerabilities trivy image myapp:latestScan với severity filter
trivy image --severity HIGH,CRITICAL myapp:latest
Scan Dockerfile
trivy config Dockerfile
Fail nếu có critical vulnerabilities
trivy image --exit-code 1 --severity CRITICAL myapp:latest
Docker Scout
# Analyze image docker scout quickview myapp:latestChi tiết vulnerabilities
docker scout cves myapp:latest
So sánh 2 images
docker scout compare --to myapp:v1.0 myapp:v2.0
5. BuildKit Features
# Enable BuildKit export DOCKER_BUILDKIT=1Hoặc trong daemon.json
{ "features": { "buildkit": true } }
# Cache mount - cache package downloads
RUN --mount=type=cache,target=/root/.npm \
npm ci
# Secret mount - build với secrets mà không bị lưu trong layer
RUN --mount=type=secret,id=npmrc,target=/root/.npmrc \
npm ci
# SSH mount - dùng SSH keys trong build
RUN --mount=type=ssh \
git clone [email protected]:private/repo.git
# Build với secrets
docker build --secret id=npmrc,src=.npmrc -t myapp .
# Build với SSH
docker build --ssh default -t myapp .
6. Chiến lược tối ưu theo ngôn ngữ
Node.js
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY . .
USER node
CMD ["node", "server.js"]
Python
FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
USER nobody
CMD ["python", "app.py"]
Go
FROM golang:1.22-alpine AS build WORKDIR /app COPY go.* ./ RUN go mod download COPY . . RUN CGO_ENABLED=0 go build -ldflags="-s -w" -o /server .
FROM scratch COPY --from=build /server /server ENTRYPOINT ["/server"]
7. Tổng kết
Trong bài này, bạn đã nắm được:
Multi-stage builds cho Go, Node.js, Java
Layer caching optimization strategies
So sánh Alpine vs Distroless vs Scratch
Security scanning với Trivy và Docker Scout
BuildKit features: cache mount, secret mount
Chiến lược tối ưu theo từng ngôn ngữ
Bài tiếp theo sẽ hướng dẫn làm việc với Docker Registry, Docker Hub và Private Registry.