Секрет ускорения Docker сборки
Давай поговорим про docker и кеширование, тема вроде поверхностная, но как оказалось многие в ней плавают и особо не понимают почему их сборка каждый раз занимает 100500 минут.
читать первым в телеграм читать первым в макс
А занимает она столько минут, по одной причине — копировать исходники нужно в последнем слое. Механизм тут простой, если какой-то слой изменился, то следующие слои будут пересобраны. Логично, что если ты копируешь исходники так:
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/index.js"]
Тебе пезда! Всё будет пересобираться каждый раз с нуля, никаким кешированием тут и не пахнет. Так делают многие, ведь оно работает и пофигу что долго.
Ключевой момент тут исходники, которые меняются.
Получаем:
- заново устанавливает 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 сбрасывает кеш начиная с измененного слоя.
Вот и вся наука.
