Skip to content

mz936: dedup base image downloads - #937

Merged
mzihlmann merged 11 commits into
mainfrom
mz936-shared-base-dedup
Jul 31, 2026
Merged

mz936: dedup base image downloads#937
mzihlmann merged 11 commits into
mainfrom
mz936-shared-base-dedup

Conversation

@mzihlmann

@mzihlmann mzihlmann commented Jul 21, 2026

Copy link
Copy Markdown
Collaborator

Part of #936.

kaniko re-downloads a base image once per stage that uses it, so a multi-stage build fetches the same base repeatedly, and a cross-registry push re-fetches every base layer again to upload it. Behind FF_KANIKO_SHARED_BASE_CACHE (default off) a remote base is stored once as an OCI layout under /kaniko/bases and reused by every later stage and by push, keyed by digest the same way the warmer keys its cache. A digest-pinned base is served straight from the store with no registry access, so a build can run against an unreachable source once the store holds it. Every base-retrieval site reads the store, but only the build loop downloads and populates it, so dependency calculation and cache lookahead still cost just a manifest.

Summary by CodeRabbit

  • New Features

    • Added optional shared base-image caching for multi-stage builds via FF_KANIKO_SHARED_BASE_CACHE (off by default; becomes default in v1.29.0).
  • Bug Fixes

    • Improved resilience when the shared base cache can’t be accessed (for example, read-only), so builds degrade gracefully instead of failing.
  • Tests

    • Added/extended integration regression coverage (including a read-only /kaniko/bases case) and updated golden fixtures for shared/streamed scenarios.
  • Documentation

    • Updated README feature-flag documentation (including the new flag in the table of contents).

@coderabbitai

coderabbitai Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds FF_KANIKO_SHARED_BASE_CACHE and implements digest-based shared base-image storage and loading through local OCI layouts. Stage planning, execution, documentation, golden tests, integration coverage, and expected plan outputs are updated.

Changes

Shared base image caching

