Improve cache layer uploads. (#443)

This change only uploads layers that were created from cache misses on RUN commands.
It also improves the cache-checking logic to handle this case.
Finally, it makes cache layer uploads happen in parallel with the rest of the build, logging
a warning if any fail.
This commit is contained in:
dlorenc
2018-11-12 16:22:04 -06:00
committed by GitHub
parent 063663e17b
commit 8408c53aa8
5 changed files with 40 additions and 17 deletions
+4
View File
@@ -43,3 +43,7 @@ func (b *BaseCommand) MetadataOnly() bool {
func (b *BaseCommand) RequiresUnpackedFS() bool {
return false
}
func (b *BaseCommand) ShouldCacheOutput() bool {
return false
}
+3
View File
@@ -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) {
+4
View File
@@ -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
+24 -16
View File
@@ -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,
+5 -1
View File
@@ -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")