Skip to content

Commit e8b4ebe

Browse files
committed
fix: allow caching run layers with no filesystem changes
Fixes #326
1 parent 08bd99b commit e8b4ebe

File tree

2 files changed

+74
-22
lines changed

2 files changed

+74
-22
lines changed

envbuilder.go

+24-22
Original file line numberDiff line numberDiff line change
@@ -456,17 +456,18 @@ func Run(ctx context.Context, opts options.Options) error {
456456
}
457457
kOpts := &config.KanikoOptions{
458458
// Boilerplate!
459-
CustomPlatform: platforms.Format(platforms.Normalize(platforms.DefaultSpec())),
460-
SnapshotMode: "redo",
461-
RunV2: true,
462-
RunStdout: stdoutWriter,
463-
RunStderr: stderrWriter,
464-
Destinations: destinations,
465-
NoPush: !opts.PushImage || len(destinations) == 0,
466-
CacheRunLayers: true,
467-
CacheCopyLayers: true,
468-
CompressedCaching: true,
469-
Compression: config.ZStd,
459+
CustomPlatform: platforms.Format(platforms.Normalize(platforms.DefaultSpec())),
460+
SnapshotMode: "redo",
461+
RunV2: true,
462+
RunStdout: stdoutWriter,
463+
RunStderr: stderrWriter,
464+
Destinations: destinations,
465+
NoPush: !opts.PushImage || len(destinations) == 0,
466+
CacheRunLayers: true,
467+
CacheCopyLayers: true,
468+
ForceBuildMetadata: opts.PushImage, // Force layers with no changes to be cached, required for cache probing.
469+
CompressedCaching: true,
470+
Compression: config.ZStd,
470471
// Maps to "default" level, ~100-300 MB/sec according to
471472
// benchmarks in klauspost/compress README
472473
// https://github.com/klauspost/compress/blob/67a538e2b4df11f8ec7139388838a13bce84b5d5/zstd/encoder_options.go#L188
@@ -1180,17 +1181,18 @@ func RunCacheProbe(ctx context.Context, opts options.Options) (v1.Image, error)
11801181
}
11811182
kOpts := &config.KanikoOptions{
11821183
// Boilerplate!
1183-
CustomPlatform: platforms.Format(platforms.Normalize(platforms.DefaultSpec())),
1184-
SnapshotMode: "redo",
1185-
RunV2: true,
1186-
RunStdout: stdoutWriter,
1187-
RunStderr: stderrWriter,
1188-
Destinations: destinations,
1189-
NoPush: !opts.PushImage || len(destinations) == 0,
1190-
CacheRunLayers: true,
1191-
CacheCopyLayers: true,
1192-
CompressedCaching: true,
1193-
Compression: config.ZStd,
1184+
CustomPlatform: platforms.Format(platforms.Normalize(platforms.DefaultSpec())),
1185+
SnapshotMode: "redo",
1186+
RunV2: true,
1187+
RunStdout: stdoutWriter,
1188+
RunStderr: stderrWriter,
1189+
Destinations: destinations,
1190+
NoPush: true,
1191+
CacheRunLayers: true,
1192+
CacheCopyLayers: true,
1193+
ForceBuildMetadata: true, // Force layers with no changes to be cached, required for cache probing.
1194+
CompressedCaching: true,
1195+
Compression: config.ZStd,
11941196
// Maps to "default" level, ~100-300 MB/sec according to
11951197
// benchmarks in klauspost/compress README
11961198
// https://github.com/klauspost/compress/blob/67a538e2b4df11f8ec7139388838a13bce84b5d5/zstd/encoder_options.go#L188

integration/integration_test.go

+50
Original file line numberDiff line numberDiff line change
@@ -1312,6 +1312,56 @@ RUN date --utc > /root/date.txt`, testImageAlpine),
13121312
require.NotEmpty(t, strings.TrimSpace(out))
13131313
})
13141314

1315+
t.Run("CacheAndPushWithNoChangeLayers", func(t *testing.T) {
1316+
t.Parallel()
1317+
1318+
ctx, cancel := context.WithCancel(context.Background())
1319+
t.Cleanup(cancel)
1320+
1321+
srv := gittest.CreateGitServer(t, gittest.Options{
1322+
Files: map[string]string{
1323+
"Dockerfile": fmt.Sprintf(`
1324+
FROM %[1]s
1325+
RUN touch /foo
1326+
RUN echo "Hi, please don't put me in a layer (I guess you won't listen to me...)"
1327+
RUN touch /bar
1328+
`, testImageAlpine),
1329+
},
1330+
})
1331+
1332+
// Given: an empty registry
1333+
testReg := setupInMemoryRegistry(t, setupInMemoryRegistryOpts{})
1334+
testRepo := testReg + "/test"
1335+
ref, err := name.ParseReference(testRepo + ":latest")
1336+
require.NoError(t, err)
1337+
_, err = remote.Image(ref)
1338+
require.ErrorContains(t, err, "NAME_UNKNOWN", "expected image to not be present before build + push")
1339+
1340+
opts := []string{
1341+
envbuilderEnv("GIT_URL", srv.URL),
1342+
envbuilderEnv("CACHE_REPO", testRepo),
1343+
envbuilderEnv("DOCKERFILE_PATH", "Dockerfile"),
1344+
}
1345+
1346+
// When: we run envbuilder with PUSH_IMAGE set
1347+
_ = pushImage(t, ref, nil, opts...)
1348+
1349+
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
1350+
require.NoError(t, err)
1351+
defer cli.Close()
1352+
1353+
// Then: re-running envbuilder with GET_CACHED_IMAGE should succeed
1354+
cachedRef := getCachedImage(ctx, t, cli, opts...)
1355+
1356+
// When: we run the image we just built
1357+
ctr := startContainerFromRef(ctx, t, cli, cachedRef)
1358+
1359+
// Then: the envbuilder binary exists in the image!
1360+
out := execContainer(t, ctr.ID, "/.envbuilder/bin/envbuilder --help")
1361+
require.Regexp(t, `(?s)^USAGE:\s+envbuilder`, strings.TrimSpace(out))
1362+
require.NotEmpty(t, strings.TrimSpace(out))
1363+
})
1364+
13151365
t.Run("CacheAndPushAuth", func(t *testing.T) {
13161366
t.Parallel()
13171367

0 commit comments

Comments
 (0)