#Что означает ошибка и при каких условиях возникает
При каждой сборке Docker заново выполняет долгие шаги, хотя изменился один файл? Сравните журнал сборки, порядок COPY и RUN, файлы контекста и настройки BuildKit. Кэш Docker строится послойно: изменение раннего COPY инвалидирует этот слой и всё, что ниже него. Задача — не отключить кэш, а поместить редко изменяющиеся зависимости до часто изменяемого исходного кода.
#Как различить причины
| Возможная причина | Как узнать | Что делать |
|---|---|---|
| COPY . . расположен до установки зависимостейЛюбое изменение исходного файла изменяет ранний COPY, из-за чего последующий RUN npm ci выполняется заново. | В сборке после COPY . . повторяется долгий RUN npm ci. | Сначала копировать package*.json, затем устанавливать зависимости, потом копировать исходники. |
| В контекст попадают изменчивые файлыВ .dockerignore не исключены каталоги журналов, локальные зависимости и временные файлы. | Контекст сборки содержит много файлов, а COPY неожиданно перестраивается после мелких локальных действий. | Добавить безопасные исключения к .dockerignore, не скрывая нужные для сборки файлы. |
| Запускается сборка без кэша или с другим строителемВ командах есть --no-cache, изменился buildx builder, платформа или кэш не сохранён между CI-запусками. | Строки CACHED не появляются даже при повторе без изменений. | Сравнить реальные команды и доступное хранилище кэша. |
| Меняются входные значения ранних слоёвИзменён Dockerfile, build ARG или файл зависимостей; при копировании ключевых файлов это нормально. | Повторно выполняется первый слой, для которого изменилась инструкция или её вход. | Зафиксировать входные значения и отделить изменяемые файлы от стабильно используемых. |
#Пошаговая диагностика и исправление
- Найдите Dockerfile и команду сборкиВ VS Code откройте проект через «Файл» → «Открыть папку»; найдите Dockerfile рядом с исходниками либо путь в compose.yaml → services → build → dockerfile. Откройте встроенный терминал через «Терминал» → «Создать терминал» или обычный терминал ОС и перейдите в каталог сборки. Выполните
docker versionиdocker buildx version: без работающего движка и builder анализ кэша будет неверным. - Повторите одинаковую сборку с подробным журналомВ учебном каталоге с Dockerfile выполните
docker build --progress=plain -t local-cache-demo:dev .дважды, ничего не меняя между запусками. Точка означает текущий контекст,-t— локальное имя образа. Во второй сборке при сохранённом кэше многие шаги будут отмеченыCACHED; если нет, запишите первый шаг без CACHED. Не используйте--no-cacheдля этой диагностики и не подставляйте образ корпоративного производства без разрешения. - Сравните порядок COPY и RUNПрочитайте Dockerfile сверху вниз. Если перед
RUN npm ciнаписаноCOPY . ., любое изменение файла проекта способно повторно запустить установку зависимостей. В Node-проекте с package-lock.json перенесите копированиеpackage.jsonиpackage-lock.jsonперед npm ci, аCOPY . .— после установки. Это применимо только к проекту с корректным lock-файлом; для Python/Java/Go принцип тот же, но имена файлов зависимостей другие. - Уберите из контекста ненужные и секретные файлыВ корне контекста создайте или откройте файл
.dockerignore. Для Node-примера можно добавитьnode_modules,.git,*.logи.env, если эти файлы не нужны для сборки; не исключайте исходники, package-lock.json или файлы, которые копирует Dockerfile. Это уменьшит контекст, а исключение .env снизит риск попадания секретов в образ. После правки проверьте, что Dockerfile всё ещё успешно собирается. - Проверьте параметры сборки и платформуПосмотрите фактическую команду из терминала или журнала сборки проекта. Уберите случайный
--no-cache, убедитесь, что вы используете тот же buildx builder и ту же платформу. Выполнитеdocker buildx ls, чтобы увидеть активный builder (он помечен звёздочкой). При сборке в новой среде CI локального кэша может не быть вовсе; для общего кэша нужна отдельная настройка cache-to/cache-from, которую согласуют с владельцем инфраструктуры. - Проверяйте изменение именно одного исходного файлаВ учебной копии проекта поправьте только комментарий в src либо main.js и запустите ту же команду сборки. В правильно организованном Node-примере шаг
RUN npm ciостаётся CACHED, а позднийCOPY . .и следующие после него шаги могут выполняться заново. Если повторный npm ci снова не кэшируется, сравните, не менялся ли package-lock.json, ARG, образ-основа или builder. - Убедитесь, что ускорение не скрывает нужное обновлениеПосле сборки запустите тесты приложения в том порядке, который принят в вашем проекте, и убедитесь, что исходное изменение действительно находится в новом образе. При обновлении пакетов изменение lock-файла обязано заново выполнить установку; это корректное поведение. Не очищайте кэш ради исправления неоправданных перестроений — сначала ищите изменившийся ранний слой.
- При отсутствии кэша в CI изучите окружение сборщикаЕсли локально повторная сборка использует CACHED, но каждая сборка в CI идёт с нуля, сравните, сохраняется ли каталог/память сборщика между задачами и есть ли настроенный внешний кэш BuildKit. Не добавляйте публикацию кэша в общий реестр с секретами без рассмотрения угроз. Запишите вывод
docker buildx lsи первую некэшируемую инструкцию для ответственного за CI. - Команды для отдельных ситуацийВыберите только подходящий вариант. Это не одна последовательность: часть команд диагностирует проблему, а часть меняет настройки или данные.
#Минимальный пример для отдельного тестового проекта
FROM node:22-alpine
WORKDIR /app
COPY package.json package-lock.json ./
RUN npm ci
COPY . .
CMD ["node", "server.js"]node_modules
.git
*.log
.env#Как проверить результат и что делать, если проблема осталась
Ожидаемый результат: при повторной сборке без изменений большинство инструкций CACHED, а после изменения только исходников слои установки зависимостей остаются CACHED. Если нет, начните с первого некэшируемого слоя; одинаковый тег образа сам по себе не гарантирует неизменность базы или платформы.