Как оптимизировать размер Docker-образа (multi-stage build)?
Подробный ответ
Зачем уменьшать image
Маленький Docker image быстрее собирается, передаётся в registry и запускается на серверах. В нём меньше лишних библиотек и утилит, а значит ниже поверхность атаки и проще управлять зависимостями.
Что такое multi-stage build
Multi-stage build использует несколько инструкций FROM в одном Dockerfile. Первый stage собирает приложение, а второй — финальный runtime-образ — получает только нужные файлы через COPY --from.
Пример для Python
FROM python:3.12-slim AS builder
WORKDIR /build
COPY requirements.txt .
RUN pip wheel --no-cache-dir --wheel-dir /wheels -r requirements.txt
FROM python:3.12-slim AS runtime
WORKDIR /app
COPY --from=builder /wheels /wheels
RUN pip install --no-cache-dir /wheels/*
COPY . .
RUN useradd --create-home appuser
USER appuser
CMD ["python", "main.py"]Пример для frontend
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM nginx:alpine AS runtime
COPY --from=builder /app/dist /usr/share/nginx/html
CMD ["nginx", "-g", "daemon off;"]Другие способы оптимизации
использовать подходящий минимальный базовый image, учитывая совместимость библиотек;
настроить
.dockerignoreи не отправлять в build context лишние файлы;копировать сначала файлы зависимостей, а затем код, чтобы эффективно использовать Docker layer cache;
не хранить в runtime image компиляторы, тесты, исходники зависимостей и секреты;
запускать приложение не от root-пользователя.
Как проверить размер
docker image ls
docker image history my-app:latestКак ответить на собеседовании
Для уменьшения Docker image я использую multi-stage build: в builder-этапе устанавливаю компиляторы и собираю артефакты, а в финальный runtime-этап копирую только то, что нужно для запуска. Дополнительно настраиваю .dockerignore, порядок COPY для layer cache и запускаю контейнер не от root.
Оцени свой прогресс