DOCKER
#docker#dockerfile#optimization#devops

Как уменьшить размер Docker-образа: alpine, кеш и порядок инструкций

Практические приёмы уменьшения Docker-образов: alpine-образы, кеширование слоёв и правильный порядок инструкций Dockerfile.

Как использовать

  1. Выберите базовый образ с суффиксом -alpine (node:22-alpine, nginx:alpine и т.д.), если совместимость с glibc не критична.
  2. В Dockerfile сначала копируйте только файлы зависимостей (package.json, requirements.txt), затем установите зависимости, потом копируйте остальной код.
  3. После сборки проверяйте размер: docker image ls и docker history имя_образа.

Большой Docker-образ дольше качается при деплое и docker pull, занимает больше места в registry и на нодах и увеличивает поверхность атаки. Проблема возникает при сборке из «тяжёлого» базового образа (например полный Debian/Ubuntu) и при неверном порядке инструкций: любое изменение кода инвалидирует кеш и заставляет заново ставить зависимости. Симптомы: сборка после каждого коммита долго идёт, образ на сотни мегабайт, в docker history видно дублирование слоёв. Ниже — выбор Alpine-образов, как работает кеш слоёв, правильный порядок COPY и RUN по Best practices и оптимизации кеша, плюс команды проверки размера.

Решение

Практические приёмы: минимальный базовый образ (Alpine при возможности), редко меняющиеся шаги в начало Dockerfile, часто меняющиеся (код) — в конец.

Почему размер образа важен

Большой образ дольше качается, занимает место, добавляет лишние пакеты и уязвимости. В документации Docker рекомендуется минимальный образ, достаточный для приложения.

Alpine vs Debian

Debian-based (ubuntu:22.04, debian:bookworm-slim) — сотни мегабайт. Alpine — минимальный дистрибутив (образ меньше 6 MB). Для Node, Nginx, Postgres есть официальные образы -alpine.

# Debian — образ заметно больше
FROM node:22-bookworm-slim
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]
# Alpine — меньше размер
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
CMD ["node", "server.js"]

Кеш слоёв и порядок инструкций

При изменении инструкции или её зависимостей пересобираются этот слой и все следующие. Правило: редко меняющееся и тяжёлое — в начало, часто меняющееся (код) — в конец.

Неправильно — сначала COPY . ., тогда любое изменение файла ломает кеш для RUN npm ci и ниже:

FROM node:22-alpine
WORKDIR /app
COPY . .
RUN npm ci --omit=dev
RUN npm run build
CMD ["node", "dist/server.js"]

Правильно — сначала только файлы зависимостей, установка, потом код:

FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY . .
RUN npm run build
CMD ["node", "dist/server.js"]

Слой с npm ci кешируется, пока не меняются lock-файлы. То же для Python: сначала requirements.txt, потом pip install, потом код.

Проверка

  1. Размер образа после сборки:
docker build -t myapp:latest .
docker image ls myapp:latest

Колонка SIZE показывает размер. Сравните до и после перехода на Alpine и смены порядка COPY.

  1. История слоёв — какие слои сколько занимают:
docker history myapp:latest

По выводу видно, где уменьшать: меньше RUN, объединение команд, более лёгкий базовый образ.

  1. Проверка кеша — измените один файл в src/, пересоберите образ. При правильном порядке пересоберутся только слои начиная с COPY . .; при неправильном — с самого первого изменённого слоя (например с npm ci). Время сборки во втором случае заметно больше.

Типичные ошибки

  • Сначала COPY . . — любой правка в проекте инвалидирует кеш для всех следующих слоёв; зависимости ставятся заново при каждом изменении кода. Копируйте только package.json/lock-файлы, делайте RUN npm ci, затем COPY . ..
  • Тяжёлый базовый образ без необходимости — для многих стеков достаточно -alpine или -slim. Используйте полный образ только если нужны пакеты или glibc из полного дистрибутива.
  • Много отдельных RUN — каждый RUN добавляет слой. Объединяйте команды в один RUN и при необходимости очищайте кеш пакетного менеджера в том же слое (apt-get clean, rm -rf /var/cache и т.п.), чтобы не раздувать образ.

Где применять

  • Prod / CI: сборка образов для деплоя; меньший образ — быстрее pull и меньше места.
  • Разработка: тот же Dockerfile; правильный порядок COPY ускоряет пересборку при изменении кода.

Связанные сниппеты: Volumes vs bind mounts в Compose, Сеть между контейнерами.

Ссылки: Building best practices, Optimize cache usage, Dockerfile reference (FROM).