← Debugging Guides

阅读中文版本

Docker — build cache invalidated on every build

Fix repeated cache invalidation by ordering Dockerfile layers and avoiding changes that invalidate early layers.

intermediatedebuggingdockerbuild

Symptoms

  • Every build re-downloads dependencies
  • COPY . . early in the Dockerfile invalidates everything
  • The build takes the same long time regardless of changes
  • A cache miss appears right after a source edit

Possible causes

  • A COPY or ADD of volatile files precedes dependency installation
  • COPY . . copies changing files before the expensive step
  • Build arguments or labels change between builds
  • Files such as lockfiles change frequently and appear early

Diagnosis steps

Read the build output for the invalidated step

docker build --progress=plain . 2>&1 | grep -i "CACHED\|CACHE"

Interpretation

The step that lost its cache is the first change that invalidated later layers; fixing its inputs restores caching.

Reorder to copy manifests first

COPY package.json pnpm-lock.yaml ./ && RUN pnpm install

Interpretation

Installing dependencies before copying source keeps the heavy layer cached while source changes.

Check what changes between builds

git diff --name-only HEAD~1

Interpretation

Identifying volatile files copied early guides what to exclude or defer to later layers.

Root cause

A layer that changes frequently runs before an expensive layer, so any change to its inputs invalidates the cached dependency install and forces a full rebuild.

Fix

Order layers from least to most frequently changing, copy dependency manifests and install before copying source, and use a .dockerignore to keep volatile files out of early layers.

Verify the fix

Rebuild after a source-only change and confirm the dependency layers report CACHED rather than re-running.

Symptom walkthrough

Builds take the same long time every run because the cache is never reused, and output shows steps re-executing instead of hitting cache. This is a layer-ordering problem: if a frequently changing file is copied before the expensive dependency install, every source edit invalidates the install and everything after it. Build arguments and changing labels can also bust the cache unexpectedly.

Fix in practice

Order the Dockerfile from least to most volatile: copy the dependency manifest and install first, then copy source. Add a .dockerignore so files like local caches and logs do not enter early layers, and keep build arguments stable. This keeps the heavy install cached across ordinary code changes.

Verification

Edit a source file and rebuild, then confirm the dependency layers report CACHED instead of re-running. Reused cache on a trivial change confirms the ordering is right.

Diagnostic commands

Check the behavior with commands like these:

docker build --progress=plain . 2>&1 | grep -i "CACHED\|CACHE"
COPY package.json pnpm-lock.yaml ./ && RUN pnpm install
git diff --name-only HEAD~1