Docker BuildKit Cache Export/Import: Missing Automatic Invalidation
0 reputation · 14 Dec 2025, 05:29 UTC
0 reputation · 14 Dec 2025, 05:29 UTC
Investigate how Docker BuildKit’s cache export/import mechanism can retain stale layers when Dockerfile changes are not reflected in the cache key. The aim is to understand the constraints that allow stale cache results to persist, the lack of automatic invalidation, and the permission boundaries that expose exported cache data to any Docker group member.
Docker BuildKit computes cache keys from Dockerfile instructions and build context. However, exported cache data is not purged or invalidated automatically when a Dockerfile is modified. There is no built‑in TTL or expiration policy for exported cache, so cache size can grow indefinitely unless manually cleaned. Exported cache resides in the Docker daemon’s storage (e.g., /var/lib/docker/overlay2), giving all Docker‑group users read access to potentially sensitive build artifacts.
BuildKit exported cache is a content-addressed set of build records keyed by the resolved instruction and input chain, not a per-Dockerfile store. It has no built-in TTL, expiration policy, or automatic invalidation. When you edit a Dockerfile, old cache records are not deleted because BuildKit cannot know whether they are still valid for other builds, stages, or future imports. Stale results persist until the effective cache key changes or an external lifecycle policy removes the export.
Likely explanation: If a rebuild after a Dockerfile edit produces a stale result, the cache key is probably under-specified. BuildKit keys on the exact instruction text and the inputs it can see. Comments, whitespace-only changes, unbuilt stages, package versions resolved at build time, remote artifacts, clocks, or network state can change the output without changing the key. The old record remains because it still matches a valid key.
Confirmed design constraint: Cache export/import is key-based, not expiration-based. BuildKit will not purge or invalidate exported records because the current Dockerfile changed. Avoidance must come from making the build hermetic or changing the effective key, not from deletion.
systemd-tmpfiles or cron. For remote caches, use registry or object-storage retention rules and garbage collection. Delete whole export sets atomically; deleting individual records can break later imports.chmod /var/lib/docker or exported cache directories. The Docker socket and daemon storage are root-equivalent when shared. Use rootless BuildKit/buildkitd, a dedicated remote builder, or a separate build host. Grant Docker group membership only to trusted administrators.Record your toolchain versions before relying on specific flags, because cache export modes, prune filters, and registry retention features vary by Docker Engine, BuildKit, buildx, and registry versions.
docker version
docker buildx version
docker info | grep -iE 'rootless|storage.driver|docker.root.dir'
ls -l /var/run/docker.sock
To reproduce the behavior, export a local cache, change a RUN command, rebuild, and inspect the export directory. Old records should remain present even if the new build is correct.
Is your cache exported to a local directory or to a registry? If it is a registry, are the tags immutable? That determines whether registry lifecycle rules and garbage collection are the right control, or whether timestamped repositories with external pruning are safer.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.