Почему Docker снова устанавливает зависимости
Порядок COPY и границы кеша на примере небольшого Node.js-приложения.
Небольшая правка обработчика не должна каждый раз превращаться в долгую установку зависимостей. Частая причина — порядок инструкций Dockerfile: исходники копируются раньше, чем выполняется npm ci. Тогда изменение одного файла делает этот слой и следующие за ним непригодными для повторного использования.
Отделить зависимости от кода
Ниже пример для проекта с package-lock.json, без отдельного шага компиляции. major-версию Node.js нужно выбирать по требованиям приложения.
FROM node:24-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci --omit=dev
COPY --chown=node:node . .
USER node
CMD ["node", "server.js"]Пока манифесты зависимостей не изменились, Docker может использовать кеш установки. Правка server.js затронет более поздний COPY. Если lifecycle-скриптам npm нужны исходники, этот пример нужно адаптировать.
Сузить контекст
Создайте .dockerignore рядом с Dockerfile:
node_modules
.git
.env
.env.*
npm-debug.logТак локальные зависимости и секреты не попадут в обычный контекст сборки. Дополните список артефактами именно вашего проекта.
Проверить гипотезу
Соберите образ, измените текст в одном исходном файле и соберите повторно. Посмотрите, был ли переиспользован шаг установки. Затем измените зависимости и убедитесь, что он выполняется заново.
Кеш ускоряет сборку, но не заменяет воспроизводимость. Для контролируемых релизов фиксируйте зависимости и при необходимости digest базового образа, а обновления выполняйте отдельной процедурой. Не отключайте проверку lock-файла только ради успешной сборки.