Какие методы уменьшения размера Docker-образа ты используешь?

«Какие методы уменьшения размера Docker-образа ты используешь?» — вопрос из категории Docker, который задают на 23% собеседований Devops Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Размер образа критически влияет на скорость деплоя, безопасность (меньше surface для атак) и стоимость хранилища. Вот мой стандартный набор практик:

1. Многоступенчатые сборки (Multi-stage builds) — основной приём:

# Stage 1: Builder - содержит полный toolchain
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/main ./cmd/api

# Stage 2: Runtime - содержит только бинарник
FROM gcr.io/distroless/static-debian12:nonroot
WORKDIR /
COPY --from=builder --chown=nonroot:nonroot /app/main .
USER nonroot:nonroot
EXPOSE 8080
CMD ["/main"]

Результат: Образ уменьшается с ~1GB (golang:1.21-alpine) до ~5MB (distroless).

2. Выбор минимального базового образа:

  • scratch — пустой образ, только для статически слинкованных бинарников (Go, Rust).
  • distroless (Google) — содержит только runtime и ваше приложение, нет shell или пакетного менеджера. Идеально для продакшена.
  • alpine — маленький, но имеет apk. Подходит, когда нужен shell для debugging.

3. Оптимизация слоёв (Layer optimization):

# ПЛОХО: Каждая команда — новый слой, кэш apt обновляется отдельно
RUN apt-get update
RUN apt-get install -y python3 python3-pip
RUN pip install --no-cache-dir flask gunicorn
RUN rm -rf /var/lib/apt/lists/*

# ХОРОШО: Всё в одном RUN, очистка в том же слое
RUN apt-get update && apt-get install -y 
    python3 
    python3-pip 
    && pip install --no-cache-dir flask gunicorn 
    && apt-get clean 
    && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*

4. Использование .dockerignore: Файл .dockerignore исключает ненужные файлы из контекста сборки, что ускоряет docker build и предотвращает попадание секретов.

# .dockerignore
.git
.gitignore
**/node_modules
**/*.log
**/*.pyc
.env
Dockerfile
README.md
**/test
**/.DS_Store

5. Сканирование и анализ образа: Перед пушем в registry я анализирую образ инструментами:

# Анализ слоёв образа
docker history my-image:latest

# Поиск уязвимостей (интегрирую в CI/CD)
docker scan my-image:latest

# Использование dive для интерактивного анализа
dive my-image:latest

6. Дополнительные продвинутые техники:

  • BuildKit и секреты: Использую --secret для безопасной передачи ключей при сборке.
  • Меньшие альтернативы: Для некоторых задач заменяю nginx на nginx:alpine или даже openresty.

В нашем CI/CD пайплайне эти практики позволили сократить средний размер образов с ~800MB до ~50-150MB, что ускорило деплой в 3-4 раза.