mirror of
https://github.com/GoogleContainerTools/kaniko
synced 2026-10-18 07:08:24 +02:00
More cache cleanups: (#397)
- move the layer cache to an interface - refactor the DockerCommand implementations to support Cached and non-cached implementations.
This commit is contained in:
Vendored
+15
-5
@@ -31,9 +31,16 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
// RetrieveLayer checks the specified cache for a layer with the tag :cacheKey
|
||||
func RetrieveLayer(opts *config.KanikoOptions, cacheKey string) (v1.Image, error) {
|
||||
cache, err := Destination(opts, cacheKey)
|
||||
type LayerCache interface {
|
||||
RetrieveLayer(string) (v1.Image, error)
|
||||
}
|
||||
|
||||
type RegistryCache struct {
|
||||
Opts *config.KanikoOptions
|
||||
}
|
||||
|
||||
func (rc *RegistryCache) RetrieveLayer(ck string) (v1.Image, error) {
|
||||
cache, err := Destination(rc.Opts, ck)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "getting cache destination")
|
||||
}
|
||||
@@ -52,8 +59,11 @@ func RetrieveLayer(opts *config.KanikoOptions, cacheKey string) (v1.Image, error
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
_, err = img.Layers()
|
||||
return img, err
|
||||
// Force the manifest to be populated
|
||||
if _, err := img.RawManifest(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return img, nil
|
||||
}
|
||||
|
||||
// Destination returns the repo where the layer should be stored
|
||||
|
||||
@@ -22,11 +22,10 @@ import (
|
||||
)
|
||||
|
||||
type BaseCommand struct {
|
||||
cache bool
|
||||
}
|
||||
|
||||
func (b *BaseCommand) CacheCommand() bool {
|
||||
return b.cache
|
||||
func (b *BaseCommand) CacheCommand(v1.Image) DockerCommand {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (b *BaseCommand) FilesToSnapshot() []string {
|
||||
|
||||
@@ -24,6 +24,8 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
type CurrentCacheKey func() (string, error)
|
||||
|
||||
type DockerCommand interface {
|
||||
// ExecuteCommand is responsible for:
|
||||
// 1. Making required changes to the filesystem (ex. copying files for ADD/COPY or setting ENV variables)
|
||||
@@ -34,9 +36,8 @@ 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 true if this command should be true
|
||||
// Currently only true for RUN
|
||||
CacheCommand() bool
|
||||
// Return a cache-aware implementation of this command, if it exists.
|
||||
CacheCommand(v1.Image) DockerCommand
|
||||
|
||||
// Return true if this command depends on the build context.
|
||||
FilesUsedFromContext(*v1.Config, *dockerfile.BuildArgs) ([]string, error)
|
||||
|
||||
+31
-2
@@ -153,6 +153,35 @@ func (r *RunCommand) FilesToSnapshot() []string {
|
||||
}
|
||||
|
||||
// CacheCommand returns true since this command should be cached
|
||||
func (r *RunCommand) CacheCommand() bool {
|
||||
return true
|
||||
func (r *RunCommand) CacheCommand(img v1.Image) DockerCommand {
|
||||
|
||||
return &CachingRunCommand{
|
||||
img: img,
|
||||
cmd: r.cmd,
|
||||
}
|
||||
}
|
||||
|
||||
type CachingRunCommand struct {
|
||||
BaseCommand
|
||||
img v1.Image
|
||||
extractedFiles []string
|
||||
cmd *instructions.RunCommand
|
||||
}
|
||||
|
||||
func (cr *CachingRunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
|
||||
logrus.Infof("Found cached layer, extracting to filesystem")
|
||||
var err error
|
||||
cr.extractedFiles, err = util.GetFSFromImage(constants.RootDir, cr.img)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "extracting fs from image")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cr *CachingRunCommand) FilesToSnapshot() []string {
|
||||
return cr.extractedFiles
|
||||
}
|
||||
|
||||
func (cr *CachingRunCommand) String() string {
|
||||
return cr.cmd.String()
|
||||
}
|
||||
|
||||
+35
-48
@@ -86,33 +86,6 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage) (*sta
|
||||
}, nil
|
||||
}
|
||||
|
||||
// extractCachedLayer will extract the cached layer and append it to the config file
|
||||
func (s *stageBuilder) extractCachedLayer(layer v1.Image, createdBy string) error {
|
||||
logrus.Infof("Found cached layer, extracting to filesystem")
|
||||
extractedFiles, err := util.GetFSFromImage(constants.RootDir, layer)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "extracting fs from image")
|
||||
}
|
||||
if _, err := s.snapshotter.TakeSnapshot(extractedFiles); err != nil {
|
||||
return err
|
||||
}
|
||||
logrus.Infof("Appending cached layer to base image")
|
||||
l, err := layer.Layers()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "getting cached layer from image")
|
||||
}
|
||||
s.image, err = mutate.Append(s.image,
|
||||
mutate.Addendum{
|
||||
Layer: l[0],
|
||||
History: v1.History{
|
||||
Author: constants.Author,
|
||||
CreatedBy: createdBy,
|
||||
},
|
||||
},
|
||||
)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s *stageBuilder) build() error {
|
||||
// Unpack file system to root
|
||||
if _, err := util.GetFSFromImage(constants.RootDir, s.image); err != nil {
|
||||
@@ -136,6 +109,32 @@ func (s *stageBuilder) build() error {
|
||||
cmds = append(cmds, command)
|
||||
}
|
||||
|
||||
layerCache := &cache.RegistryCache{
|
||||
Opts: s.opts,
|
||||
}
|
||||
if s.opts.Cache {
|
||||
// Possibly replace commands with their cached implementations.
|
||||
for i, command := range cmds {
|
||||
if command == nil {
|
||||
continue
|
||||
}
|
||||
ck, err := compositeKey.Hash()
|
||||
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 cacheCmd := command.CacheCommand(img); cacheCmd != nil {
|
||||
logrus.Infof("Using caching version of cmd: %s", command.String())
|
||||
cmds[i] = cacheCmd
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
args := dockerfile.NewBuildArgs(s.opts.BuildArgs)
|
||||
for index, command := range cmds {
|
||||
if command == nil {
|
||||
@@ -157,22 +156,6 @@ func (s *stageBuilder) build() error {
|
||||
}
|
||||
logrus.Info(command.String())
|
||||
|
||||
ck, err := compositeKey.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if command.CacheCommand() && s.opts.Cache {
|
||||
image, err := cache.RetrieveLayer(s.opts, ck)
|
||||
if err == nil {
|
||||
if err := s.extractCachedLayer(image, command.String()); err != nil {
|
||||
return errors.Wrap(err, "extracting cached layer")
|
||||
}
|
||||
continue
|
||||
}
|
||||
logrus.Info("No cached layer found, executing command...")
|
||||
}
|
||||
|
||||
if err := command.ExecuteCommand(&s.cf.Config, args); err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -196,7 +179,11 @@ func (s *stageBuilder) build() error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.saveSnapshot(command, ck, contents); err != nil {
|
||||
ck, err := compositeKey.Hash()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := s.saveSnapshot(command.String(), ck, contents); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -228,7 +215,7 @@ func (s *stageBuilder) shouldTakeSnapshot(index int, files []string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *stageBuilder) saveSnapshot(command commands.DockerCommand, ck string, contents []byte) error {
|
||||
func (s *stageBuilder) saveSnapshot(createdBy string, ck string, contents []byte) error {
|
||||
if contents == nil {
|
||||
logrus.Info("No files were changed, appending empty layer to config. No layer added to image.")
|
||||
return nil
|
||||
@@ -242,8 +229,8 @@ func (s *stageBuilder) saveSnapshot(command commands.DockerCommand, ck string, c
|
||||
return err
|
||||
}
|
||||
// Push layer to cache now along with new config file
|
||||
if command.CacheCommand() && s.opts.Cache {
|
||||
if err := pushLayerToCache(s.opts, ck, layer, command.String()); err != nil {
|
||||
if s.opts.Cache {
|
||||
if err := pushLayerToCache(s.opts, ck, layer, createdBy); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -252,7 +239,7 @@ func (s *stageBuilder) saveSnapshot(command commands.DockerCommand, ck string, c
|
||||
Layer: layer,
|
||||
History: v1.History{
|
||||
Author: constants.Author,
|
||||
CreatedBy: command.String(),
|
||||
CreatedBy: createdBy,
|
||||
},
|
||||
},
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user