Skip to content

Commit

Permalink
Merge pull request #1214 from tejal29/experiment
Browse files Browse the repository at this point in the history
Snapshot FS on first cache miss.
  • Loading branch information
tejal29 authored May 4, 2020
2 parents e32715e + ee097f9 commit e1c7862
Show file tree
Hide file tree
Showing 11 changed files with 96 additions and 47 deletions.
4 changes: 4 additions & 0 deletions pkg/commands/base_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ func (b *BaseCommand) FilesToSnapshot() []string {
return []string{}
}

func (b *BaseCommand) ProvidesFilesToSnapshot() bool {
return true
}

func (b *BaseCommand) FilesUsedFromContext(_ *v1.Config, _ *dockerfile.BuildArgs) ([]string, error) {
return []string{}, nil
}
Expand Down
8 changes: 1 addition & 7 deletions pkg/commands/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,12 @@ import v1 "github.com/google/go-containerregistry/pkg/v1"

type Cached interface {
Layer() v1.Layer
ReadSuccess() bool
}

type caching struct {
layer v1.Layer
readSuccess bool
layer v1.Layer
}

func (c caching) Layer() v1.Layer {
return c.layer
}

func (c caching) ReadSuccess() bool {
return c.readSuccess
}
6 changes: 1 addition & 5 deletions pkg/commands/cache_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,16 +21,12 @@ import (
)

func Test_caching(t *testing.T) {
c := caching{layer: fakeLayer{}, readSuccess: true}
c := caching{layer: fakeLayer{}}

actual := c.Layer().(fakeLayer)
expected := fakeLayer{}
actualLen, expectedLen := len(actual.TarContent), len(expected.TarContent)
if actualLen != expectedLen {
t.Errorf("expected layer tar content to be %v but was %v", expectedLen, actualLen)
}

if !c.ReadSuccess() {
t.Errorf("expected ReadSuccess to be %v but was %v", true, c.ReadSuccess())
}
}
4 changes: 4 additions & 0 deletions pkg/commands/commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type DockerCommand interface {
// A list of files to snapshot, empty for metadata commands or nil if we don't know
FilesToSnapshot() []string

// ProvidesFileToSnapshot is true for all metadata commands and commands which know
// list of files changed. False for Run command.
ProvidesFilesToSnapshot() bool

// Return a cache-aware implementation of this command, if it exists.
CacheCommand(v1.Image) DockerCommand

Expand Down
6 changes: 4 additions & 2 deletions pkg/commands/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,6 @@ func (cr *CachingCopyCommand) ExecuteCommand(config *v1.Config, buildArgs *docke
}

cr.layer = layers[0]
cr.readSuccess = true

cr.extractedFiles, err = util.GetFSFromLayers(kConfig.RootDir, layers, util.ExtractFunc(cr.extractFn), util.IncludeWhiteout())

logrus.Debugf("extractedFiles: %s", cr.extractedFiles)
Expand All @@ -213,6 +211,10 @@ func (cr *CachingCopyCommand) FilesToSnapshot() []string {
return f
}

func (cr *CachingCopyCommand) MetadataOnly() bool {
return false
}

func (cr *CachingCopyCommand) String() string {
if cr.cmd == nil {
return "nil command"
Expand Down
4 changes: 0 additions & 4 deletions pkg/commands/copy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -385,10 +385,6 @@ func Test_CachingCopyCommand_ExecuteCommand(t *testing.T) {
} else if c.layer != nil && !tc.expectLayer {
t.Error("expected the command to have no layer set but instead found a layer")
}

if c.readSuccess != tc.expectLayer {
t.Errorf("expected read success to be %v but was %v", tc.expectLayer, c.readSuccess)
}
})
}
}
Expand Down
9 changes: 8 additions & 1 deletion pkg/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,10 @@ func (r *RunCommand) FilesToSnapshot() []string {
return nil
}

func (r *RunCommand) ProvidesFilesToSnapshot() bool {
return false
}

// CacheCommand returns true since this command should be cached
func (r *RunCommand) CacheCommand(img v1.Image) DockerCommand {

Expand Down Expand Up @@ -200,7 +204,6 @@ func (cr *CachingRunCommand) ExecuteCommand(config *v1.Config, buildArgs *docker
}

cr.layer = layers[0]
cr.readSuccess = true

cr.extractedFiles, err = util.GetFSFromLayers(
kConfig.RootDir,
Expand Down Expand Up @@ -229,3 +232,7 @@ func (cr *CachingRunCommand) String() string {
}
return cr.cmd.String()
}

func (cr *CachingRunCommand) MetadataOnly() bool {
return false
}
4 changes: 0 additions & 4 deletions pkg/commands/run_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -313,10 +313,6 @@ func Test_CachingRunCommand_ExecuteCommand(t *testing.T) {
} else if c.layer != nil && !tc.expectLayer {
t.Error("expected the command to have no layer set but instead found a layer")
}

if c.readSuccess != tc.expectLayer {
t.Errorf("expected read success to be %v but was %v", tc.expectLayer, c.readSuccess)
}
})
}
}
59 changes: 38 additions & 21 deletions pkg/executor/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -317,14 +317,14 @@ func (s *stageBuilder) build() error {
return errors.Wrap(err, "failed to check filesystem whitelist")
}

