diff --git a/pkg/commands/base_command.go b/pkg/commands/base_command.go index fe6a45c711..3d2cd8fad4 100644 --- a/pkg/commands/base_command.go +++ b/pkg/commands/base_command.go @@ -43,3 +43,7 @@ func (b *BaseCommand) MetadataOnly() bool { func (b *BaseCommand) RequiresUnpackedFS() bool { return false } + +func (b *BaseCommand) ShouldCacheOutput() bool { + return false +} diff --git a/pkg/commands/commands.go b/pkg/commands/commands.go index b8acade2c2..2615138be4 100644 --- a/pkg/commands/commands.go +++ b/pkg/commands/commands.go @@ -36,6 +36,7 @@ type DockerCommand interface { String() string // A list of files to snapshot, empty for metadata commands or nil if we don't know FilesToSnapshot() []string + // Return a cache-aware implementation of this command, if it exists. CacheCommand(v1.Image) DockerCommand @@ -45,6 +46,8 @@ type DockerCommand interface { MetadataOnly() bool RequiresUnpackedFS() bool + + ShouldCacheOutput() bool } func GetCommand(cmd instructions.Command, buildcontext string) (DockerCommand, error) { diff --git a/pkg/commands/run.go b/pkg/commands/run.go index 5295cab82b..7a9bf03dc2 100644 --- a/pkg/commands/run.go +++ b/pkg/commands/run.go @@ -169,6 +169,10 @@ func (r *RunCommand) RequiresUnpackedFS() bool { return true } +func (r *RunCommand) ShouldCacheOutput() bool { + return true +} + type CachingRunCommand struct { BaseCommand img v1.Image diff --git a/pkg/executor/build.go b/pkg/executor/build.go index f039fb5cab..0f9f3dd2d5 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -23,6 +23,8 @@ import ( "strconv" "time" + "golang.org/x/sync/errgroup" + "github.com/google/go-containerregistry/pkg/name" "github.com/google/go-containerregistry/pkg/v1" "github.com/google/go-containerregistry/pkg/v1/mutate" @@ -119,15 +121,17 @@ func (s *stageBuilder) optimize(compositeKey CompositeCache, cfg v1.Config, cmds if err != nil { return err } - img, err := layerCache.RetrieveLayer(ck) - if err != nil { - logrus.Infof("No cached layer found for cmd %s", command.String()) - break - } + if command.ShouldCacheOutput() { + img, err := layerCache.RetrieveLayer(ck) + if err != nil { + logrus.Infof("No cached layer found for cmd %s", command.String()) + break + } - if cacheCmd := command.CacheCommand(img); cacheCmd != nil { - logrus.Infof("Using caching version of cmd: %s", command.String()) - cmds[i] = cacheCmd + if cacheCmd := command.CacheCommand(img); cacheCmd != nil { + logrus.Infof("Using caching version of cmd: %s", command.String()) + cmds[i] = cacheCmd + } } // Mutate the config for any commands that require it. @@ -184,6 +188,7 @@ func (s *stageBuilder) build() error { return err } + cacheGroup := errgroup.Group{} for index, command := range cmds { if command == nil { continue @@ -222,10 +227,19 @@ func (s *stageBuilder) build() error { if err != nil { return err } - if err := s.saveSnapshotToImage(command.String(), ck, tarPath); err != nil { + // Push layer to cache (in parallel) now along with new config file + if s.opts.Cache && command.ShouldCacheOutput() { + cacheGroup.Go(func() error { + return pushLayerToCache(s.opts, ck, tarPath, command.String()) + }) + } + if err := s.saveSnapshotToImage(command.String(), tarPath); err != nil { return err } } + if err := cacheGroup.Wait(); err != nil { + logrus.Warnf("error uploading layer to cache: %s", err) + } return nil } @@ -266,7 +280,7 @@ func (s *stageBuilder) shouldTakeSnapshot(index int, files []string) bool { return true } -func (s *stageBuilder) saveSnapshotToImage(createdBy string, ck string, tarPath string) error { +func (s *stageBuilder) saveSnapshotToImage(createdBy string, tarPath string) error { if tarPath == "" { return nil } @@ -283,12 +297,6 @@ func (s *stageBuilder) saveSnapshotToImage(createdBy string, ck string, tarPath if err != nil { return err } - // Push layer to cache now along with new config file - if s.opts.Cache { - if err := pushLayerToCache(s.opts, ck, layer, createdBy); err != nil { - return err - } - } s.image, err = mutate.Append(s.image, mutate.Addendum{ Layer: layer, diff --git a/pkg/executor/push.go b/pkg/executor/push.go index 796c17cf77..c2fe76d41b 100644 --- a/pkg/executor/push.go +++ b/pkg/executor/push.go @@ -107,7 +107,11 @@ func DoPush(image v1.Image, opts *config.KanikoOptions) error { // pushLayerToCache pushes layer (tagged with cacheKey) to opts.Cache // if opts.Cache doesn't exist, infer the cache from the given destination -func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, layer v1.Layer, createdBy string) error { +func pushLayerToCache(opts *config.KanikoOptions, cacheKey string, tarPath string, createdBy string) error { + layer, err := tarball.LayerFromFile(tarPath) + if err != nil { + return err + } cache, err := cache.Destination(opts, cacheKey) if err != nil { return errors.Wrap(err, "getting cache destination")