Skip to content

Commit 89f7b79

Browse files
committed
fix: addressed another comment
--layers and --cache-stages can be used together. When --cache-stages is enabled (with or without --layers) checkForLayers is set to false, blocking cache lookup (fresh build every time with --cache-stages). When --cache-stages is enabled with --layers together, all other subsequent builds without --cache-stages can use cached layers. This commit will be squashed serves only for review purposes. Signed-off-by: Erik Mravec <emravec@redhat.com>
1 parent 6f81555 commit 89f7b79

4 files changed

Lines changed: 66 additions & 16 deletions

File tree

docs/buildah-build.1.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,10 @@ Preserve intermediate stage images instead of removing them after the build comp
150150
This option keeps those images, which can be useful for debugging multi-stage builds or
151151
for reusing intermediate stages in subsequent builds.
152152

153-
Note: This option cannot be used together with `--layers`. Use `--layers` for build caching
154-
or `--cache-stages` for preserving stage artifacts, but not both.
153+
When `--cache-stages` is used, cache lookup is disabled to ensure a fresh build every time.
154+
This means the build will not reuse cached intermediate images from previous builds. On the
155+
other hand when `--cache-stages` is used with `--layers` in a first build, subsequent builds without
156+
`--cache-stages` but with `--layers` can still use the preserved intermediate layers as cache.
155157

156158
When combined with `--stage-labels`, intermediate images will include metadata labels
157159
for easier identification and management.
@@ -614,8 +616,6 @@ Cache intermediate images during the build process (Default is `false`).
614616
Note: You can also override the default value of layers by setting the BUILDAH\_LAYERS
615617
environment variable. `export BUILDAH_LAYERS=true`
616618

617-
This option cannot be used together with `--cache-stages`.
618-
619619
**--logfile** *filename*
620620

621621
Log output which would be sent to standard output and standard error to the

imagebuildah/stage_executor.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,11 @@ func (s *stageExecutor) execute(ctx context.Context, base string) (imgID string,
12051205
stage := s.stage
12061206
ib := stage.Builder
12071207
checkForLayers := s.executor.layers && s.executor.useCache
1208+
// When --cache-stages is used, disable cache lookup to ensure a fresh build.
1209+
// Subsequent builds without --cache-stages still can use these intermediate images as cache.
1210+
if s.executor.cacheStages {
1211+
checkForLayers = false
1212+
}
12081213
moreStages := s.index < len(s.stages)-1
12091214
lastStage := !moreStages
12101215
onlyBaseImage := false

pkg/cli/build.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -231,10 +231,6 @@ func GenBuildOptions(c *cobra.Command, inputArgs []string, iopts BuildOptions) (
231231
return options, nil, nil, errors.New("'build-id-file' requires 'stage-labels'")
232232
}
233233

234-
if iopts.Layers && iopts.CacheStages {
235-
return options, nil, nil, errors.New("'layers' and 'cache-stages' cannot be used together")
236-
}
237-
238234
if c.Flag("compress").Changed {
239235
logrus.Debugf("--compress option specified but is ignored")
240236
}

tests/bud.bats

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9245,14 +9245,6 @@ EOF
92459245
expect_output --substring "writing build ID to file"
92469246
}
92479247

9248-
@test "bud with --layers and --cache-stages should error" {
9249-
_prefetch alpine
9250-
target="layers-cache-stages-error-test-$(safename)"
9251-
9252-
run_buildah 125 build $WITH_POLICY_JSON --layers --cache-stages -t ${target} -f $BUDFILES/cache-stages-test/Dockerfile.single-intermediate $BUDFILES/cache-stages-test
9253-
expect_output --substring "'layers' and 'cache-stages' cannot be used together"
9254-
}
9255-
92569248
@test "bud with --cache-stages on single-stage Dockerfile should not create intermediate images" {
92579249
_prefetch alpine
92589250
target="single-stage-test-$(safename)"
@@ -9571,3 +9563,60 @@ EOF
95719563
run_buildah rmi --all
95729564
}
95739565

9566+
@test "bud with --layers --cache-stages stores labeled layers and subsequent --layers build reuses them" {
9567+
_prefetch alpine
9568+
target="cache-reuse-test-$(safename)"
9569+
build_id_file="${TEST_SCRATCH_DIR}/cache-reuse-build-id.txt"
9570+
9571+
run_buildah build $WITH_POLICY_JSON --layers --cache-stages --stage-labels --build-id-file ${build_id_file} -t ${target}-first -f $BUDFILES/cache-stages-test/Dockerfile.single-intermediate $BUDFILES/cache-stages-test
9572+
9573+
first_build_id=$(cat ${build_id_file})
9574+
9575+
# Get all intermediate layers from first build and store their image IDs and build IDs
9576+
run_buildah images -a
9577+
all_intermediate_layers_first=$(echo "$output" | awk '$1 == "<none>" && $2 == "<none>" {print $3}')
9578+
9579+
# Create associative array: image_id -> build_id
9580+
declare -A first_build_image_to_build_id
9581+
for image_id in $all_intermediate_layers_first; do
9582+
run_buildah inspect --format '{{index .OCIv1.Config.Labels "io.buildah.build.id"}}' $image_id
9583+
build_id_label="$output"
9584+
if [[ -n "$build_id_label" ]]; then
9585+
first_build_image_to_build_id[$image_id]="$build_id_label"
9586+
assert "$build_id_label" == "$first_build_id" "all intermediate layers from first build should have build ID: $first_build_id"
9587+
fi
9588+
done
9589+
9590+
first_intermediate_count=$(echo "$all_intermediate_layers_first" | wc -w)
9591+
assert "$first_intermediate_count" -gt 0 "first build should create intermediate layers"
9592+
9593+
# Remove the final tagged image but keep all intermediate layers for cache
9594+
run_buildah rmi ${target}-first
9595+
9596+
# Second should reuse the layers created by first build (cache hit not creating more)
9597+
run_buildah build $WITH_POLICY_JSON --layers -t ${target}-second -f $BUDFILES/cache-stages-test/Dockerfile.single-intermediate $BUDFILES/cache-stages-test
9598+
9599+
expect_output --substring "Using cache"
9600+
9601+
run_buildah images -a
9602+
all_intermediate_layers_second=$(echo "$output" | awk '$1 == "<none>" && $2 == "<none>" {print $3}')
9603+
9604+
# Verify that intermediate layers with matching image IDs have matching build IDs
9605+
cached_layers_count=0
9606+
for image_id in $all_intermediate_layers_second; do
9607+
if [[ -n "${first_build_image_to_build_id[$image_id]}" ]]; then
9608+
cached_layers_count=$((cached_layers_count + 1))
9609+
9610+
run_buildah inspect --format '{{index .OCIv1.Config.Labels "io.buildah.build.id"}}' $image_id
9611+
current_build_id="$output"
9612+
expected_build_id="${first_build_image_to_build_id[$image_id]}"
9613+
9614+
assert "$current_build_id" == "$expected_build_id" "image $image_id reused from cache must have same build ID: $expected_build_id"
9615+
fi
9616+
done
9617+
9618+
# COPY --from=... layers are not reused
9619+
assert "$cached_layers_count" -eq 3 "intermediate layers should be reused from cache (have matching image IDs)"
9620+
9621+
run_buildah rmi --all
9622+
}

0 commit comments

Comments
 (0)