support empty images in cache to handle WORKDIR w/o implicit folders created

This commit is contained in:
Martin Zihlmann 2024-10-13 10:56:06 +01:00
parent caebb2a538
commit 0561cc5664
No known key found for this signature in database
GPG Key ID: 0F7784F41354DE99
3 changed files with 29 additions and 24 deletions

View File

@ -88,11 +88,7 @@ func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile
// FilesToSnapshot returns the workingdir, which should have been created if it didn't already exist
func (w *WorkdirCommand) FilesToSnapshot() []string {
return nil
}
func (r *WorkdirCommand) ProvidesFilesToSnapshot() bool {
return false
return w.snapshotFiles
}
// String returns some information about the command for the image config history
@ -154,8 +150,11 @@ func (wr *CachingWorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *do
return errors.Wrap(err, "retrieving image layers")
}
if len(layers) != 1 {
if len(layers) > 1 {
return errors.New(fmt.Sprintf("expected %d layers but got %d", 1, len(layers)))
} else if len(layers) == 0 {
// an empty image in cache indicates that no directory was created by WORKDIR
return nil
}
wr.layer = layers[0]

View File

@ -414,11 +414,13 @@ func (s *stageBuilder) build() error {
continue
}
if isCacheCommand {
if files != nil && len(files) == 0 {
v := command.(commands.Cached)
layer := v.Layer()
if (files != nil || layer == nil) && len(files) == 0 {
// a cache image with a layer with no files indicates that no files were changed, ie. by 'RUN echo hello'
// a cache image without a layer indicates that no files were changed too, ie. by 'WORKDIR /'
logrus.Info("No files were changed, appending empty layer to config. No layer added to image.")
} else {
v := command.(commands.Cached)
layer := v.Layer()
if err := s.saveLayerToImage(layer, command.String()); err != nil {
return errors.Wrap(err, "failed to save layer")
}

View File

@ -369,11 +369,6 @@ func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, tarPath strin
// layer already gzipped by default
}
layer, err := tarball.LayerFromFile(tarPath, layerOpts...)
if err != nil {
return err
}
cache, err := cache.Destination(opts, cacheKey)
if err != nil {
return errors.Wrap(err, "getting cache destination")
@ -385,18 +380,27 @@ func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, tarPath strin
return errors.Wrap(err, "setting empty image created time")
}
empty, err = mutate.Append(empty,
mutate.Addendum{
Layer: layer,
History: v1.History{
Author: constants.Author,
CreatedBy: createdBy,
// WORKDIR can create empty layers by design, yet still we must cache them
// to transfer the knowledge that they are empty.
if tarPath != "" {
layer, err := tarball.LayerFromFile(tarPath, layerOpts...)
if err != nil {
return err
}
empty, err = mutate.Append(empty,
mutate.Addendum{
Layer: layer,
History: v1.History{
Author: constants.Author,
CreatedBy: createdBy,
},
},
},
)
if err != nil {
return errors.Wrap(err, "appending layer onto empty image")
)
if err != nil {
return errors.Wrap(err, "appending layer onto empty image")
}
}
cacheOpts := *opts
cacheOpts.TarPath = "" // tarPath doesn't make sense for Docker layers
cacheOpts.NoPush = opts.NoPushCache // we do not want to push cache if --no-push-cache is set.