Перейти к содержанию
Innovialabs

Как уменьшить размер Docker-образа: практические способы

Практика3 мин

Коротко

Главный выигрыш дают multi-stage сборка и лёгкий базовый образ (slim, alpine или distroless); затем очистите кеши пакетов в том же слое, добавьте .dockerignore и проверьте слои через dive.

Короткий ответ

Размер образа складывается из базового образа, зависимостей и всего, что осталось в слоях после сборки. Поэтому работают четыре вещи:

  1. Multi-stage build — собирать в одном образе, а в финальный копировать только результат.
  2. Лёгкая база — slim, alpine или distroless вместо полного дистрибутива.
  3. Чистка в том же слое — кеши пакетных менеджеров удалять в той же инструкции RUN, где они появились.
  4. Анализ — смотреть, что реально лежит в слоях, утилитой dive.

Маленький образ быстрее скачивается при деплое, быстрее стартует на новых нодах и содержит меньше пакетов, в которых могут найтись уязвимости.

Multi-stage build

Компиляторы, dev-зависимости и исходники нужны только на этапе сборки. В multi-stage сборке их можно оставить в промежуточной стадии:

FROM node:20 AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build && npm prune --omit=dev

FROM node:20-slim
WORKDIR /app
COPY --from=build /app/node_modules ./node_modules
COPY --from=build /app/dist ./dist
CMD ["node", "dist/server.js"]

Для Go и Rust эффект ещё сильнее: в финальный образ попадает один бинарник, и базой может быть distroless или даже scratch.

Как выбрать базовый образ

БазаЧто внутриКогда подходит
Полный (debian, ubuntu)Shell, пакетный менеджер, много утилитОтладка, сложные системные зависимости
slimУрезанный DebianХороший компромисс для большинства языков
alpinemusl libc, busybox, apkМаленький размер, если зависимости совместимы с musl
distrolessТолько runtime, без shell и пакетного менеджераПродакшен, минимальная поверхность атаки
scratchПустоСтатически собранные бинарники

Нюанс alpine: из-за musl вместо glibc некоторые нативные модули (например, Python-пакеты с C-расширениями) приходится собирать из исходников, и сборка становится дольше, а иногда и образ — больше. Если так происходит, slim часто оказывается практичнее.

Нюанс distroless: внутри нет shell, поэтому docker exec ... sh не сработает. Для отладки используют debug-варианты образов или эфемерные контейнеры.

Чистка кешей и слоёв

Каждая инструкция RUN, COPY и ADD создаёт слой. Файл, удалённый в следующем слое, всё равно остаётся в образе. Поэтому установка и очистка должны быть в одной команде:

RUN apt-get update \
 && apt-get install -y --no-install-recommends curl \
 && rm -rf /var/lib/apt/lists/*

Аналогично:

  • pip install --no-cache-dir ...
  • apk add --no-cache ...
  • npm ci и затем npm cache clean --force в том же RUN, если кеш попадает в образ.

Squashing слоёв (объединение в один) иногда уменьшает размер, но ломает переиспользование кеша слоёв между образами. Обычно multi-stage сборка решает ту же задачу аккуратнее.

.dockerignore

Без него в контекст сборки, а потом через COPY . . и в образ, попадают .git, node_modules, логи, локальные .env и тестовые данные. Минимальный пример:

.git
node_modules
*.log
.env
coverage

Это заодно ускоряет сборку и защищает от случайной утечки секретов в образ.

Как найти, что занимает место

  • docker images — общий размер образа.
  • docker history <image> — размер каждого слоя и команда, которая его создала.
  • dive — интерактивно показывает содержимое каждого слоя, добавленные и изменённые файлы и «потерянное» место. Его можно запускать и в CI, чтобы образ не разрастался незаметно.

Частые ошибки

  • Копировать весь проект до установки зависимостей — ломается кеш слоёв, и каждая сборка ставит всё заново.
  • Оставлять dev-зависимости и инструменты сборки в финальном образе.
  • Удалять файлы отдельной инструкцией RUN и считать, что образ уменьшился.
  • Переходить на alpine вслепую, не проверив нативные зависимости.

Частые вопросы

Если нужен shell и пакетный менеджер внутри контейнера — alpine или slim. Если приложение просто запускается и отладка снаружи вас устраивает — distroless даёт меньше лишнего и меньше потенциальных уязвимостей.

Поможем с этим

Если хотите не разбираться самим, а получить результат — этим мы занимаемся каждый день.

Обсудить проект

Читайте также

Есть идея или задача? Расскажите нам

Ответим в течение рабочего дня и предложим решение. Консультация бесплатная.