From eba7c26de47c64dc3472fe7851728bbfec10ec23 Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Sun, 9 Aug 2026 15:48:06 +0100 Subject: [PATCH 1/3] Account for every pushed layer in the plan --- golden/golden_test.go | 2 + golden/testdata/test_issue_mz195/Dockerfile | 4 +- golden/testdata/test_issue_mz195/plans/fourth | 8 +-- golden/testdata/test_issue_mz195/plans/noise | 4 +- golden/testdata/test_issue_mz195/plans/normal | 8 +-- golden/testdata/test_issue_mz195/plans/push | 10 +-- golden/testdata/test_issue_mz333/plans/plan | 4 +- golden/testdata/test_issue_mz334/plans/cached | 14 ++-- .../test_issue_mz334/plans/eliminated | 16 ++--- .../testdata/test_issue_mz334/plans/inferred | 24 +++---- golden/testdata/test_issue_mz334/plans/plan | 8 +-- golden/testdata/test_issue_mz338/plans/plan | 2 +- golden/testdata/test_issue_mz480/Dockerfile | 2 +- golden/testdata/test_issue_mz480/plans/final | 11 +-- .../test_issue_mz480/plans/final_test | 13 ++-- golden/testdata/test_issue_mz487/plans/plan | 6 +- .../plans/legacy_stop_after_miss | 8 +-- .../test_issue_mz703/plans/probe_after_miss | 8 +-- .../test_issue_mz791/plans/resolved_one | 10 +-- .../test_issue_mz791/plans/resolved_two | 10 +-- .../test_issue_mz791/plans/unresolved_one | 10 +-- .../test_issue_mz791/plans/unresolved_two | 10 +-- .../test_issue_mz813/plans/resolved_one | 6 +- .../test_issue_mz813/plans/resolved_two | 6 +- .../test_issue_mz813/plans/unresolved_one | 6 +- .../test_issue_mz813/plans/unresolved_two | 6 +- .../test_issue_mz822/plans/resolved_one | 6 +- .../test_issue_mz822/plans/resolved_two | 6 +- .../test_issue_mz822/plans/unresolved | 6 +- golden/testdata/test_issue_mz936/Dockerfile | 10 +-- golden/testdata/test_issue_mz936/plans/push | 36 ++++++---- golden/testdata/test_issue_mz936/plans/shared | 28 ++++---- .../testdata/test_issue_mz936/plans/streamed | 22 +++--- golden/testdata/test_issue_mz989/Dockerfile | 3 + .../testdata/test_issue_mz989/plans/cache_hit | 10 +++ .../test_issue_mz989/plans/cache_miss | 12 ++++ golden/testdata/test_issue_mz989/plans/plain | 8 +++ .../testdata/test_issue_mz989/plans/rekeyed | 10 +++ golden/testdata/test_issue_mz989/plans/stored | 9 +++ golden/testdata/test_issue_mz989/test.go | 56 +++++++++++++++ golden/testdata/test_unittests/plans/alias | 4 +- .../test_unittests/plans/copyfrom_final | 4 +- .../test_unittests/plans/final_wo_deps_buzz | 2 +- .../test_unittests/plans/final_wo_deps_final | 2 +- .../test_unittests/plans/final_wo_deps_fizz | 4 +- .../testdata/test_unittests/plans/global_arg | 2 +- .../test_unittests/plans/global_arg_stage1 | 2 +- .../test_unittests/plans/multiple_copy | 4 +- .../plans/two_copyfrom_and_arg_base | 2 +- .../plans/two_copyfrom_and_arg_final | 6 +- .../test_unittests/plans/two_copyfrom_final | 6 +- .../test_unittests/plans/wo_copyfrom_dev | 2 +- .../test_unittests/plans/wo_copyfrom_final | 2 +- .../test_unittests/plans/wo_copyfrom_prod | 2 +- pkg/executor/build.go | 70 +++++++++++++------ 55 files changed, 353 insertions(+), 199 deletions(-) create mode 100644 golden/testdata/test_issue_mz989/Dockerfile create mode 100644 golden/testdata/test_issue_mz989/plans/cache_hit create mode 100644 golden/testdata/test_issue_mz989/plans/cache_miss create mode 100644 golden/testdata/test_issue_mz989/plans/plain create mode 100644 golden/testdata/test_issue_mz989/plans/rekeyed create mode 100644 golden/testdata/test_issue_mz989/plans/stored create mode 100644 golden/testdata/test_issue_mz989/test.go diff --git a/golden/golden_test.go b/golden/golden_test.go index 380642d8d..4c23da283 100644 --- a/golden/golden_test.go +++ b/golden/golden_test.go @@ -43,6 +43,7 @@ import ( testissuemz813 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz813" testissuemz822 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz822" testissuemz936 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz936" + testissuemz989 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz989" testunittests "github.com/osscontainertools/kaniko/golden/testdata/test_unittests" "github.com/osscontainertools/kaniko/golden/types" "github.com/osscontainertools/kaniko/pkg/cache" @@ -100,6 +101,7 @@ var allTests = map[string][]types.GoldenTests{ "test_issue_mz813": {testissuemz813.Tests}, "test_issue_mz822": {testissuemz822.Tests}, "test_issue_mz936": {testissuemz936.Tests}, + "test_issue_mz989": {testissuemz989.Tests}, "test_unittests": testunittests.Tests, } var update bool diff --git a/golden/testdata/test_issue_mz195/Dockerfile b/golden/testdata/test_issue_mz195/Dockerfile index 9f3b823c5..fed9bb12e 100644 --- a/golden/testdata/test_issue_mz195/Dockerfile +++ b/golden/testdata/test_issue_mz195/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:12.10 AS first-stage +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS first-stage FROM first-stage AS second-stage @@ -14,5 +14,5 @@ COPY --from=third-stage test test # When we optimize stages out this should not # impact squashing logic at all -FROM debian:12.10 as noise +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 as noise FROM fourth-stage AS fifth-stage diff --git a/golden/testdata/test_issue_mz195/plans/fourth b/golden/testdata/test_issue_mz195/plans/fourth index 80f84477e..63190128d 100644 --- a/golden/testdata/test_issue_mz195/plans/fourth +++ b/golden/testdata/test_issue_mz195/plans/fourth @@ -1,14 +1,14 @@ -FROM debian:12.10 AS first-stage -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS first-stage + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 SAVE STAGE /kaniko/stages/0 CLEAN FROM first-stage AS third-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN touch test SAVE FILES [test] /kaniko/deps/2 CLEAN FROM first-stage AS fourth-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=third-stage test test diff --git a/golden/testdata/test_issue_mz195/plans/noise b/golden/testdata/test_issue_mz195/plans/noise index d3100d41d..d83737cec 100644 --- a/golden/testdata/test_issue_mz195/plans/noise +++ b/golden/testdata/test_issue_mz195/plans/noise @@ -1,2 +1,2 @@ -FROM debian:12.10 AS noise -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS noise + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 diff --git a/golden/testdata/test_issue_mz195/plans/normal b/golden/testdata/test_issue_mz195/plans/normal index d1c8bb08a..731316d3a 100644 --- a/golden/testdata/test_issue_mz195/plans/normal +++ b/golden/testdata/test_issue_mz195/plans/normal @@ -1,14 +1,14 @@ -FROM debian:12.10 AS first-stage -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS first-stage + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 SAVE STAGE /kaniko/stages/0 CLEAN FROM first-stage AS third-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN touch test SAVE FILES [test] /kaniko/deps/2 CLEAN FROM first-stage AS fifth-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=third-stage test test diff --git a/golden/testdata/test_issue_mz195/plans/push b/golden/testdata/test_issue_mz195/plans/push index a76dc9f15..a0ceadde2 100644 --- a/golden/testdata/test_issue_mz195/plans/push +++ b/golden/testdata/test_issue_mz195/plans/push @@ -1,15 +1,17 @@ -FROM debian:12.10 AS first-stage -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS first-stage + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 SAVE STAGE /kaniko/stages/0 CLEAN FROM first-stage AS third-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN touch test SAVE FILES [test] /kaniko/deps/2 CLEAN FROM first-stage AS fifth-stage -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=third-stage test test PUSH [registry] + UPLOAD sha256:cf05a52c02353f0b2b6f9be0549ac916c3fb1dc8d4bacd405eac7f28562ec9f2 + UPLOAD COPY --from=third-stage test test diff --git a/golden/testdata/test_issue_mz333/plans/plan b/golden/testdata/test_issue_mz333/plans/plan index a10deaaba..07d173d75 100644 --- a/golden/testdata/test_issue_mz333/plans/plan +++ b/golden/testdata/test_issue_mz333/plans/plan @@ -1,9 +1,9 @@ FROM busybox AS base -STREAM busybox + STREAM busybox RUN touch blubb SAVE FILES [blubb] /kaniko/deps/0 CLEAN FROM scratch AS final -STREAM scratch + STREAM scratch COPY --from=base blubb . diff --git a/golden/testdata/test_issue_mz334/plans/cached b/golden/testdata/test_issue_mz334/plans/cached index 2b04bb23a..4873aeaa1 100644 --- a/golden/testdata/test_issue_mz334/plans/cached +++ b/golden/testdata/test_issue_mz334/plans/cached @@ -1,27 +1,27 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE HIT: 72e9e0e54e4522d381e54427f5ac6f24dd09910e1ff8d4bc7f60d02f54e2cdc3 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /blubb + CACHE HIT: 72e9e0e54e4522d381e54427f5ac6f24dd09910e1ff8d4bc7f60d02f54e2cdc3 SAVE STAGE /kaniko/stages/0 SAVE FILES [/blubb] /kaniko/deps/0 CLEAN FROM first AS second -UNPACK /kaniko/stages/0 -CACHE HIT: 3829b10dc17cc7bafd22450e05b7f265b73e94d46b08817d0502848b21dd69aa + UNPACK /kaniko/stages/0 RUN touch /bla + CACHE HIT: 3829b10dc17cc7bafd22450e05b7f265b73e94d46b08817d0502848b21dd69aa SAVE STAGE /kaniko/stages/1 CLEAN FROM second AS third -UNPACK /kaniko/stages/1 -CACHE HIT: 256455fba386c671b4808e621379712ca6dfecce4d4e9ed2d6edab8b5e415b75 + UNPACK /kaniko/stages/1 RUN touch /bli + CACHE HIT: 256455fba386c671b4808e621379712ca6dfecce4d4e9ed2d6edab8b5e415b75 SAVE FILES [/bli] /kaniko/deps/2 CLEAN FROM second AS final -UNPACK /kaniko/stages/1 + UNPACK /kaniko/stages/1 COPY --from=first /blubb /blubb COPY --from=third /bli /bli RUN ls -lah /blubb diff --git a/golden/testdata/test_issue_mz334/plans/eliminated b/golden/testdata/test_issue_mz334/plans/eliminated index 674406fe8..845a372d1 100644 --- a/golden/testdata/test_issue_mz334/plans/eliminated +++ b/golden/testdata/test_issue_mz334/plans/eliminated @@ -1,14 +1,14 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS final -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE HIT: ec50b204a07f169d1beec66434b673ca44caf8b98ee6c98e886320969926d029 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /blubb -CACHE HIT: 9097bbf817837a54a5ba9b91d9d2a771a145d25f5389c96a4c3315119aa482a5 + CACHE HIT: ec50b204a07f169d1beec66434b673ca44caf8b98ee6c98e886320969926d029 RUN touch /bla -CACHE REDIRECT HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 -CACHE HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 + CACHE HIT: 9097bbf817837a54a5ba9b91d9d2a771a145d25f5389c96a4c3315119aa482a5 COPY --from=first /blubb /blubb -CACHE REDIRECT HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb -CACHE HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb + CACHE REDIRECT HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 + CACHE HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 COPY --from=third /bli /bli -CACHE HIT: e3d0a39d0f55303c063b93635b40f56d535f5bd2b48b770af66bf0fe61b7debc + CACHE REDIRECT HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb + CACHE HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb RUN ls -lah /blubb + CACHE HIT: e3d0a39d0f55303c063b93635b40f56d535f5bd2b48b770af66bf0fe61b7debc diff --git a/golden/testdata/test_issue_mz334/plans/inferred b/golden/testdata/test_issue_mz334/plans/inferred index ec6c15e32..4279147c0 100644 --- a/golden/testdata/test_issue_mz334/plans/inferred +++ b/golden/testdata/test_issue_mz334/plans/inferred @@ -1,32 +1,32 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE HIT: ec50b204a07f169d1beec66434b673ca44caf8b98ee6c98e886320969926d029 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /blubb + CACHE HIT: ec50b204a07f169d1beec66434b673ca44caf8b98ee6c98e886320969926d029 SAVE STAGE /kaniko/stages/0 SAVE FILES [/blubb] /kaniko/deps/0 CLEAN FROM first AS second -UNPACK /kaniko/stages/0 -CACHE HIT: 9097bbf817837a54a5ba9b91d9d2a771a145d25f5389c96a4c3315119aa482a5 + UNPACK /kaniko/stages/0 RUN touch /bla + CACHE HIT: 9097bbf817837a54a5ba9b91d9d2a771a145d25f5389c96a4c3315119aa482a5 SAVE STAGE /kaniko/stages/1 CLEAN FROM second AS third -UNPACK /kaniko/stages/1 -CACHE HIT: dd8070993f952ce8287efcf5c6b32d3d2399905c6fc8dc9b4036d4196b80e10f + UNPACK /kaniko/stages/1 RUN touch /bli + CACHE HIT: dd8070993f952ce8287efcf5c6b32d3d2399905c6fc8dc9b4036d4196b80e10f SAVE FILES [/bli] /kaniko/deps/2 CLEAN FROM second AS final -UNPACK /kaniko/stages/1 -CACHE REDIRECT HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 -CACHE HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 + UNPACK /kaniko/stages/1 COPY --from=first /blubb /blubb -CACHE REDIRECT HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb -CACHE HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb + CACHE REDIRECT HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 + CACHE HIT: 8ef1283833b79b08b093a99de08ffc3fed1fbbf8fb328f81e9d7561af0524e95 COPY --from=third /bli /bli -CACHE HIT: e3d0a39d0f55303c063b93635b40f56d535f5bd2b48b770af66bf0fe61b7debc + CACHE REDIRECT HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb + CACHE HIT: c59fad0bd865d2ed209d0f7a29d55161a8332681a1b68abc9e98da2dca1254cb RUN ls -lah /blubb + CACHE HIT: e3d0a39d0f55303c063b93635b40f56d535f5bd2b48b770af66bf0fe61b7debc diff --git a/golden/testdata/test_issue_mz334/plans/plan b/golden/testdata/test_issue_mz334/plans/plan index 01e22a842..c62478fe8 100644 --- a/golden/testdata/test_issue_mz334/plans/plan +++ b/golden/testdata/test_issue_mz334/plans/plan @@ -1,24 +1,24 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /blubb SAVE STAGE /kaniko/stages/0 SAVE FILES [/blubb] /kaniko/deps/0 CLEAN FROM first AS second -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN touch /bla SAVE STAGE /kaniko/stages/1 CLEAN FROM second AS third -UNPACK /kaniko/stages/1 + UNPACK /kaniko/stages/1 RUN touch /bli SAVE FILES [/bli] /kaniko/deps/2 CLEAN FROM second AS final -UNPACK /kaniko/stages/1 + UNPACK /kaniko/stages/1 COPY --from=first /blubb /blubb COPY --from=third /bli /bli RUN ls -lah /blubb diff --git a/golden/testdata/test_issue_mz338/plans/plan b/golden/testdata/test_issue_mz338/plans/plan index 04f292f58..b809f8822 100644 --- a/golden/testdata/test_issue_mz338/plans/plan +++ b/golden/testdata/test_issue_mz338/plans/plan @@ -1,5 +1,5 @@ FROM alpine -STREAM alpine + STREAM alpine RUN rm -rf /blubb RUN touch /blubb RUN ls -lah /blubb diff --git a/golden/testdata/test_issue_mz480/Dockerfile b/golden/testdata/test_issue_mz480/Dockerfile index 306866c16..5de3e06b4 100644 --- a/golden/testdata/test_issue_mz480/Dockerfile +++ b/golden/testdata/test_issue_mz480/Dockerfile @@ -1,4 +1,4 @@ -FROM debian:12.10 AS base +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS base RUN install FROM base AS build diff --git a/golden/testdata/test_issue_mz480/plans/final b/golden/testdata/test_issue_mz480/plans/final index 992bd4185..ff52b9d00 100644 --- a/golden/testdata/test_issue_mz480/plans/final +++ b/golden/testdata/test_issue_mz480/plans/final @@ -1,16 +1,19 @@ -FROM debian:12.10 AS base -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS base + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 RUN install SAVE STAGE /kaniko/stages/0 CLEAN FROM base AS build -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN compile SAVE FILES [output] /kaniko/deps/1 CLEAN FROM base AS final -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=build output output PUSH [registry] + UPLOAD sha256:cf05a52c02353f0b2b6f9be0549ac916c3fb1dc8d4bacd405eac7f28562ec9f2 + UPLOAD RUN install + UPLOAD COPY --from=build output output diff --git a/golden/testdata/test_issue_mz480/plans/final_test b/golden/testdata/test_issue_mz480/plans/final_test index 285665f8a..966ce9073 100644 --- a/golden/testdata/test_issue_mz480/plans/final_test +++ b/golden/testdata/test_issue_mz480/plans/final_test @@ -1,22 +1,25 @@ -FROM debian:12.10 AS base -STREAM debian:12.10 +FROM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 AS base + STREAM debian@sha256:264982ff4d18000fa74540837e2c43ca5137a53a83f8f62c7b3803c0f0bdcd56 RUN install SAVE STAGE /kaniko/stages/0 CLEAN FROM base AS build -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN compile SAVE FILES [output] /kaniko/deps/1 CLEAN FROM base AS final -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=build output output PUSH [registry] + UPLOAD sha256:cf05a52c02353f0b2b6f9be0549ac916c3fb1dc8d4bacd405eac7f28562ec9f2 + UPLOAD RUN install + UPLOAD COPY --from=build output output SAVE STAGE /kaniko/stages/2 CLEAN FROM final AS test -UNPACK /kaniko/stages/2 + UNPACK /kaniko/stages/2 RUN test diff --git a/golden/testdata/test_issue_mz487/plans/plan b/golden/testdata/test_issue_mz487/plans/plan index d65f38b4e..e952cca15 100644 --- a/golden/testdata/test_issue_mz487/plans/plan +++ b/golden/testdata/test_issue_mz487/plans/plan @@ -1,16 +1,16 @@ FROM alpine AS base -STREAM alpine + STREAM alpine RUN install SAVE STAGE /kaniko/stages/0 CLEAN FROM base AS build -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN install more RUN compile SAVE FILES [output] /kaniko/deps/2 CLEAN FROM base AS final -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 COPY --from=build output output diff --git a/golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss b/golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss index 6206d7016..590e25b7f 100644 --- a/golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss +++ b/golden/testdata/test_issue_mz703/plans/legacy_stop_after_miss @@ -1,8 +1,8 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE HIT: ef4ba1bfa1a8010630d9a007fad694d95d88419c791f0053b5525169f21e3247 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /a -CACHE MISS: 3ae6b57ba75852932ecd2efd4039e0a7951e9fc5971f012d00b8070d4d4d1e77 + CACHE HIT: ef4ba1bfa1a8010630d9a007fad694d95d88419c791f0053b5525169f21e3247 RUN touch /b -CACHE MISS: 2f4043dde38e8a86a388c786d43c46606463533a2eca79177a7246698f9b62a7 + CACHE MISS: 3ae6b57ba75852932ecd2efd4039e0a7951e9fc5971f012d00b8070d4d4d1e77 RUN touch /c + CACHE MISS: 2f4043dde38e8a86a388c786d43c46606463533a2eca79177a7246698f9b62a7 diff --git a/golden/testdata/test_issue_mz703/plans/probe_after_miss b/golden/testdata/test_issue_mz703/plans/probe_after_miss index a9fde3b8a..a5b5adace 100644 --- a/golden/testdata/test_issue_mz703/plans/probe_after_miss +++ b/golden/testdata/test_issue_mz703/plans/probe_after_miss @@ -1,8 +1,8 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE HIT: ef4ba1bfa1a8010630d9a007fad694d95d88419c791f0053b5525169f21e3247 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /a -CACHE MISS: 3ae6b57ba75852932ecd2efd4039e0a7951e9fc5971f012d00b8070d4d4d1e77 + CACHE HIT: ef4ba1bfa1a8010630d9a007fad694d95d88419c791f0053b5525169f21e3247 RUN touch /b -CACHE HIT: 2f4043dde38e8a86a388c786d43c46606463533a2eca79177a7246698f9b62a7 + CACHE MISS: 3ae6b57ba75852932ecd2efd4039e0a7951e9fc5971f012d00b8070d4d4d1e77 RUN touch /c + CACHE HIT: 2f4043dde38e8a86a388c786d43c46606463533a2eca79177a7246698f9b62a7 diff --git a/golden/testdata/test_issue_mz791/plans/resolved_one b/golden/testdata/test_issue_mz791/plans/resolved_one index b249f84ca..493c2cd32 100644 --- a/golden/testdata/test_issue_mz791/plans/resolved_one +++ b/golden/testdata/test_issue_mz791/plans/resolved_one @@ -1,13 +1,13 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 44499f20592b9bc502443b107cde66f5aaebb8118bf60f19b9c93c80c2a34720 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /foo + CACHE MISS: 44499f20592b9bc502443b107cde66f5aaebb8118bf60f19b9c93c80c2a34720 SAVE FILES [/foo] /kaniko/deps/0 CLEAN FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS second -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE REDIRECT MISS: fb9685e713d8dbd0f8f76a16cdba32fe1f905e4c91d5fed40f71bf81c8bf4986 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f COPY --from=first /foo /$A/foo + CACHE REDIRECT MISS: fb9685e713d8dbd0f8f76a16cdba32fe1f905e4c91d5fed40f71bf81c8bf4986 diff --git a/golden/testdata/test_issue_mz791/plans/resolved_two b/golden/testdata/test_issue_mz791/plans/resolved_two index 7f8d48394..71ea0c127 100644 --- a/golden/testdata/test_issue_mz791/plans/resolved_two +++ b/golden/testdata/test_issue_mz791/plans/resolved_two @@ -1,13 +1,13 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 44499f20592b9bc502443b107cde66f5aaebb8118bf60f19b9c93c80c2a34720 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /foo + CACHE MISS: 44499f20592b9bc502443b107cde66f5aaebb8118bf60f19b9c93c80c2a34720 SAVE FILES [/foo] /kaniko/deps/0 CLEAN FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS second -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE REDIRECT MISS: da7bda88a042b33d3d7cd2496453a897b398574b34d0f3e8eef5ac11ee83647d + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f COPY --from=first /foo /$A/foo + CACHE REDIRECT MISS: da7bda88a042b33d3d7cd2496453a897b398574b34d0f3e8eef5ac11ee83647d diff --git a/golden/testdata/test_issue_mz791/plans/unresolved_one b/golden/testdata/test_issue_mz791/plans/unresolved_one index ea207fd59..e80ba626a 100644 --- a/golden/testdata/test_issue_mz791/plans/unresolved_one +++ b/golden/testdata/test_issue_mz791/plans/unresolved_one @@ -1,13 +1,13 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: fe269af13cc75f19ed91638e3eb570631f05caf9eafe2e2874df2f7601875143 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /foo + CACHE MISS: fe269af13cc75f19ed91638e3eb570631f05caf9eafe2e2874df2f7601875143 SAVE FILES [/foo] /kaniko/deps/0 CLEAN FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS second -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE REDIRECT MISS: 9f79e533c21d9231e1bf71b350e2b60f697ea705a9cd5233dfd9c8f3f8a75320 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f COPY --from=first /foo /$A/foo + CACHE REDIRECT MISS: 9f79e533c21d9231e1bf71b350e2b60f697ea705a9cd5233dfd9c8f3f8a75320 diff --git a/golden/testdata/test_issue_mz791/plans/unresolved_two b/golden/testdata/test_issue_mz791/plans/unresolved_two index ea207fd59..e80ba626a 100644 --- a/golden/testdata/test_issue_mz791/plans/unresolved_two +++ b/golden/testdata/test_issue_mz791/plans/unresolved_two @@ -1,13 +1,13 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS first -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: fe269af13cc75f19ed91638e3eb570631f05caf9eafe2e2874df2f7601875143 + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d RUN touch /foo + CACHE MISS: fe269af13cc75f19ed91638e3eb570631f05caf9eafe2e2874df2f7601875143 SAVE FILES [/foo] /kaniko/deps/0 CLEAN FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d AS second -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE REDIRECT MISS: 9f79e533c21d9231e1bf71b350e2b60f697ea705a9cd5233dfd9c8f3f8a75320 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f COPY --from=first /foo /$A/foo + CACHE REDIRECT MISS: 9f79e533c21d9231e1bf71b350e2b60f697ea705a9cd5233dfd9c8f3f8a75320 diff --git a/golden/testdata/test_issue_mz813/plans/resolved_one b/golden/testdata/test_issue_mz813/plans/resolved_one index 9165173a0..239c47207 100644 --- a/golden/testdata/test_issue_mz813/plans/resolved_one +++ b/golden/testdata/test_issue_mz813/plans/resolved_one @@ -1,6 +1,6 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE MISS: 716062abb9a4684d50376c8b6691dd79fe73a4a0de751db16f1159549d0d2b51 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f WORKDIR /$A/foo + CACHE MISS: 716062abb9a4684d50376c8b6691dd79fe73a4a0de751db16f1159549d0d2b51 diff --git a/golden/testdata/test_issue_mz813/plans/resolved_two b/golden/testdata/test_issue_mz813/plans/resolved_two index 24cba1028..cd7a95c8c 100644 --- a/golden/testdata/test_issue_mz813/plans/resolved_two +++ b/golden/testdata/test_issue_mz813/plans/resolved_two @@ -1,6 +1,6 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE MISS: 87fefee7e0e2cfe9bd247e7a7e5c4310f38763f0eb6abf1a2315183807e84bb9 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f WORKDIR /$A/foo + CACHE MISS: 87fefee7e0e2cfe9bd247e7a7e5c4310f38763f0eb6abf1a2315183807e84bb9 diff --git a/golden/testdata/test_issue_mz813/plans/unresolved_one b/golden/testdata/test_issue_mz813/plans/unresolved_one index 55a7beddf..c8aea070d 100644 --- a/golden/testdata/test_issue_mz813/plans/unresolved_one +++ b/golden/testdata/test_issue_mz813/plans/unresolved_one @@ -1,6 +1,6 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE MISS: 0a736be98d25e4f2e811ec8d82a0604e86913120d75246761c80483e48438532 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f WORKDIR /$A/foo + CACHE MISS: 0a736be98d25e4f2e811ec8d82a0604e86913120d75246761c80483e48438532 diff --git a/golden/testdata/test_issue_mz813/plans/unresolved_two b/golden/testdata/test_issue_mz813/plans/unresolved_two index 55a7beddf..c8aea070d 100644 --- a/golden/testdata/test_issue_mz813/plans/unresolved_two +++ b/golden/testdata/test_issue_mz813/plans/unresolved_two @@ -1,6 +1,6 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE MISS: 0a736be98d25e4f2e811ec8d82a0604e86913120d75246761c80483e48438532 + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f WORKDIR /$A/foo + CACHE MISS: 0a736be98d25e4f2e811ec8d82a0604e86913120d75246761c80483e48438532 diff --git a/golden/testdata/test_issue_mz822/plans/resolved_one b/golden/testdata/test_issue_mz822/plans/resolved_one index 1322dfd8d..f003edcd7 100644 --- a/golden/testdata/test_issue_mz822/plans/resolved_one +++ b/golden/testdata/test_issue_mz822/plans/resolved_one @@ -1,6 +1,6 @@ FROM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d -CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f + STREAM busybox@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d ARG A -CACHE MISS: b5b1f6f264c7b5df52961b7297debb1015ca25012f68c84621ca990324ac12bc + CACHE MISS: 8572931eed3c707f392e914b1a74ea1fb62462a1fb923359b40268b89f68695f COPY < /hi SAVE FILES [/hi] /kaniko/deps/1 CLEAN FROM alpine:3.11 -STREAM alpine:3.11 + STREAM alpine:3.11 COPY --from=base-prod /hi /finalhi RUN cat /finalhi diff --git a/golden/testdata/test_unittests/plans/final_wo_deps_buzz b/golden/testdata/test_unittests/plans/final_wo_deps_buzz index 0a344d189..cf1b43678 100644 --- a/golden/testdata/test_unittests/plans/final_wo_deps_buzz +++ b/golden/testdata/test_unittests/plans/final_wo_deps_buzz @@ -1,3 +1,3 @@ FROM alpine:3.11 AS buzz -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo buzz > /buzz diff --git a/golden/testdata/test_unittests/plans/final_wo_deps_final b/golden/testdata/test_unittests/plans/final_wo_deps_final index 3abc5fd6b..e268b67ec 100644 --- a/golden/testdata/test_unittests/plans/final_wo_deps_final +++ b/golden/testdata/test_unittests/plans/final_wo_deps_final @@ -1,3 +1,3 @@ FROM alpine:3.11 AS final -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo bar > /bar diff --git a/golden/testdata/test_unittests/plans/final_wo_deps_fizz b/golden/testdata/test_unittests/plans/final_wo_deps_fizz index 4daf46675..46285917f 100644 --- a/golden/testdata/test_unittests/plans/final_wo_deps_fizz +++ b/golden/testdata/test_unittests/plans/final_wo_deps_fizz @@ -1,10 +1,10 @@ FROM debian:12.10 AS base -STREAM debian:12.10 + STREAM debian:12.10 RUN echo foo > /foo SAVE FILES [/foo] /kaniko/deps/1 CLEAN FROM debian:12.10 AS fizz -STREAM debian:12.10 + STREAM debian:12.10 RUN echo fizz >> /fizz COPY --from=base /foo /fizz diff --git a/golden/testdata/test_unittests/plans/global_arg b/golden/testdata/test_unittests/plans/global_arg index efce37b77..4e05f7239 100644 --- a/golden/testdata/test_unittests/plans/global_arg +++ b/golden/testdata/test_unittests/plans/global_arg @@ -1,3 +1,3 @@ FROM alpine:3.11 AS stage2 -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo "stage2" > /stage2.txt diff --git a/golden/testdata/test_unittests/plans/global_arg_stage1 b/golden/testdata/test_unittests/plans/global_arg_stage1 index 3bcc6ce8c..305f850f9 100644 --- a/golden/testdata/test_unittests/plans/global_arg_stage1 +++ b/golden/testdata/test_unittests/plans/global_arg_stage1 @@ -1,3 +1,3 @@ FROM alpine:3.11 AS stage1 -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo "stage1" > /stage1.txt diff --git a/golden/testdata/test_unittests/plans/multiple_copy b/golden/testdata/test_unittests/plans/multiple_copy index aa5392dd8..9820af0e6 100644 --- a/golden/testdata/test_unittests/plans/multiple_copy +++ b/golden/testdata/test_unittests/plans/multiple_copy @@ -1,12 +1,12 @@ FROM alpine:3.11 AS builder -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo "file1" > /file1.txt RUN echo "file2" > /file2.txt SAVE FILES [/file1.txt /file2.txt] /kaniko/deps/0 CLEAN FROM alpine:3.11 -STREAM alpine:3.11 + STREAM alpine:3.11 COPY --from=builder /file1.txt /dest1/ COPY --from=builder /file2.txt /dest2/ COPY --from=builder /file1.txt /dest3/ diff --git a/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base b/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base index cc00b0a0b..d220f75a6 100644 --- a/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base +++ b/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_base @@ -1,3 +1,3 @@ FROM debian:12.10 AS base -STREAM debian:12.10 + STREAM debian:12.10 COPY . . diff --git a/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final b/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final index d31dbda3a..8a67c69ce 100644 --- a/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final +++ b/golden/testdata/test_unittests/plans/two_copyfrom_and_arg_final @@ -1,19 +1,19 @@ FROM debian:12.10 AS base -STREAM debian:12.10 + STREAM debian:12.10 COPY . . SAVE STAGE /kaniko/stages/0 SAVE FILES [context/b* context/foo] /kaniko/deps/0 CLEAN FROM scratch AS second -STREAM scratch + STREAM scratch ENV foopath context/foo COPY --from=0 $foopath context/b* /foo/ SAVE FILES [/foo] /kaniko/deps/1 CLEAN FROM base -UNPACK /kaniko/stages/0 + UNPACK /kaniko/stages/0 RUN date > /date ENV foo bar ARG file=/foo2 diff --git a/golden/testdata/test_unittests/plans/two_copyfrom_final b/golden/testdata/test_unittests/plans/two_copyfrom_final index 9e5399648..86166e0a2 100644 --- a/golden/testdata/test_unittests/plans/two_copyfrom_final +++ b/golden/testdata/test_unittests/plans/two_copyfrom_final @@ -1,17 +1,17 @@ FROM alpine:3.11 AS base-dev -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo dev > /hi SAVE FILES [/hi] /kaniko/deps/0 CLEAN FROM alpine:3.11 AS base-prod -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo prod > /hi SAVE FILES [/hi] /kaniko/deps/1 CLEAN FROM alpine:3.11 -STREAM alpine:3.11 + STREAM alpine:3.11 COPY --from=base-dev /hi /finalhidev COPY --from=base-prod /hi /finalhiprod RUN cat /finalhidev diff --git a/golden/testdata/test_unittests/plans/wo_copyfrom_dev b/golden/testdata/test_unittests/plans/wo_copyfrom_dev index 50a372b0a..8708ba58c 100644 --- a/golden/testdata/test_unittests/plans/wo_copyfrom_dev +++ b/golden/testdata/test_unittests/plans/wo_copyfrom_dev @@ -1,3 +1,3 @@ FROM alpine:3.11 AS base-dev -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo dev > /hi diff --git a/golden/testdata/test_unittests/plans/wo_copyfrom_final b/golden/testdata/test_unittests/plans/wo_copyfrom_final index 63cc304b1..96ff676aa 100644 --- a/golden/testdata/test_unittests/plans/wo_copyfrom_final +++ b/golden/testdata/test_unittests/plans/wo_copyfrom_final @@ -1,4 +1,4 @@ FROM alpine:3.11 AS final-stage -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo dev > /hi RUN cat /hi diff --git a/golden/testdata/test_unittests/plans/wo_copyfrom_prod b/golden/testdata/test_unittests/plans/wo_copyfrom_prod index 6812d77cd..078ed0c4f 100644 --- a/golden/testdata/test_unittests/plans/wo_copyfrom_prod +++ b/golden/testdata/test_unittests/plans/wo_copyfrom_prod @@ -1,3 +1,3 @@ FROM alpine:3.11 AS base-prod -STREAM alpine:3.11 + STREAM alpine:3.11 RUN echo prod > /hi diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 0e50fd459..3dca11595 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -1098,30 +1098,58 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts if opts.PreCleanup { printf("CLEAN\n") } + stageLayers := map[int][]string{} for _, s := range stages { if s.Name != "" { printf("FROM %s AS %s\n", s.BaseName, s.Name) } else { printf("FROM %s\n", s.BaseName) } - switch { - case s.BaseImageStoredLocally: - printf("UNPACK %s%d\n", config.KanikoIntermediateStagesDir, s.BaseImageIndex) - case s.BaseImageShared: - printf("FETCH %s\n", s.BaseName) - printf("UNPACK %s\n", s.BaseName) - default: - printf("STREAM %s\n", s.BaseName) + var layers []string + if s.BaseImageStoredLocally { + printf(" UNPACK %s%d\n", config.KanikoIntermediateStagesDir, s.BaseImageIndex) + layers = slices.Clone(stageLayers[s.BaseImageIndex]) + } else { + if s.BaseImageShared { + printf(" FETCH %s\n", s.BaseName) + printf(" UNPACK %s\n", s.BaseName) + } else { + printf(" STREAM %s\n", s.BaseName) + } + if s.BaseImageDigest != "" { + base, err := image_util.RetrieveSourceImage(s, opts) + if err != nil { + return err + } + manifest, err := base.Manifest() + if err != nil { + return err + } + for _, l := range manifest.Layers { + layers = append(layers, l.Digest.String()) + } + } } for jdx, c := range s.Commands { + command, err := commands.GetCommand(c, fileContext, opts.Secrets, opts.RunV2, opts.CacheCopyLayers, opts.CacheRunLayers) + if err != nil { + return err + } + if command == nil { + continue + } + printf("%s\n", command) + if !command.MetadataOnly() { + layers = append(layers, command.String()) + } if opts.Cache && opts.CacheCopyLayers && config.FF.InferCrossStageCacheKey && config.FF.CacheLookahead { if copyCmd, ok := c.(*instructions.CopyCommand); ok && copyCmd.From != "" { ci := cacheInfo[s.Index] if ck := ci.redirectKeys[jdx]; ck != "" { if ci.redirectHits[jdx] { - printf("CACHE REDIRECT HIT: %s\n", ck) + printf(" CACHE REDIRECT HIT: %s\n", ck) } else { - printf("CACHE REDIRECT MISS: %s\n", ck) + printf(" CACHE REDIRECT MISS: %s\n", ck) } } } @@ -1130,23 +1158,25 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts ci := cacheInfo[s.Index] if ck := ci.cacheKeys[jdx]; ck != "" { if ci.cacheHits[jdx] { - printf("CACHE HIT: %s\n", ck) + printf(" CACHE HIT: %s\n", ck) } else { - printf("CACHE MISS: %s\n", ck) + printf(" CACHE MISS: %s\n", ck) + if !opts.NoPushCache && command.ShouldCacheOutput() { + cacheRef, err := cache.Destination(opts, ck) + if err == nil { + printf(" UPLOAD %s\n", cacheRef) + } + } } } } - command, err := commands.GetCommand(c, fileContext, opts.Secrets, opts.RunV2, opts.CacheCopyLayers, opts.CacheRunLayers) - if err != nil { - return err - } - if command == nil { - continue - } - printf("%s\n", command) } + stageLayers[s.Index] = layers if s.Push && !opts.NoPush { printf("PUSH %v\n", opts.Destinations) + for _, l := range layers { + printf(" UPLOAD %s\n", l) + } } if s.Final { if opts.Cleanup { From 6e8cf664c12e63fcbee084ff087c38a3631d7167 Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Sun, 9 Aug 2026 16:39:54 +0100 Subject: [PATCH 2/3] Mount layers the destination registry already holds --- README.md | 7 ++ golden/testdata/test_issue_mz989/test.go | 6 ++ integration/images.go | 1 + pkg/cache/cache.go | 4 + pkg/config/featureflags.go | 2 + pkg/executor/push.go | 11 ++- pkg/mounts/mounts.go | 108 +++++++++++++++++++++++ 7 files changed, 138 insertions(+), 1 deletion(-) create mode 100644 pkg/mounts/mounts.go diff --git a/README.md b/README.md index 70ed401bd..72d043907 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ expect - see [Known Issues](#known-issues). - [Flag `FF_KANIKO_EXPAND_HEREDOC`](#flag-ff_kaniko_expand_heredoc) - [Flag `FF_KANIKO_SKIP_CACHED_STAGES`](#flag-ff_kaniko_skip_cached_stages) - [Flag `FF_KANIKO_SHARED_BASE_CACHE`](#flag-ff_kaniko_shared_base_cache) + - [Flag `FF_KANIKO_CROSS_REPO_MOUNT`](#flag-ff_kaniko_cross_repo_mount) - [Assertion Overrides](#assertion-overrides) - [Telemetry](#telemetry) - [Debug Image](#debug-image) @@ -1428,6 +1429,12 @@ Stored bases stay in `/kaniko/bases` after the build, `--cleanup` does not remov Defaults to `false`. Becomes default in `v1.29.0`. +#### Flag `FF_KANIKO_CROSS_REPO_MOUNT` + +A registry can copy a blob between its own repositories for free, but only if it is told which repository already holds it. Kaniko loses that as soon as it copies a layer locally, so with `--cache` every built layer goes up twice, once to the cache repo and once inside the image. Set this flag to `true` to remember which layers can be mounted and which ones need to be pushed. +Defaults to `false`. +Becomes default in `v1.29.0`. + ### Assertion Overrides Kaniko checks internal invariants at runtime. If one is violated the build stops with a message like: diff --git a/golden/testdata/test_issue_mz989/test.go b/golden/testdata/test_issue_mz989/test.go index 4b20d857a..5a12fb614 100644 --- a/golden/testdata/test_issue_mz989/test.go +++ b/golden/testdata/test_issue_mz989/test.go @@ -16,6 +16,12 @@ var Tests = types.GoldenTests{ Args: []string{"-d", "example.com/img:latest"}, Plan: "plain", }, + { + // The mount decision is made at push time, so the plan does not move. + Args: []string{"-d", "example.com/img:latest"}, + Env: map[string]string{"FF_KANIKO_CROSS_REPO_MOUNT": "1"}, + Plan: "plain", + }, { // The store hands the push a local copy, and the base uploads instead. Args: []string{"-d", "example.com/img:latest"}, diff --git a/integration/images.go b/integration/images.go index 83fac1357..0e351f7f0 100644 --- a/integration/images.go +++ b/integration/images.go @@ -126,6 +126,7 @@ var KanikoEnv = []string{ "FF_KANIKO_SKIP_WRITE_WHITEOUTS=1", "FF_KANIKO_SKIP_RELABEL_RECOMPRESS=1", "FF_KANIKO_SHARED_BASE_CACHE=1", + "FF_KANIKO_CROSS_REPO_MOUNT=1", "KANIKO_PRINT_PLAN=1", "KANIKO_TELEMETRY_ENDPOINT", "OTEL_EXPORTER_OTLP_HEADERS", diff --git a/pkg/cache/cache.go b/pkg/cache/cache.go index 9e9b98f55..17868945d 100644 --- a/pkg/cache/cache.go +++ b/pkg/cache/cache.go @@ -32,6 +32,7 @@ import ( "github.com/google/go-containerregistry/pkg/v1/tarball" "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/creds" + "github.com/osscontainertools/kaniko/pkg/mounts" "github.com/osscontainertools/kaniko/pkg/util" "github.com/sirupsen/logrus" ) @@ -81,6 +82,9 @@ func (rc *RegistryCache) RetrieveLayer(ck string) (v1.Image, error) { if err = verifyImage(img, rc.Opts.CacheTTL, cache); err != nil { return nil, err } + if config.FF.CrossRepoMount { + mounts.RecordImage(img, cacheRef.Context()) + } return img, nil } diff --git a/pkg/config/featureflags.go b/pkg/config/featureflags.go index 4f8e58a7c..9f15dcd95 100644 --- a/pkg/config/featureflags.go +++ b/pkg/config/featureflags.go @@ -34,6 +34,7 @@ type FeatureFlags struct { CleanKanikoDir bool CopyAsRoot bool CopyChmodOnImplicitDirs bool + CrossRepoMount bool DeprecateInterStageRestore bool DisableHTTP2 bool ExpandHeredoc bool @@ -104,6 +105,7 @@ func InitFeatureFlags() { CleanKanikoDir: featureFlag("FF_KANIKO_CLEAN_KANIKO_DIR", true), CopyAsRoot: featureFlag("FF_KANIKO_COPY_AS_ROOT", false), CopyChmodOnImplicitDirs: featureFlag("FF_KANIKO_COPY_CHMOD_ON_IMPLICIT_DIRS", false), + CrossRepoMount: featureFlag("FF_KANIKO_CROSS_REPO_MOUNT", false), DeprecateInterStageRestore: featureFlag("FF_KANIKO_DEPRECATE_INTER_STAGE_RESTORE", true), DisableHTTP2: featureFlag("FF_KANIKO_DISABLE_HTTP2", false), ExpandHeredoc: featureFlag("FF_KANIKO_EXPAND_HEREDOC", false), diff --git a/pkg/executor/push.go b/pkg/executor/push.go index 6b9628ef1..29bb1197a 100644 --- a/pkg/executor/push.go +++ b/pkg/executor/push.go @@ -40,6 +40,7 @@ import ( "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/constants" "github.com/osscontainertools/kaniko/pkg/creds" + "github.com/osscontainertools/kaniko/pkg/mounts" "github.com/osscontainertools/kaniko/pkg/timing" "github.com/osscontainertools/kaniko/pkg/util" "github.com/osscontainertools/kaniko/pkg/version" @@ -290,6 +291,10 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error { rt := &withUserAgent{t: tr} logrus.Infof("Pushing image to %s", destRef.String()) + pushImage := image + if config.FF.CrossRepoMount { + pushImage = mounts.Mountable(image, destRef.RegistryStr()) + } retryFunc := func() error { dig, err := image.Digest() @@ -297,7 +302,7 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error { return err } digest := destRef.Context().Digest(dig.String()) - if err := remote.Write(destRef, image, remote.WithAuth(pushAuth), remote.WithTransport(rt)); err != nil { + if err := remote.Write(destRef, pushImage, remote.WithAuth(pushAuth), remote.WithTransport(rt)); err != nil { if !opts.PushIgnoreImmutableTagErrors { return err } @@ -313,6 +318,10 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error { return err } logrus.Infof("Pushed %s", digest) + // pushLayerToCache funnels through here, so cache entries land here too. + if config.FF.CrossRepoMount { + mounts.RecordImage(image, destRef.Context()) + } return nil } diff --git a/pkg/mounts/mounts.go b/pkg/mounts/mounts.go new file mode 100644 index 000000000..0117d323b --- /dev/null +++ b/pkg/mounts/mounts.go @@ -0,0 +1,108 @@ +/* +Copyright 2026 OSS Container Tools + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +// Package mounts remembers which repositories hold a layer, so a push can have the +// destination registry mount a blob instead of taking the bytes. +// +// remote.Write only offers a mount for layers still carrying the reference they were pulled +// from, which every local copy kaniko makes throws away. Keyed by digest rather than held on +// the layer, so a copy that keeps the bytes keeps the entry and one that rewrites them misses. +// +// Only repositories this process read from or wrote to belong here. remote.Write fails a push +// outright when the token request for a mount source is refused, so an unproven entry is not +// a missed optimisation but a broken build. +package mounts + +import ( + "slices" + "sync" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/remote" +) + +var ( + mu sync.Mutex + sources = map[v1.Hash][]name.Repository{} +) + +func RecordImage(img v1.Image, repo name.Repository) { + layers, err := img.Layers() + if err != nil { + return + } + mu.Lock() + defer mu.Unlock() + for _, l := range layers { + digest, err := l.Digest() + if err == nil { + _, known := find(sources[digest], func(r name.Repository) bool { return r.String() == repo.String() }) + if !known { + sources[digest] = append(sources[digest], repo) + } + } + } +} + +func find(repos []name.Repository, match func(name.Repository) bool) (name.Repository, bool) { + i := slices.IndexFunc(repos, match) + if i < 0 { + return name.Repository{}, false + } + return repos[i], true +} + +func Mountable(img v1.Image, registry string) v1.Image { + return &mountableImage{Image: img, registry: registry} +} + +type mountableImage struct { + v1.Image + + registry string +} + +// Cross-registry origins are not honoured in practice, so a source off the registry being +// pushed to is no source at all. +func mountable(l v1.Layer, digest v1.Hash, candidates []name.Repository, registry string) v1.Layer { + repo, ok := find(candidates, func(r name.Repository) bool { return r.RegistryStr() == registry }) + if !ok { + return l + } + return &remote.MountableLayer{Layer: l, Reference: repo.Digest(digest.String())} +} + +// Layers is the only accessor remote.Write reads to decide what it sends, so LayerByDigest +// and LayerByDiffID are deliberately left untagged. +func (m *mountableImage) Layers() ([]v1.Layer, error) { + layers, err := m.Image.Layers() + if err != nil { + return nil, err + } + tagged := make([]v1.Layer, 0, len(layers)) + mu.Lock() + defer mu.Unlock() + for _, l := range layers { + digest, err := l.Digest() + if err == nil { + tagged = append(tagged, mountable(l, digest, sources[digest], m.registry)) + } else { + tagged = append(tagged, l) + } + } + return tagged, nil +} From fb1dc8e9fdd088b33a7a5f972213dca870e07923 Mon Sep 17 00:00:00 2001 From: Martin Zihlmann Date: Sun, 9 Aug 2026 17:46:07 +0100 Subject: [PATCH 3/3] Show in the plan which pushed layers the cache repo can serve --- README.md | 2 +- golden/golden_test.go | 52 +++++++++++++- .../testdata/test_issue_mz989/plans/cache_hit | 4 +- .../test_issue_mz989/plans/cache_miss | 4 +- .../testdata/test_issue_mz989/plans/rekeyed | 4 +- .../test_issue_mz989/plans/single_snapshot | 10 +++ golden/testdata/test_issue_mz989/test.go | 13 +++- pkg/executor/build.go | 71 +++++++++++++++---- pkg/executor/push.go | 2 +- pkg/mounts/mounts.go | 53 ++++++++------ 10 files changed, 167 insertions(+), 48 deletions(-) create mode 100644 golden/testdata/test_issue_mz989/plans/single_snapshot diff --git a/README.md b/README.md index 72d043907..d9d0698a4 100644 --- a/README.md +++ b/README.md @@ -1431,7 +1431,7 @@ Becomes default in `v1.29.0`. #### Flag `FF_KANIKO_CROSS_REPO_MOUNT` -A registry can copy a blob between its own repositories for free, but only if it is told which repository already holds it. Kaniko loses that as soon as it copies a layer locally, so with `--cache` every built layer goes up twice, once to the cache repo and once inside the image. Set this flag to `true` to remember which layers can be mounted and which ones need to be pushed. +A registry can copy a blob between its own repositories for free, but only if it is told which repository already holds it. Kaniko loses that as soon as it copies a layer locally. Worse, with `--cache` every built layer goes up twice, once to the cache repo and once inside the image. Set this flag to `true` to remember which layers can be mounted remotely and which ones genuinely need to be pushed. Defaults to `false`. Becomes default in `v1.29.0`. diff --git a/golden/golden_test.go b/golden/golden_test.go index 4c23da283..a9ac3c0ee 100644 --- a/golden/golden_test.go +++ b/golden/golden_test.go @@ -20,6 +20,7 @@ import ( "bytes" "errors" "flag" + "io" "os" "path/filepath" "slices" @@ -28,9 +29,11 @@ import ( "testing" "github.com/google/go-cmp/cmp" + "github.com/google/go-containerregistry/pkg/name" v1 "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/empty" "github.com/google/go-containerregistry/pkg/v1/mutate" + ggcrtypes "github.com/google/go-containerregistry/pkg/v1/types" "github.com/osscontainertools/kaniko/cmd/executor/cmd" testissuemz195 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz195" testissuemz333 "github.com/osscontainertools/kaniko/golden/testdata/test_issue_mz333" @@ -49,6 +52,7 @@ import ( "github.com/osscontainertools/kaniko/pkg/cache" "github.com/osscontainertools/kaniko/pkg/config" "github.com/osscontainertools/kaniko/pkg/executor" + "github.com/osscontainertools/kaniko/pkg/mounts" "github.com/sirupsen/logrus" "github.com/spf13/cobra" ) @@ -57,16 +61,58 @@ import ( const cachePointerLabel = "kaniko.cache.pointer-target" type fakeLayerCache struct { + opts *config.KanikoOptions cachedKeys []string } +// fakeLayer stands in for a cache entry's layer. Its content is the key that found it, so its +// digest is derived rather than fixed by hand and stays stable across runs. +type fakeLayer struct { + key string +} + +func (l *fakeLayer) Digest() (v1.Hash, error) { return l.hash() } +func (l *fakeLayer) DiffID() (v1.Hash, error) { return l.hash() } +func (l *fakeLayer) Size() (int64, error) { return int64(len(l.key)), nil } + +func (l *fakeLayer) MediaType() (ggcrtypes.MediaType, error) { return ggcrtypes.DockerLayer, nil } +func (l *fakeLayer) Compressed() (io.ReadCloser, error) { return l.reader(), nil } + +func (l *fakeLayer) Uncompressed() (io.ReadCloser, error) { return l.reader(), nil } + +func (l *fakeLayer) hash() (v1.Hash, error) { + return mounts.PlannedDigest(l.key), nil +} + +func (l *fakeLayer) reader() io.ReadCloser { + return io.NopCloser(strings.NewReader(l.key)) +} + func (f *fakeLayerCache) RetrieveLayer(key string) (v1.Image, error) { if !slices.Contains(f.cachedKeys, key) { return nil, errors.New("could not find layer") } cf := &v1.ConfigFile{} cf.Config.Labels = map[string]string{cachePointerLabel: key} - return mutate.ConfigFile(empty.Image, cf) + img, err := mutate.ConfigFile(empty.Image, cf) + if err != nil { + return nil, err + } + img, err = mutate.AppendLayers(img, &fakeLayer{key: key}) + if err != nil { + return nil, err + } + // The real registry cache records where it read from, and the plan reads that back. + if config.FF.CrossRepoMount { + dest, err := cache.Destination(f.opts, key) + if err == nil { + tag, err := name.NewTag(dest, name.WeakValidation) + if err == nil { + mounts.RecordImage(img, tag.Context()) + } + } + } + return img, nil } func renderCommand(env map[string]string, args []string) string { @@ -134,8 +180,8 @@ func TestRun(t *testing.T) { opts := config.KanikoOptions{} origNewLayerCache := executor.NewLayerCache - executor.NewLayerCache = func(_ *config.KanikoOptions) cache.LayerCache { - return &fakeLayerCache{cachedKeys: test.CachedKeys} + executor.NewLayerCache = func(opts *config.KanikoOptions) cache.LayerCache { + return &fakeLayerCache{opts: opts, cachedKeys: test.CachedKeys} } t.Cleanup(func() { executor.NewLayerCache = origNewLayerCache }) exec := &cobra.Command{ diff --git a/golden/testdata/test_issue_mz989/plans/cache_hit b/golden/testdata/test_issue_mz989/plans/cache_hit index 4598904a1..b5be14cf2 100644 --- a/golden/testdata/test_issue_mz989/plans/cache_hit +++ b/golden/testdata/test_issue_mz989/plans/cache_hit @@ -6,5 +6,5 @@ RUN touch /bla CACHE HIT: c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784 PUSH [example.com/img:latest] UPLOAD sha256:1b7ca6aea1ddfe716f3694edb811ab35114db9e93f3ce38d7dab6b4d9270cb0c - UPLOAD RUN touch /blubb - UPLOAD RUN touch /bla + MOUNT RUN touch /blubb FROM example.com/cache + MOUNT RUN touch /bla FROM example.com/cache diff --git a/golden/testdata/test_issue_mz989/plans/cache_miss b/golden/testdata/test_issue_mz989/plans/cache_miss index 473549386..48b630a54 100644 --- a/golden/testdata/test_issue_mz989/plans/cache_miss +++ b/golden/testdata/test_issue_mz989/plans/cache_miss @@ -8,5 +8,5 @@ RUN touch /bla UPLOAD example.com/cache:c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784 PUSH [example.com/img:latest] UPLOAD sha256:1b7ca6aea1ddfe716f3694edb811ab35114db9e93f3ce38d7dab6b4d9270cb0c - UPLOAD RUN touch /blubb - UPLOAD RUN touch /bla + MOUNT RUN touch /blubb FROM example.com/cache + MOUNT RUN touch /bla FROM example.com/cache diff --git a/golden/testdata/test_issue_mz989/plans/rekeyed b/golden/testdata/test_issue_mz989/plans/rekeyed index 4598904a1..b5be14cf2 100644 --- a/golden/testdata/test_issue_mz989/plans/rekeyed +++ b/golden/testdata/test_issue_mz989/plans/rekeyed @@ -6,5 +6,5 @@ RUN touch /bla CACHE HIT: c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784 PUSH [example.com/img:latest] UPLOAD sha256:1b7ca6aea1ddfe716f3694edb811ab35114db9e93f3ce38d7dab6b4d9270cb0c - UPLOAD RUN touch /blubb - UPLOAD RUN touch /bla + MOUNT RUN touch /blubb FROM example.com/cache + MOUNT RUN touch /bla FROM example.com/cache diff --git a/golden/testdata/test_issue_mz989/plans/single_snapshot b/golden/testdata/test_issue_mz989/plans/single_snapshot new file mode 100644 index 000000000..3c2d1746a --- /dev/null +++ b/golden/testdata/test_issue_mz989/plans/single_snapshot @@ -0,0 +1,10 @@ +FROM alpine@sha256:c75ac27b49326926b803b9ed43bf088bc220d22556de1bc5f72d742c91398f69 + STREAM alpine@sha256:c75ac27b49326926b803b9ed43bf088bc220d22556de1bc5f72d742c91398f69 +RUN touch /blubb + CACHE MISS: 9960b0560d3e4212d47329ac9e3379b8891474e43756b7650ae3bc18092b62f7 +RUN touch /bla + CACHE MISS: c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784 + UPLOAD example.com/cache:c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784 +PUSH [example.com/img:latest] + UPLOAD sha256:1b7ca6aea1ddfe716f3694edb811ab35114db9e93f3ce38d7dab6b4d9270cb0c + MOUNT RUN touch /bla FROM example.com/cache diff --git a/golden/testdata/test_issue_mz989/test.go b/golden/testdata/test_issue_mz989/test.go index 5a12fb614..7775f7e26 100644 --- a/golden/testdata/test_issue_mz989/test.go +++ b/golden/testdata/test_issue_mz989/test.go @@ -32,26 +32,33 @@ var Tests = types.GoldenTests{ // Every missed layer reaches example.com/cache before the image push // sends the same blob to example.com/img. Args: []string{"-d", "example.com/img:latest", "--cache", "--cache-repo", "example.com/cache"}, - Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1"}, + Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1", "FF_KANIKO_CROSS_REPO_MOUNT": "1"}, Plan: "cache_miss", }, { // Both layers are read out of example.com/cache and then uploaded to // example.com/img anyway. Args: []string{"-d", "example.com/img:latest", "--cache", "--cache-repo", "example.com/cache"}, - Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1"}, + Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1", "FF_KANIKO_CROSS_REPO_MOUNT": "1"}, CachedKeys: []string{ "9960b0560d3e4212d47329ac9e3379b8891474e43756b7650ae3bc18092b62f7", "c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784", }, Plan: "cache_hit", }, + { + // --single-snapshot builds one layer for the whole stage, so only the last + // command reaches the cache repo or the push. + Args: []string{"-d", "example.com/img:latest", "--cache", "--cache-repo", "example.com/cache", "--single-snapshot"}, + Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1", "FF_KANIKO_CROSS_REPO_MOUNT": "1"}, + Plan: "single_snapshot", + }, { // Baseline. The cache entry is zstd against a gzip image, so // convertLayerMediaType recompresses it and the layer that gets pushed is // not the blob the cache repo holds. These uploads must stay uploads. Args: []string{"-d", "example.com/img:latest", "--cache", "--cache-repo", "example.com/cache", "--compression", "zstd"}, - Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1"}, + Env: map[string]string{"FF_KANIKO_CACHE_LOOKAHEAD": "1", "FF_KANIKO_CROSS_REPO_MOUNT": "1"}, CachedKeys: []string{ "9960b0560d3e4212d47329ac9e3379b8891474e43756b7650ae3bc18092b62f7", "c4d1d053ed51898d12bc0fe84e96f70fc77ad862f9e38b677cf97c1cddd78784", diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 3dca11595..d7d1602dd 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -51,6 +51,7 @@ import ( "github.com/osscontainertools/kaniko/pkg/dockerfile" image_util "github.com/osscontainertools/kaniko/pkg/image" "github.com/osscontainertools/kaniko/pkg/image/remote" + "github.com/osscontainertools/kaniko/pkg/mounts" "github.com/osscontainertools/kaniko/pkg/snapshot" "github.com/osscontainertools/kaniko/pkg/timing" "github.com/osscontainertools/kaniko/pkg/util" @@ -1085,7 +1086,12 @@ var ( Out io.Writer = os.Stdout ) -func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts *config.KanikoOptions, fileContext util.FileContext, crossStageDependencies map[int][]string) (retErr error) { +type pushedLayer struct { + name string + key v1.Hash +} + +func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts *config.KanikoOptions, fileContext util.FileContext, crossStageDependencies map[int][]string, layerCache *memoizedLayerCache) (retErr error) { printf := func(format string, args ...any) { if retErr == nil { _, retErr = fmt.Fprintf(Out, format, args...) @@ -1098,14 +1104,15 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts if opts.PreCleanup { printf("CLEAN\n") } - stageLayers := map[int][]string{} + sources := mounts.Snapshot() + stageLayers := map[int][]pushedLayer{} for _, s := range stages { if s.Name != "" { printf("FROM %s AS %s\n", s.BaseName, s.Name) } else { printf("FROM %s\n", s.BaseName) } - var layers []string + var layers []pushedLayer if s.BaseImageStoredLocally { printf(" UNPACK %s%d\n", config.KanikoIntermediateStagesDir, s.BaseImageIndex) layers = slices.Clone(stageLayers[s.BaseImageIndex]) @@ -1126,7 +1133,7 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts return err } for _, l := range manifest.Layers { - layers = append(layers, l.Digest.String()) + layers = append(layers, pushedLayer{name: l.Digest.String(), key: l.Digest}) } } } @@ -1139,9 +1146,8 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts continue } printf("%s\n", command) - if !command.MetadataOnly() { - layers = append(layers, command.String()) - } + snapshots := shouldTakeSnapshot(command.MetadataOnly(), jdx == len(s.Commands)-1, opts) + var key v1.Hash if opts.Cache && opts.CacheCopyLayers && config.FF.InferCrossStageCacheKey && config.FF.CacheLookahead { if copyCmd, ok := c.(*instructions.CopyCommand); ok && copyCmd.From != "" { ci := cacheInfo[s.Index] @@ -1157,25 +1163,64 @@ func RenderStages(stages []config.KanikoStage, cacheInfo []*stageCacheInfo, opts if opts.Cache && config.FF.CacheLookahead { ci := cacheInfo[s.Index] if ck := ci.cacheKeys[jdx]; ck != "" { + cacheRef, err := cache.Destination(opts, ck) + if err != nil { + cacheRef = "" + } if ci.cacheHits[jdx] { printf(" CACHE HIT: %s\n", ck) + cached, err := layerCache.RetrieveLayer(ck) + if err == nil { + cachedLayers, err := cached.Layers() + if err == nil && len(cachedLayers) == 1 && snapshots { + key, _ = cachedLayers[0].Digest() + } + } } else { printf(" CACHE MISS: %s\n", ck) - if !opts.NoPushCache && command.ShouldCacheOutput() { - cacheRef, err := cache.Destination(opts, ck) - if err == nil { - printf(" UPLOAD %s\n", cacheRef) + if snapshots && !opts.NoPushCache && command.ShouldCacheOutput() && cacheRef != "" { + printf(" UPLOAD %s\n", cacheRef) + key = mounts.PlannedDigest(ck) + tag, err := name.NewTag(cacheRef, name.WeakValidation) + if err != nil { + return err } + sources[key] = []name.Repository{tag.Context()} } } } } + if snapshots { + layers = append(layers, pushedLayer{name: command.String(), key: key}) + } } stageLayers[s.Index] = layers if s.Push && !opts.NoPush { printf("PUSH %v\n", opts.Destinations) + var registries []string + for _, destination := range opts.Destinations { + dest, err := name.NewTag(destination, name.WeakValidation) + if err != nil { + return err + } + registries = append(registries, dest.RegistryStr()) + } for _, l := range layers { - printf(" UPLOAD %s\n", l) + var source name.Repository + serves := config.FF.CrossRepoMount && len(registries) > 0 + for _, registry := range registries { + repo, ok := mounts.Mountable(sources[l.key], registry) + if ok { + source = repo + } else { + serves = false + } + } + if serves { + printf(" MOUNT %s FROM %s\n", l.name, source) + } else { + printf(" UPLOAD %s\n", l.name) + } } } if s.Final { @@ -1377,7 +1422,7 @@ func DoBuild(opts *config.KanikoOptions) (image v1.Image, retErr error) { } if opts.Dryrun || config.EnvBool("KANIKO_PRINT_PLAN") { - err := RenderStages(kanikoStages, cacheInfo, opts, fileContext, crossStageDependencies) + err := RenderStages(kanikoStages, cacheInfo, opts, fileContext, crossStageDependencies, layerCache) if err != nil { return nil, err } diff --git a/pkg/executor/push.go b/pkg/executor/push.go index 29bb1197a..2c9307ba5 100644 --- a/pkg/executor/push.go +++ b/pkg/executor/push.go @@ -293,7 +293,7 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error { logrus.Infof("Pushing image to %s", destRef.String()) pushImage := image if config.FF.CrossRepoMount { - pushImage = mounts.Mountable(image, destRef.RegistryStr()) + pushImage = mounts.MountableImage(image, destRef.RegistryStr()) } retryFunc := func() error { diff --git a/pkg/mounts/mounts.go b/pkg/mounts/mounts.go index 0117d323b..7c83f3a13 100644 --- a/pkg/mounts/mounts.go +++ b/pkg/mounts/mounts.go @@ -27,7 +27,7 @@ limitations under the License. package mounts import ( - "slices" + "maps" "sync" "github.com/google/go-containerregistry/pkg/name" @@ -50,7 +50,8 @@ func RecordImage(img v1.Image, repo name.Repository) { for _, l := range layers { digest, err := l.Digest() if err == nil { - _, known := find(sources[digest], func(r name.Repository) bool { return r.String() == repo.String() }) + // One repository per registry is all a push can ever use. + _, known := Mountable(sources[digest], repo.RegistryStr()) if !known { sources[digest] = append(sources[digest], repo) } @@ -58,15 +59,32 @@ func RecordImage(img v1.Image, repo name.Repository) { } } -func find(repos []name.Repository, match func(name.Repository) bool) (name.Repository, bool) { - i := slices.IndexFunc(repos, match) - if i < 0 { - return name.Repository{}, false +// PlannedDigest names a layer that does not exist yet by the cache key that decides where it +// will end up. Cache keys are sha256 hex like a digest, and never collide with one in practice. +func PlannedDigest(cacheKey string) v1.Hash { + return v1.Hash{Algorithm: "sha256", Hex: cacheKey} +} + +// Snapshot copies the map, not the slices in it. Those are shared and read-only: extend an +// entry by replacing it, never by appending into the one that is there. +func Snapshot() map[v1.Hash][]name.Repository { + mu.Lock() + defer mu.Unlock() + return maps.Clone(sources) +} + +// Mountable returns one of the repositories known to hold a layer that sits on registry. +// Cross-registry origins are not honoured in practice, so a source elsewhere is no source. +func Mountable(repos []name.Repository, registry string) (name.Repository, bool) { + for _, repo := range repos { + if repo.RegistryStr() == registry { + return repo, true + } } - return repos[i], true + return name.Repository{}, false } -func Mountable(img v1.Image, registry string) v1.Image { +func MountableImage(img v1.Image, registry string) v1.Image { return &mountableImage{Image: img, registry: registry} } @@ -76,16 +94,6 @@ type mountableImage struct { registry string } -// Cross-registry origins are not honoured in practice, so a source off the registry being -// pushed to is no source at all. -func mountable(l v1.Layer, digest v1.Hash, candidates []name.Repository, registry string) v1.Layer { - repo, ok := find(candidates, func(r name.Repository) bool { return r.RegistryStr() == registry }) - if !ok { - return l - } - return &remote.MountableLayer{Layer: l, Reference: repo.Digest(digest.String())} -} - // Layers is the only accessor remote.Write reads to decide what it sends, so LayerByDigest // and LayerByDiffID are deliberately left untagged. func (m *mountableImage) Layers() ([]v1.Layer, error) { @@ -97,12 +105,15 @@ func (m *mountableImage) Layers() ([]v1.Layer, error) { mu.Lock() defer mu.Unlock() for _, l := range layers { + layer := l digest, err := l.Digest() if err == nil { - tagged = append(tagged, mountable(l, digest, sources[digest], m.registry)) - } else { - tagged = append(tagged, l) + repo, ok := Mountable(sources[digest], m.registry) + if ok { + layer = &remote.MountableLayer{Layer: l, Reference: repo.Digest(digest.String())} + } } + tagged = append(tagged, layer) } return tagged, nil }