Ответ
Для создания минимальных Docker-образов я использую несколько проверенных техник:
1. Многоступенчатая сборка (multi-stage build):
# Этап сборки
FROM golang:1.21-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 app .
# Финальный образ
FROM alpine:3.18
RUN apk --no-cache add ca-certificates tzdata
WORKDIR /root/
COPY --from=builder /app/app .
CMD ["./app"]
2. Использование scratch-образов для статических бинарников:
FROM scratch
COPY --from=builder /app/app /app
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/app"]
3. Ключевые оптимизации, которые я применяю:
-
.dockerignoreдля исключения ненужных файлов:.git node_modules *.log Dockerfile README.md -
Объединение RUN-команд в Alpine:
RUN apk add --no-cache python3 py3-pip && pip3 install --no-cache-dir flask && apk del py3-pip -
Использование distroless-образов от Google для Java/Python:
FROM gcr.io/distroless/python3-debian12 COPY app.py . CMD ["app.py"]
Результаты:
- Go-приложение: ~5-10 МБ (Alpine) или ~2-5 МБ (scratch)
- Python-приложение: ~80-100 МБ (slim) vs 1+ ГБ (полный образ)
- Java-приложение: ~150 МБ (JRE slim) vs 500+ МБ (полный JDK)
Я всегда проверяю размер образа командой docker images и анализирую слои через docker history <image>.