// Take initial snapshot
t := timing.Start("Initial FS snapshot")
if err := s.snapshotter.Init(); err != nil {
return err
initSnapshotTaken := false
if s.opts.SingleSnapshot {
if err := s.initSnapshotWithTimings(); err != nil {
return err
}
initSnapshotTaken = true
}

timing.DefaultRun.Stop(t)

cacheGroup := errgroup.Group{}
for index, command := range s.cmds {
if command == nil {
Expand All @@ -348,26 +348,33 @@ func (s *stageBuilder) build() error {

logrus.Info(command.String())

isCacheCommand := func() bool {
switch command.(type) {
case commands.Cached:
return true
default:
return false
}
}()
if !initSnapshotTaken && !isCacheCommand && !command.ProvidesFilesToSnapshot() {
// Take initial snapshot if command does not expect to return
// a list of files.
if err := s.initSnapshotWithTimings(); err != nil {
return err
}
initSnapshotTaken = true
}

if err := command.ExecuteCommand(&s.cf.Config, s.args); err != nil {
return errors.Wrap(err, "failed to execute command")
}
files = command.FilesToSnapshot()
timing.DefaultRun.Stop(t)

if !s.shouldTakeSnapshot(index, files) {
if !s.shouldTakeSnapshot(index, files, command.ProvidesFilesToSnapshot()) {
continue
}

fn := func() bool {
switch v := command.(type) {
case commands.Cached:
return v.ReadSuccess()
default:
return false
}
}

if fn() {
if isCacheCommand {
v := command.(commands.Cached)
layer := v.Layer()
if err := s.saveLayerToImage(layer, command.String()); err != nil {
Expand Down Expand Up @@ -411,6 +418,7 @@ func (s *stageBuilder) build() error {
func (s *stageBuilder) takeSnapshot(files []string) (string, error) {
var snapshot string
var err error

t := timing.Start("Snapshotting FS")
if files == nil || s.opts.SingleSnapshot {
snapshot, err = s.snapshotter.TakeSnapshotFS()
Expand All @@ -423,7 +431,7 @@ func (s *stageBuilder) takeSnapshot(files []string) (string, error) {
return snapshot, err
}

func (s *stageBuilder) shouldTakeSnapshot(index int, files []string) bool {
func (s *stageBuilder) shouldTakeSnapshot(index int, files []string, provideFiles bool) bool {
isLastCommand := index == len(s.cmds)-1

// We only snapshot the very end with single snapshot mode on.
Expand All @@ -436,8 +444,8 @@ func (s *stageBuilder) shouldTakeSnapshot(index int, files []string) bool {
return true
}

// nil means snapshot everything.
if files == nil {
// if command does not provide files, snapshot everything.
if !provideFiles {
return true
}

Expand Down Expand Up @@ -848,3 +856,12 @@ func ResolveCrossStageInstructions(stages []instructions.Stage) map[string]strin
logrus.Debugf("Built stage name to index map: %v", nameToIndex)
return nameToIndex
}

func (s stageBuilder) initSnapshotWithTimings() error {
t := timing.Start("Initial FS snapshot")
if err := s.snapshotter.Init(); err != nil {
return err
}
timing.DefaultRun.Stop(t)
return nil
}
33 changes: 30 additions & 3 deletions pkg/executor/build_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,9 @@ func Test_stageBuilder_shouldTakeSnapshot(t *testing.T) {
cmds []commands.DockerCommand
}
type args struct {
index int
files []string
index int
files []string
hasFiles bool
}
tests := []struct {
name string
Expand Down Expand Up @@ -151,6 +152,32 @@ func Test_stageBuilder_shouldTakeSnapshot(t *testing.T) {
},
want: true,
},
{
name: "not final stage not last command but empty list of files",
fields: fields{
stage: config.KanikoStage{},
},
args: args{
index: 0,
files: []string{},
hasFiles: true,
},
want: false,
},
{
name: "not final stage not last command no files provided",
fields: fields{
stage: config.KanikoStage{
Final: false,
},
},
args: args{
index: 0,
files: nil,
hasFiles: false,
},
want: true,
},
{
name: "caching enabled intermediate container",
fields: fields{
Expand All @@ -177,7 +204,7 @@ func Test_stageBuilder_shouldTakeSnapshot(t *testing.T) {
opts: tt.fields.opts,
cmds: tt.fields.cmds,
}
if got := s.shouldTakeSnapshot(tt.args.index, tt.args.files); got != tt.want {
if got := s.shouldTakeSnapshot(tt.args.index, tt.args.files, tt.args.hasFiles); got != tt.want {
t.Errorf("stageBuilder.shouldTakeSnapshot() = %v, want %v", got, tt.want)
}
})
Expand Down
6 changes: 6 additions & 0 deletions pkg/executor/fakes.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ func (m MockDockerCommand) String() string {
func (m MockDockerCommand) FilesToSnapshot() []string {
return []string{"meow-snapshot-no-cache"}
}
func (m MockDockerCommand) ProvidesFilesToSnapshot() bool {
return true
}
func (m MockDockerCommand) CacheCommand(image v1.Image) commands.DockerCommand {
return m.cacheCommand
}
Expand Down Expand Up @@ -84,6 +87,9 @@ func (m MockCachedDockerCommand) String() string {
func (m MockCachedDockerCommand) FilesToSnapshot() []string {
return []string{"meow-snapshot"}
}
func (m MockCachedDockerCommand) ProvidesFilesToSnapshot() bool {
return true
}
func (m MockCachedDockerCommand) CacheCommand(image v1.Image) commands.DockerCommand {
return nil
}
Expand Down

0 comments on commit e1c7862

Please sign in to comment.