Layer / File(s) Summary
Base cache contracts and configuration
README.md, pkg/config/featureflags.go, pkg/config/init.go, pkg/config/stage.go
Defines the shared-cache flag, /kaniko/bases, and base-image metadata.
Stage planning and base classification
pkg/dockerfile/dockerfile.go, pkg/executor/build_test.go
Tracks base-image digests and classifies repeated bases for shared caching.
Base retrieval and OCI storage
pkg/executor/build.go
Renders shared or streamed base actions and loads or stores shared bases through OCI layouts with registry fallback.
Shared-cache golden and integration coverage
golden/golden_test.go, golden/testdata/test_issue_mz936/*, integration/dockerfiles/Dockerfile_test_issue_mz936, integration/images.go
Registers shared-cache golden scenarios and exercises read-only base-store fallback behavior.
Updated plan expectations
golden/testdata/test_issue_mz195/*, golden/testdata/test_issue_mz333/*, golden/testdata/test_issue_mz334/*, golden/testdata/test_issue_mz338/*, golden/testdata/test_issue_mz480/*, golden/testdata/test_issue_mz487/*, golden/testdata/test_issue_mz703/*, golden/testdata/test_issue_mz791/*, golden/testdata/test_issue_mz813/*, golden/testdata/test_issue_mz822/*, golden/testdata/test_unittests/plans/*
Updates recorded base-image operations from UNPACK to STREAM across existing golden fixtures.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant DockerfileParser
  participant MakeKanikoStages
  participant RenderStages
  participant retrieveBaseImage
  participant OCIBaseStore
  participant Registry
  DockerfileParser->>MakeKanikoStages: resolve base image digest
  MakeKanikoStages->>RenderStages: classify shared base
  RenderStages->>retrieveBaseImage: execute base action
  retrieveBaseImage->>OCIBaseStore: load or store digest-keyed image
  retrieveBaseImage->>Registry: retrieve image on local-store failure
Loading

Possibly related issues

Possibly related PRs

Suggested labels: performance, enhancement

Suggested reviewers: 0hlov3, babs, bobdu, nejch

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the change, but it omits required template sections like checklist, reviewer notes, and release notes. Add the template sections: Fixes #NNN, Description, Submitter Checklist, Reviewer Notes, and Release Notes, even if briefly filled in.
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly matches the PR’s main change: deduplicating base image downloads for mz936.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch mz936-shared-base-dedup

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.43243% with 13 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
pkg/executor/build.go 78.26% 5 Missing and 5 partials ⚠️
pkg/dockerfile/dockerfile.go 88.88% 2 Missing and 1 partial ⚠️

📢 Thoughts on this report? Let us know!

@mzihlmann
mzihlmann force-pushed the mz936-shared-base-dedup branch 2 times, most recently from 55705d5 to 391989a Compare July 22, 2026 07:23
@mzihlmann mzihlmann changed the title Dedup base image downloads across stages behind FF_KANIKO_SHARED_BASE_CACHE dedup base image downloads Jul 22, 2026
@mzihlmann mzihlmann added the performance Build speed or resource usage label Jul 22, 2026
@mzihlmann

Copy link
Copy Markdown
Collaborator Author

Performance results

Three-way comparison against regression, following the methodology from #871. Real Docker Hub pulls, not loopback. Variants:

  • base: branch parent ec6d0901c, no shared-base code.
  • off: this branch, FF_KANIKO_SHARED_BASE_CACHE=0.
  • on: this branch, flag on.

Each build has a RUN so the base is actually unpacked. Cross-registry push targets a fresh ephemeral registry so it never already holds the base blobs. Host interface RX measures bytes pulled from Hub.

Byte proof (debian:12, n=3, RX per run)

proof base off on
push, 1 stage 106 MB (2x) 106 MB (2x) 54 MB (1x)
no-push, 1 stage 54 MB (1x) 54 MB (1x) 54 MB (1x)
no-push, 3 stages 160 MB (3x) 160 MB (3x) 55 MB (1x)

The flag collapses every case to a single base download. Cross-registry push saves one download even at N=1, and a 3-stage build drops from three downloads to one.

Wall-time magnitude (nvidia/cuda:12.9.1-runtime-ubuntu24.04, ~2.65 GB, n=2)

Median wall time / median RX.

proof base off on
push, 1 stage 383s / 5306 MB 419s / 5322 MB 225s / 2648 MB
no-push, 1 stage 160s / 2630 MB 154s / 2630 MB 196s / 2627 MB
no-push, 3 stages 460s / 8036 MB 456s / 7949 MB 327s / 2677 MB

base and off tie everywhere, so the added code is free on the default path. With the flag on, cross-registry push is ~1.7x faster and the 3-stage build ~1.4x faster.

Known regression: single stage, no push is ~28% slower with the flag on

196s vs 154-160s, same bytes, stddev 0.1s so it is real. With the flag on the base is written to the store and only then extracted, replacing the streaming path where download and extraction interleave. For a single stage that is never reused the serialization is pure overhead.

Acceptable for a default-off flag, but the aim is a win in every case. The fix is to tee the compressed layer into the store with an io.TeeReader while the extractor consumes the same stream, so storing runs concurrent with extraction instead of before it. Single-stage no-push then streams as today and reuse still reads the store. That is the next step for this flag.

@mzihlmann mzihlmann changed the title dedup base image downloads mz936: dedup base image downloads Jul 23, 2026
@mzihlmann

Copy link
Copy Markdown
Collaborator Author

Fix: decide the base action per stage

The first pass stored every remote base. That made a single no-push stage about 28% slower on a heavy base, because the base was downloaded into the store and then extracted, instead of streaming the download and extraction together.

The fix decides per stage whether the base is read more than once, and only stores it then. A base is stored when several built stages share it, when a stage is kept for a later stage to build on, or when the built image is written out (push, tarball, or OCI layout), because all of those re-read the base layers. A base read exactly once streams as before, so it never pays a store round trip it cannot repay.

The decision runs in MakeKanikoStages, after stage squashing when the build order is fixed, and is carried on the stage as a three state action:

  • none: stream (download and unpack in one pass). Also local-stage bases.
  • store: the first stage to pull a shared or re-read base writes it to the store, then loads it.
  • load: later stages read it back from the store with no registry access.

The dryrun plan prints STORE / UNPACK / STREAM per stage, and golden test test_issue_mz936 pins the decisions across the shared, push, and flag-off cases.

Performance

nvidia/cuda:12.9.1-runtime-ubuntu24.04, three way: pre-change (executor-base) / branch flag-off / branch flag-on. Real Docker Hub pulls. Wall time and host RX.

proof2: single stage, no push (the regression check), n=5

variant wall median wall mean +/- sd RX
pre-change 198.4s 194.9 +/- 40.6 2641 MB
branch off 148.3s 170.2 +/- 42.7 2631 MB
branch on 148.3s 150.4 +/- 5.5 2631 MB

branch-on median equals branch-off, and RX is 1x, so the single no-push stage now streams. The regression is gone, and branch-on has the tightest spread of the three.

The pre-change median reads higher only because the harness ran it first every round and it caught the cold-network slots. A control round with the order flipped gives pre-change 138.2s, off 138.3s, on 139.7s, all within 1.5s. So pre-change, off, and on are equal for this case, as expected.

proof1: cross-registry push, single stage, n=2

variant wall median RX
pre-change 287s 5290 MB (2x)
branch off 287s 5325 MB (2x)
branch on 228s 2669 MB (1x)

The push re-reads the base to upload it. With the flag on the base is stored once and the push reads it locally, saving one full download even at a single stage.

proof3: multi-stage, 3 stages on the same base, no push

Three stages on the same base drop from 3 downloads to 1: RX about 8.0 GB to 2.68 GB, wall about 460s to 327s. This is unchanged by the elision, since a shared base is still stored and loaded.

Summary

  • pre-change and branch-off tie in every case, so the added code is free when the flag is off.
  • single stage no push no longer regresses, it streams.
  • cross-registry push saves one base download even at a single stage.
  • multi-stage downloads the shared base once.

@mzihlmann
mzihlmann marked this pull request as ready for review July 24, 2026 08:30
@mzihlmann
mzihlmann requested review from 0hlov3, BobDu, babs and nejch July 24, 2026 08:31
@mzihlmann

Copy link
Copy Markdown
Collaborator Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@golden/testdata/test_issue_mz936/test.go`:
- Around line 25-27: Make the flag-off test case in the relevant test
configuration explicitly disable FF_KANIKO_SHARED_BASE_CACHE by setting it to
"0" or unsetting it in test.Env, so inherited environment values cannot enable
shared base caching and the Plan: "streamed" baseline remains deterministic.

In `@pkg/dockerfile/dockerfile.go`:
- Around line 419-432: Update the shared-cache planning loop in the
stage-processing logic to skip digestless base images before assigning
STORE/LOAD actions. Require a non-empty BaseImageDigest for both the current
stage and matching later stages, preserving existing planning for digest-keyed
bases.

In `@pkg/executor/build.go`:
- Around line 1587-1590: Update the error branch after img.Digest() in the
surrounding build function to emit a warning containing the digest error before
returning img, nil. Match the warning behavior and logging style used by the
other failure branches in that function, while preserving the existing return
behavior.
- Around line 1566-1610: Update retrieveBaseImage’s BaseImageLoad branch to
handle loadFromOCILayout failures without asserting or panicking: log a warning
and fall back to image_util.RetrieveSourceImage(stage, opts), propagating any
registry-fetch error. Preserve the local-store fast path when loading succeeds
and keep the existing Store-branch behavior unchanged.
- Line 1217: Update the cache lookahead path around retrieveBaseImage so every
non-local stage, including BaseImageLoad stages, resolves its base through
retrieveBaseImage instead of directly calling image_util.RetrieveSourceImage.
Preserve local-stage behavior and ensure shared remote bases are read from the
local OCI layout rather than redownloaded during precompute.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1957a9ca-d685-4698-9d7c-af5b6f8f6063

📥 Commits

Reviewing files that changed from the base of the PR and between 9616444 and 01adcba.

📒 Files selected for processing (52)
  • README.md
  • golden/golden_test.go
  • golden/testdata/test_issue_mz195/plans/fourth
  • golden/testdata/test_issue_mz195/plans/noise
  • golden/testdata/test_issue_mz195/plans/normal
  • golden/testdata/test_issue_mz195/plans/push
  • golden/testdata/test_issue_mz333/plans/plan
  • golden/testdata/test_issue_mz334/plans/cached
  • golden/testdata/test_issue_mz334/plans/inferred
  • golden/testdata/test_issue_mz334/plans/plan
  • golden/testdata/test_issue_mz338/plans/plan
  • golden/testdata/test_issue_mz480/plans/final
  • golden/testdata/test_issue_mz480/plans/final_test
  • golden/testdata/test_issue_mz487/plans/plan
  • golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss
  • golden/testdata/test_issue_mz703/plans/probe_after_miss
  • golden/testdata/test_issue_mz791/plans/resolved_one
  • golden/testdata/test_issue_mz791/plans/resolved_two
  • golden/testdata/test_issue_mz791/plans/unresolved_one
  • golden/testdata/test_issue_mz791/plans/unresolved_two
  • golden/testdata/test_issue_mz813/plans/resolved_one
  • golden/testdata/test_issue_mz813/plans/resolved_two
  • golden/testdata/test_issue_mz813/plans/unresolved_one
  • golden/testdata/test_issue_mz813/plans/unresolved_two
  • golden/testdata/test_issue_mz822/plans/resolved_one
  • golden/testdata/test_issue_mz822/plans/resolved_two
  • golden/testdata/test_issue_mz822/plans/unresolved
  • golden/testdata/test_issue_mz936/Dockerfile
  • golden/testdata/test_issue_mz936/plans/push
  • golden/testdata/test_issue_mz936/plans/shared
  • golden/testdata/test_issue_mz936/plans/streamed
  • golden/testdata/test_issue_mz936/test.go
  • golden/testdata/test_unittests/plans/alias
  • golden/testdata/test_unittests/plans/copyfrom_final
  • golden/testdata/test_unittests/plans/final_wo_deps_buzz
  • golden/testdata/test_unittests/plans/final_wo_deps_final
  • golden/testdata/test_unittests/plans/final_wo_deps_fizz
  • golden/testdata/test_unittests/plans/global_arg
  • golden/testdata/test_unittests/plans/global_arg_stage1
  • golden/testdata/test_unittests/plans/multiple_copy
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final
  • golden/testdata/test_unittests/plans/two_copyfrom_final
  • golden/testdata/test_unittests/plans/wo_copyfrom_dev
  • golden/testdata/test_unittests/plans/wo_copyfrom_final
  • golden/testdata/test_unittests/plans/wo_copyfrom_prod
  • pkg/config/featureflags.go
  • pkg/config/init.go
  • pkg/config/stage.go
  • pkg/dockerfile/dockerfile.go
  • pkg/executor/build.go
  • pkg/executor/build_test.go

Comment thread golden/testdata/test_issue_mz936/test.go
Comment thread pkg/dockerfile/dockerfile.go Outdated
Comment thread pkg/executor/build.go
Comment thread pkg/executor/build.go
Comment thread pkg/executor/build.go Outdated
@mzihlmann

Copy link
Copy Markdown
Collaborator Author

Thanks for the review. Pushed 522563e. Rather than patch the store/load model in place, I collapsed it, which resolves two of these at the source.

Load-branch panic (critical) and silent img.Digest() (minor): merged the none/store/load enum into a single BaseImageShared bool. retrieveBaseImage now loads from the store if the entry is present and otherwise fetches, stores, and returns. There is no separate load branch left to assert on, so a store miss always falls through to a registry fetch. The build-time img.Digest() recompute is gone too. The digest was already resolved from the same ref at plan time in getRemoteOnBuild, so a shared stage keys the store on stage.BaseImageDigest. If that call could fail here the base would be unusable and streaming would fail anyway, so there was nothing to recover.

Digestless bases (major): the planner now skips bases with an empty digest, so FROM scratch is never marked shared.

Flag-off golden case (minor): we chose not to configure the flag off explicitly. The golden reads better with only active flags set, and FF_KANIKO_SHARED_BASE_CACHE is now enabled across the integration suite instead.

Cache lookahead: unchanged, as agreed. It stays digest-only.

New integration test Dockerfile_test_issue_mz936 mounts /kaniko/bases read-only and confirms a shared base degrades to a registry fetch. It panics on the pre-merge code and passes after the merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integration/images.go`:
- Around line 392-393: Update the Dockerfile_test_issue_mz936 test expectation
for the shared-base: fallback warning so both stage warnings are required,
rather than allowing checkNoWarnings to succeed after the first match. Set the
expected occurrence count to two using the existing expectation mechanism, or
add a Dockerfile-specific output assertion that verifies both warnings.

In `@pkg/dockerfile/dockerfile.go`:
- Around line 418-420: Update the stage-filtering condition in the
duplicate-scan loop to stop treating BaseImageShared as a reason to continue.
Preserve skipping for locally stored base images and empty digests, while
allowing already-shared stages to participate in later same-digest scanning and
load the shared OCI layout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 1d39afcf-f39e-4ec3-adc3-f3e33547b511

📥 Commits

Reviewing files that changed from the base of the PR and between 01adcba and 522563e.

📒 Files selected for processing (8)
  • golden/testdata/test_issue_mz936/plans/push
  • golden/testdata/test_issue_mz936/plans/shared
  • integration/dockerfiles/Dockerfile_test_issue_mz936
  • integration/images.go
  • integration/testdata/readonly-base-store/.gitkeep
  • pkg/config/stage.go
  • pkg/dockerfile/dockerfile.go
  • pkg/executor/build.go
🚧 Files skipped from review as they are similar to previous changes (3)
  • golden/testdata/test_issue_mz936/plans/shared
  • golden/testdata/test_issue_mz936/plans/push
  • pkg/executor/build.go

Comment thread integration/images.go
Comment thread pkg/dockerfile/dockerfile.go
@mzihlmann
mzihlmann force-pushed the mz936-shared-base-dedup branch from 522563e to 3b82e0d Compare July 24, 2026 16:24

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
pkg/executor/build.go (1)

1564-1593: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Clean up partial OCI layout writes on error. writeImageLayout can leave a broken cache entry behind when layout.Write or AppendImage fails, so later BaseImageShared lookups will keep hitting the same unreadable directory instead of starting clean. Removing the directory or writing to a temp path and renaming on success would avoid that stale state.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/executor/build.go` around lines 1564 - 1593, Update retrieveBaseImage and
the writeImageLayout flow so failed OCI layout writes cannot leave a stale
partial cache at the path derived from stage.BaseImageDigest. On
writeImageLayout failure, remove the incomplete layout directory (or use an
equivalent temporary-path-and-rename approach), while preserving the existing
fallback to the retrieved registry image.
🧹 Nitpick comments (1)
pkg/executor/build.go (1)

1568-1570: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider logging the store-miss before falling back to fetch.

Every other branch in this function logs (Infof/Warnf) on hit, store, or fallback, but the initial store-miss (loadFromOCILayout returning an error before the registry fetch) is silent. A short debug/info log would help confirm the reported cache-hit-ratio improvements in production.

♻️ Proposed addition
 	stored, err := loadFromOCILayout(path)
 	if err == nil {
 		logrus.Infof("shared-base: loading base %s from local store", stage.BaseImageDigest)
 		return stored, nil
 	}
+	logrus.Debugf("shared-base: base %s not found in local store (%v), fetching from registry", stage.BaseImageDigest, err)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/executor/build.go` around lines 1568 - 1570, Add a concise debug or info
log in the stage-loading flow immediately after loadFromOCILayout returns an
error, before the registry-fetch fallback. Include the relevant stage or
base-image identifier and indicate that the OCI layout store missed, while
preserving the existing fallback behavior and nearby hit/store logging.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@pkg/executor/build.go`:
- Around line 1564-1593: Update retrieveBaseImage and the writeImageLayout flow
so failed OCI layout writes cannot leave a stale partial cache at the path
derived from stage.BaseImageDigest. On writeImageLayout failure, remove the
incomplete layout directory (or use an equivalent temporary-path-and-rename
approach), while preserving the existing fallback to the retrieved registry
image.

---

Nitpick comments:
In `@pkg/executor/build.go`:
- Around line 1568-1570: Add a concise debug or info log in the stage-loading
flow immediately after loadFromOCILayout returns an error, before the
registry-fetch fallback. Include the relevant stage or base-image identifier and
indicate that the OCI layout store missed, while preserving the existing
fallback behavior and nearby hit/store logging.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: bbe7c72a-a524-46d4-98e8-9632253c7e80

📥 Commits

Reviewing files that changed from the base of the PR and between 522563e and 3b82e0d.

📒 Files selected for processing (7)
  • golden/testdata/test_issue_mz936/plans/push
  • golden/testdata/test_issue_mz936/plans/shared
  • integration/dockerfiles/Dockerfile_test_issue_mz936
  • integration/images.go
  • pkg/config/stage.go
  • pkg/dockerfile/dockerfile.go
  • pkg/executor/build.go
🚧 Files skipped from review as they are similar to previous changes (5)
  • pkg/config/stage.go
  • integration/dockerfiles/Dockerfile_test_issue_mz936
  • golden/testdata/test_issue_mz936/plans/push
  • golden/testdata/test_issue_mz936/plans/shared
  • integration/images.go

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/config/init.go`:
- Around line 59-61: Update Cleanup to remove the shared-base directory
represented by KanikoBaseStagesDir alongside the other /kaniko work directories,
ensuring accumulated OCI layouts and blobs are deleted during cleanup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 5ed080c4-a473-4d5e-8090-c0b44d8d6206

📥 Commits

Reviewing files that changed from the base of the PR and between 3b82e0d and d1496d8.

📒 Files selected for processing (54)
  • README.md
  • golden/golden_test.go
  • golden/testdata/test_issue_mz195/plans/fourth
  • golden/testdata/test_issue_mz195/plans/noise
  • golden/testdata/test_issue_mz195/plans/normal
  • golden/testdata/test_issue_mz195/plans/push
  • golden/testdata/test_issue_mz333/plans/plan
  • golden/testdata/test_issue_mz334/plans/cached
  • golden/testdata/test_issue_mz334/plans/inferred
  • golden/testdata/test_issue_mz334/plans/plan
  • golden/testdata/test_issue_mz338/plans/plan
  • golden/testdata/test_issue_mz480/plans/final
  • golden/testdata/test_issue_mz480/plans/final_test
  • golden/testdata/test_issue_mz487/plans/plan
  • golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss
  • golden/testdata/test_issue_mz703/plans/probe_after_miss
  • golden/testdata/test_issue_mz791/plans/resolved_one
  • golden/testdata/test_issue_mz791/plans/resolved_two
  • golden/testdata/test_issue_mz791/plans/unresolved_one
  • golden/testdata/test_issue_mz791/plans/unresolved_two
  • golden/testdata/test_issue_mz813/plans/resolved_one
  • golden/testdata/test_issue_mz813/plans/resolved_two
  • golden/testdata/test_issue_mz813/plans/unresolved_one
  • golden/testdata/test_issue_mz813/plans/unresolved_two
  • golden/testdata/test_issue_mz822/plans/resolved_one
  • golden/testdata/test_issue_mz822/plans/resolved_two
  • golden/testdata/test_issue_mz822/plans/unresolved
  • golden/testdata/test_issue_mz936/Dockerfile
  • golden/testdata/test_issue_mz936/plans/push
  • golden/testdata/test_issue_mz936/plans/shared
  • golden/testdata/test_issue_mz936/plans/streamed
  • golden/testdata/test_issue_mz936/test.go
  • golden/testdata/test_unittests/plans/alias
  • golden/testdata/test_unittests/plans/copyfrom_final
  • golden/testdata/test_unittests/plans/final_wo_deps_buzz
  • golden/testdata/test_unittests/plans/final_wo_deps_final
  • golden/testdata/test_unittests/plans/final_wo_deps_fizz
  • golden/testdata/test_unittests/plans/global_arg
  • golden/testdata/test_unittests/plans/global_arg_stage1
  • golden/testdata/test_unittests/plans/multiple_copy
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final
  • golden/testdata/test_unittests/plans/two_copyfrom_final
  • golden/testdata/test_unittests/plans/wo_copyfrom_dev
  • golden/testdata/test_unittests/plans/wo_copyfrom_final
  • golden/testdata/test_unittests/plans/wo_copyfrom_prod
  • integration/dockerfiles/Dockerfile_test_issue_mz936
  • integration/images.go
  • pkg/config/featureflags.go
  • pkg/config/init.go
  • pkg/config/stage.go
  • pkg/dockerfile/dockerfile.go
  • pkg/executor/build.go
  • pkg/executor/build_test.go
🚧 Files skipped from review as they are similar to previous changes (46)
  • golden/testdata/test_issue_mz822/plans/unresolved
  • golden/testdata/test_issue_mz334/plans/cached
  • golden/testdata/test_unittests/plans/final_wo_deps_buzz
  • golden/testdata/test_issue_mz334/plans/inferred
  • golden/testdata/test_unittests/plans/wo_copyfrom_final
  • golden/testdata/test_issue_mz480/plans/final_test
  • golden/testdata/test_unittests/plans/final_wo_deps_final
  • golden/testdata/test_issue_mz813/plans/unresolved_two
  • golden/testdata/test_unittests/plans/wo_copyfrom_prod
  • golden/testdata/test_unittests/plans/global_arg_stage1
  • golden/testdata/test_issue_mz813/plans/resolved_one
  • golden/testdata/test_issue_mz195/plans/noise
  • integration/dockerfiles/Dockerfile_test_issue_mz936
  • golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base
  • golden/testdata/test_issue_mz822/plans/resolved_two
  • golden/testdata/test_issue_mz338/plans/plan
  • golden/testdata/test_unittests/plans/global_arg
  • golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final
  • golden/testdata/test_issue_mz813/plans/unresolved_one
  • golden/testdata/test_issue_mz487/plans/plan
  • golden/testdata/test_issue_mz703/plans/probe_after_miss
  • golden/testdata/test_issue_mz791/plans/resolved_two
  • golden/testdata/test_issue_mz813/plans/resolved_two
  • golden/testdata/test_unittests/plans/alias
  • golden/testdata/test_issue_mz791/plans/unresolved_two
  • golden/testdata/test_issue_mz936/plans/streamed
  • golden/testdata/test_issue_mz333/plans/plan
  • golden/testdata/test_issue_mz791/plans/unresolved_one
  • golden/testdata/test_unittests/plans/two_copyfrom_final
  • pkg/config/stage.go
  • golden/testdata/test_issue_mz334/plans/plan
  • golden/testdata/test_issue_mz195/plans/normal
  • golden/testdata/test_unittests/plans/copyfrom_final
  • README.md
  • golden/testdata/test_issue_mz791/plans/resolved_one
  • golden/testdata/test_unittests/plans/wo_copyfrom_dev
  • golden/testdata/test_unittests/plans/final_wo_deps_fizz
  • golden/golden_test.go
  • golden/testdata/test_issue_mz936/test.go
  • pkg/config/featureflags.go
  • golden/testdata/test_issue_mz936/plans/shared
  • integration/images.go
  • golden/testdata/test_issue_mz936/plans/push
  • pkg/executor/build_test.go
  • pkg/dockerfile/dockerfile.go

Comment thread pkg/config/init.go
@mzihlmann
mzihlmann force-pushed the mz936-shared-base-dedup branch 3 times, most recently from 6daf5da to 82967c9 Compare July 26, 2026 09:57
Comment thread pkg/executor/build.go Outdated
@mzihlmann
mzihlmann force-pushed the mz936-shared-base-dedup branch from bcb82f4 to 887226b Compare July 30, 2026 17:14
@mzihlmann
mzihlmann force-pushed the mz936-shared-base-dedup branch from 30410d3 to 723c07b Compare July 30, 2026 19:28
@mzihlmann
mzihlmann requested a review from 0hlov3 July 30, 2026 19:49

@0hlov3 0hlov3 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@mzihlmann overall everything looks good. Maybe we should mention that the /kaniko/bases are never cleaned up by config.Cleanup() with FF_KANIKO_SHARED_BASE_CACHE enabled, cause it can leave potentially large base layers behind, in repeated builds or long-lived executors this .

@mzihlmann
mzihlmann merged commit 93be5ff into main Jul 31, 2026
13 checks passed
@mzihlmann
mzihlmann deleted the mz936-shared-base-dedup branch July 31, 2026 07:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

performance Build speed or resource usage

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants