@@ -61,23 +61,24 @@ type snapShotter interface {
6161
6262// stageBuilder contains all fields necessary to build one stage of a Dockerfile
6363type stageBuilder struct {
64- stage config.KanikoStage
65- image v1.Image
66- cf * v1.ConfigFile
67- snapshotter snapShotter
68- layerCache cache.LayerCache
69- pushCache cachePusher
70- baseImageDigest string
71- finalCacheKey string
72- opts * config.KanikoOptions
73- cmds []commands.DockerCommand
74- args * dockerfile.BuildArgs
75- crossStageDeps map [int ][]string
76- digestToCacheKeyMap map [string ]string
64+ stage config.KanikoStage
65+ image v1.Image
66+ cf * v1.ConfigFile
67+ baseImageDigest string
68+ finalCacheKey string
69+ opts * config.KanikoOptions
70+ cmds []commands.DockerCommand
71+ args * dockerfile.BuildArgs
72+ crossStageDeps map [int ][]string
73+ digestToCacheKey map [string ]string
74+ stageIdxToDigest map [string ]string
75+ snapshotter snapShotter
76+ layerCache cache.LayerCache
77+ pushCache cachePusher
7778}
7879
7980// newStageBuilder returns a new type stageBuilder which contains all the information required to build the stage
80- func newStageBuilder (opts * config.KanikoOptions , stage config.KanikoStage , crossStageDeps map [int ][]string , dcm map [string ]string ) (* stageBuilder , error ) {
81+ func newStageBuilder (opts * config.KanikoOptions , stage config.KanikoStage , crossStageDeps map [int ][]string , dcm map [string ]string , sid map [ string ] string ) (* stageBuilder , error ) {
8182 sourceImage , err := util .RetrieveSourceImage (stage , opts )
8283 if err != nil {
8384 return nil , err
@@ -104,14 +105,15 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
104105 return nil , err
105106 }
106107 s := & stageBuilder {
107- stage : stage ,
108- image : sourceImage ,
109- cf : imageConfig ,
110- snapshotter : snapshotter ,
111- baseImageDigest : digest .String (),
112- opts : opts ,
113- crossStageDeps : crossStageDeps ,
114- digestToCacheKeyMap : dcm ,
108+ stage : stage ,
109+ image : sourceImage ,
110+ cf : imageConfig ,
111+ snapshotter : snapshotter ,
112+ baseImageDigest : digest .String (),
113+ opts : opts ,
114+ crossStageDeps : crossStageDeps ,
115+ digestToCacheKey : dcm ,
116+ stageIdxToDigest : sid ,
115117 layerCache : & cache.RegistryCache {
116118 Opts : opts ,
117119 },
@@ -146,6 +148,40 @@ func initializeConfig(img partial.WithConfigFile) (*v1.ConfigFile, error) {
146148 return imageConfig , nil
147149}
148150
151+ func (s * stageBuilder ) populateCompositeKey (command fmt.Stringer , files []string , compositeKey CompositeCache ) (CompositeCache , error ) {
152+ // Add the next command to the cache key.
153+ compositeKey .AddKey (command .String ())
154+ switch v := command .(type ) {
155+ case * commands.CopyCommand :
156+ compositeKey = s .populateCopyCmdCompositeKey (command , v .From (), compositeKey )
157+ case * commands.CachingCopyCommand :
158+ compositeKey = s .populateCopyCmdCompositeKey (command , v .From (), compositeKey )
159+ }
160+
161+ for _ , f := range files {
162+ if err := compositeKey .AddPath (f ); err != nil {
163+ return compositeKey , err
164+ }
165+ }
166+ return compositeKey , nil
167+ }
168+
169+ func (s * stageBuilder ) populateCopyCmdCompositeKey (command fmt.Stringer , from string , compositeKey CompositeCache ) CompositeCache {
170+ if from != "" {
171+ digest , ok := s .stageIdxToDigest [from ]
172+ if ok {
173+ ds := digest
174+ cacheKey , ok := s .digestToCacheKey [ds ]
175+ if ok {
176+ logrus .Debugf ("adding digest %v from previous stage to composite key for %v" , ds , command .String ())
177+ compositeKey .AddKey (cacheKey )
178+ }
179+ }
180+ }
181+
182+ return compositeKey
183+ }
184+
149185func (s * stageBuilder ) optimize (compositeKey CompositeCache , cfg v1.Config ) error {
150186 if ! s .opts .Cache {
151187 return nil
@@ -160,22 +196,22 @@ func (s *stageBuilder) optimize(compositeKey CompositeCache, cfg v1.Config) erro
160196 if command == nil {
161197 continue
162198 }
163- compositeKey .AddKey (command .String ())
164- // If the command uses files from the context, add them.
165199 files , err := command .FilesUsedFromContext (& cfg , s .args )
166200 if err != nil {
167201 return errors .Wrap (err , "failed to get files used from context" )
168202 }
169- for _ , f := range files {
170- if err := compositeKey . AddPath ( f ); err != nil {
171- return errors . Wrap ( err , "failed to add path to composite key" )
172- }
203+
204+ compositeKey , err = s . populateCompositeKey ( command , files , compositeKey )
205+ if err != nil {
206+ return err
173207 }
174208
209+ logrus .Debugf ("optimize: composite key for command %v %v" , command .String (), compositeKey )
175210 ck , err := compositeKey .Hash ()
176211 if err != nil {
177212 return errors .Wrap (err , "failed to hash composite key" )
178213 }
214+ logrus .Debugf ("optimize: cache key for command %v %v" , command .String (), ck )
179215 s .finalCacheKey = ck
180216 if command .ShouldCacheOutput () && ! stopCache {
181217 img , err := s .layerCache .RetrieveLayer (ck )
@@ -206,7 +242,7 @@ func (s *stageBuilder) optimize(compositeKey CompositeCache, cfg v1.Config) erro
206242func (s * stageBuilder ) build () error {
207243 // Set the initial cache key to be the base image digest, the build args and the SrcContext.
208244 var compositeKey * CompositeCache
209- if cacheKey , ok := s .digestToCacheKeyMap [s .baseImageDigest ]; ok {
245+ if cacheKey , ok := s .digestToCacheKey [s .baseImageDigest ]; ok {
210246 compositeKey = NewCompositeCache (cacheKey )
211247 } else {
212248 compositeKey = NewCompositeCache (s .baseImageDigest )
@@ -256,19 +292,19 @@ func (s *stageBuilder) build() error {
256292 continue
257293 }
258294
259- // Add the next command to the cache key.
260- compositeKey .AddKey (command .String ())
261295 t := timing .Start ("Command: " + command .String ())
296+
262297 // If the command uses files from the context, add them.
263298 files , err := command .FilesUsedFromContext (& s .cf .Config , s .args )
264299 if err != nil {
265300 return errors .Wrap (err , "failed to get files used from context" )
266301 }
267- for _ , f := range files {
268- if err := compositeKey . AddPath ( f ); err != nil {
269- return errors . Wrap ( err , fmt . Sprintf ( "failed to add path to composite key %v" , f ))
270- }
302+
303+ * compositeKey , err = s . populateCompositeKey ( command , files , * compositeKey )
304+ if err != nil {
305+ return err
271306 }
307+
272308 logrus .Info (command .String ())
273309
274310 if err := command .ExecuteCommand (& s .cf .Config , s .args ); err != nil {
@@ -286,6 +322,7 @@ func (s *stageBuilder) build() error {
286322 return errors .Wrap (err , "failed to take snapshot" )
287323 }
288324
325+ logrus .Debugf ("build: composite key for command %v %v" , command .String (), compositeKey )
289326 ck , err := compositeKey .Hash ()
290327 if err != nil {
291328 return errors .Wrap (err , "failed to hash composite key" )
@@ -303,6 +340,7 @@ func (s *stageBuilder) build() error {
303340 if err := cacheGroup .Wait (); err != nil {
304341 logrus .Warnf ("error uploading layer to cache: %s" , err )
305342 }
343+
306344 return nil
307345}
308346
@@ -374,7 +412,6 @@ func (s *stageBuilder) saveSnapshotToImage(createdBy string, tarPath string) err
374412 },
375413 )
376414 return err
377-
378415}
379416
380417func CalculateDependencies (opts * config.KanikoOptions ) (map [int ][]string , error ) {
@@ -442,7 +479,9 @@ func CalculateDependencies(opts *config.KanikoOptions) (map[int][]string, error)
442479// DoBuild executes building the Dockerfile
443480func DoBuild (opts * config.KanikoOptions ) (v1.Image , error ) {
444481 t := timing .Start ("Total Build Time" )
445- digestToCacheKeyMap := make (map [string ]string )
482+ digestToCacheKey := make (map [string ]string )
483+ stageIdxToDigest := make (map [string ]string )
484+
446485 // Parse dockerfile and unpack base image to root
447486 stages , err := dockerfile .Stages (opts )
448487 if err != nil {
@@ -463,23 +502,32 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
463502 logrus .Infof ("Built cross stage deps: %v" , crossStageDependencies )
464503
465504 for index , stage := range stages {
466- sb , err := newStageBuilder (opts , stage , crossStageDependencies , digestToCacheKeyMap )
505+ sb , err := newStageBuilder (opts , stage , crossStageDependencies , digestToCacheKey , stageIdxToDigest )
467506 if err != nil {
468507 return nil , err
469508 }
470509 if err := sb .build (); err != nil {
471510 return nil , errors .Wrap (err , "error building stage" )
472511 }
512+
473513 reviewConfig (stage , & sb .cf .Config )
514+
474515 sourceImage , err := mutate .Config (sb .image , sb .cf .Config )
475516 if err != nil {
476517 return nil , err
477518 }
519+
478520 d , err := sourceImage .Digest ()
479521 if err != nil {
480522 return nil , err
481523 }
482- digestToCacheKeyMap [d .String ()] = sb .finalCacheKey
524+
525+ stageIdxToDigest [fmt .Sprintf ("%d" , sb .stage .Index )] = d .String ()
526+ logrus .Debugf ("mapping stage idx %v to digest %v" , sb .stage .Index , d .String ())
527+
528+ digestToCacheKey [d .String ()] = sb .finalCacheKey
529+ logrus .Debugf ("mapping digest %v to cachekey %v" , d .String (), sb .finalCacheKey )
530+
483531 if stage .Final {
484532 sourceImage , err = mutate .CreatedAt (sourceImage , v1.Time {Time : time .Now ()})
485533 if err != nil {
0 commit comments