Секрет ускорения Docker сборки

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

 читать первым в телеграм    читать первым в макс

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

FROM node:22
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/index.js"]

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

Роман Шубин
Роман Шубин
CEO & CTO, Главред в «Цифровой улей»
Задать вопрос
В примере выше, команда `COPY` копирует весь проект. Представь, что ты изменил одну букву в конфиге и приехали. Кеш инвалидировался, сборка пошла по новой и `RUN npm install` доставит много удовольствия.

Ключевой момент тут исходники, которые меняются.

Получаем:

  • заново устанавливает npm зависимости
  • заново качает пакеты
  • заново rebuild native modules
  • тратит минуты в CI

Хотя зависимости вообще не менялись. Мрак! Фиксим:

FROM node:22

WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
RUN npm run build
CMD ["node", "dist/index.js"]

Теперь если что-то изменить в коде проекта, пересобирается только:

COPY . .  
RUN npm run build

А RUN npm ci возьмется из кеша. Аналогично и в питончике и гошке:

COPY . .  
RUN pip install -r requirements.txt

COPY . .
RUN go mod download

Бест-практика простая: От самого стабильного → к самому изменяемому.

  • base image
  • системные пакеты
  • lock-файлы зависимостей
  • install dependencies
  • исходники
  • build
  • startup

Короче думай паттерном, а не жопой — «Какие файлы меняются редко?» и выносить их максимально вверх Dockerfile.

Каждый RUN, COPY, ADD это новый слой. Docker пытается переиспользовать уже существующие слои из кеша. Если инструкция и все предыдущие слои не изменились — слой не пересобирается. Docker сбрасывает кеш начиная с измененного слоя.

Вот и вся наука.

Комментарии