6. Слои и кэш
Каждый Docker-образ состоит из слоёв — неизменяемых (иммутабельных) файловых систем, объединённых с помощью Union File System. Понимание механизма слоёв и кеширования позволяет значительно ускорить сборку образов.
Как формируются слои
Заголовок раздела «Как формируются слои»Каждая инструкция RUN, COPY и ADD в Dockerfile создаёт новый слой. Инструкции FROM, ENV, ARG, EXPOSE, CMD, ENTRYPOINT, WORKDIR — создают мета-слои, не занимающие дискового пространства.
FROM node:20-alpine # Слой 1: базовый образ (~130 MB)WORKDIR /app # Мета-данныеCOPY package*.json ./ # Слой 2: файлы зависимостей (~10 KB)RUN npm ci # Слой 3: node_modules (~50 MB)COPY . . # Слой 4: исходный код (~5 MB)CMD ["node", "server.js"] # Мета-данныеМеханизм кеширования
Заголовок раздела «Механизм кеширования»Docker кеширует каждый слой. При повторной сборке Docker проверяет каждую инструкцию:
- Если инструкция и её контекст не изменились → используется кеш
- Если что-то изменилось → пересобираются этот и все последующие слои
Это ключевое правило: как только кеш инвалидируется, все последующие слои пересобираются заново.
docker build .
Step 1/6 : FROM node:20-alpine ---> 3a1e2b23a4f1 # кешStep 2/6 : WORKDIR /app ---> Using cache # кешStep 3/6 : COPY package*.json ./ ---> Using cache # кеш (package.json не изменился)Step 4/6 : RUN npm ci ---> Using cache # кеш (зависимости не изменились!)Step 5/6 : COPY . . ---> abc123def456 # пересборка (код изменился)Step 6/6 : CMD ["node", "server.js"] ---> Rebuilt # пересборкаНеправильный порядок vs правильный
Заголовок раздела «Неправильный порядок vs правильный»Порядок инструкций критически важен для эффективного кеширования:
❌ Плохой Dockerfile — долгая пересборка:
FROM node:20-alpineWORKDIR /appCOPY . . # Копируем всё сразу — кеш сбивается при любом изменении кода!RUN npm install # Пересобирается каждый разCMD ["node", "app.js"]✅ Хороший Dockerfile — быстрое кеширование:
FROM node:20-alpineWORKDIR /appCOPY package*.json ./ # Сначала только зависимостиRUN npm ci # Этот слой кешируется, если package.json не менялсяCOPY . . # Код копируем ПОСЛЕ установки зависимостейCMD ["node", "app.js"]Теперь при изменении только кода приложения npm install не нужно запускать заново — его результат уже закеширован.
Инспектирование слоёв
Заголовок раздела «Инспектирование слоёв»# История слоёв образа с размерамиdocker history nginx
IMAGE CREATED CREATED BY SIZEa6bd71f48f68 3 weeks ago /bin/sh -c #(nop) CMD ["nginx" "-g" "daemon... 0B<missing> 3 weeks ago /bin/sh -c #(nop) EXPOSE 80 0B<missing> 3 weeks ago /bin/sh -c set -x && ... install nginx 45.4MB
# Просмотр с полными командамиdocker history --no-trunc nginx
# Дайвер для детального анализа (инструмент dive)dive nginxОптимизация слоёв
Заголовок раздела «Оптимизация слоёв»Объединение RUN-команд:
# ❌ Три слоя по 10 MB каждый = 30 MBRUN apt-get updateRUN apt-get install -y curlRUN rm -rf /var/lib/apt/lists/*
# ✅ Один слой = ~10 MB (кеш apt удаляется в том же слое)RUN apt-get update && \ apt-get install -y curl && \ rm -rf /var/lib/apt/lists/*Использование .dockerignore:
node_modules/.git/.env*.logdist/coverage/.DS_StoreBuildKit и параллельная сборка
Заголовок раздела «BuildKit и параллельная сборка»Docker BuildKit (включён по умолчанию с Docker 23+) улучшает производительность:
- Параллельная сборка независимых слоёв
- Улучшенное кеширование (включая удалённый кеш)
- Поддержка монтирования секретов и SSH
# Включить BuildKit для старых версийDOCKER_BUILDKIT=1 docker build .
# Сборка с отображением прогрессаdocker build --progress=plain .