@@ -44,6 +44,7 @@ import (
44
44
"github.com/GoogleContainerTools/kaniko/pkg/filesystem"
45
45
image_util "github.com/GoogleContainerTools/kaniko/pkg/image"
46
46
"github.com/GoogleContainerTools/kaniko/pkg/image/remote"
47
+ "github.com/GoogleContainerTools/kaniko/pkg/imagefs"
47
48
"github.com/GoogleContainerTools/kaniko/pkg/snapshot"
48
49
"github.com/GoogleContainerTools/kaniko/pkg/timing"
49
50
"github.com/GoogleContainerTools/kaniko/pkg/util"
@@ -731,9 +732,12 @@ func (s *stageBuilder) saveLayerToImage(layer v1.Layer, createdBy string) error
731
732
return err
732
733
}
733
734
734
- func CalculateDependencies (stages []config.KanikoStage , opts * config.KanikoOptions , stageNameToIdx map [string ]string ) (map [int ][]string , error ) {
735
+ func CalculateDependencies (stages []config.KanikoStage , opts * config.KanikoOptions , stageNameToIdx map [string ]string ) (map [int ][]string , map [ string ][] string , error ) {
735
736
images := []v1.Image {}
736
- depGraph := map [int ][]string {}
737
+ stageDepGraph := map [int ][]string {}
738
+ // imageDepGraph tracks stage dependencies from non-stage
739
+ // images for use by imagefs to avoid extraction.
740
+ imageDepGraph := map [string ][]string {}
737
741
for _ , s := range stages {
738
742
ba := dockerfile .NewBuildArgs (opts .BuildArgs )
739
743
ba .AddMetaArgs (s .MetaArgs )
@@ -746,12 +750,12 @@ func CalculateDependencies(stages []config.KanikoStage, opts *config.KanikoOptio
746
750
} else {
747
751
image , err = image_util .RetrieveSourceImage (s , opts )
748
752
if err != nil {
749
- return nil , err
753
+ return nil , nil , err
750
754
}
751
755
}
752
756
cfg , err := initializeConfig (image , opts )
753
757
if err != nil {
754
- return nil , err
758
+ return nil , nil , err
755
759
}
756
760
757
761
cmds , err := dockerfile .GetOnBuildInstructions (& cfg .Config , stageNameToIdx )
@@ -761,37 +765,38 @@ func CalculateDependencies(stages []config.KanikoStage, opts *config.KanikoOptio
761
765
switch cmd := c .(type ) {
762
766
case * instructions.CopyCommand :
763
767
if cmd .From != "" {
764
- i , err := strconv .Atoi (cmd .From )
765
- if err != nil {
766
- continue
767
- }
768
768
resolved , err := util .ResolveEnvironmentReplacementList (cmd .SourcesAndDest .SourcePaths , ba .ReplacementEnvs (cfg .Config .Env ), true )
769
769
if err != nil {
770
- return nil , err
770
+ return nil , nil , err
771
+ }
772
+ i , err := strconv .Atoi (cmd .From )
773
+ if err == nil {
774
+ stageDepGraph [i ] = append (stageDepGraph [i ], resolved ... )
775
+ } else {
776
+ imageDepGraph [cmd .From ] = append (imageDepGraph [cmd .From ], resolved ... )
771
777
}
772
- depGraph [i ] = append (depGraph [i ], resolved ... )
773
778
}
774
779
case * instructions.EnvCommand :
775
780
if err := util .UpdateConfigEnv (cmd .Env , & cfg .Config , ba .ReplacementEnvs (cfg .Config .Env )); err != nil {
776
- return nil , err
781
+ return nil , nil , err
777
782
}
778
783
image , err = mutate .Config (image , cfg .Config )
779
784
if err != nil {
780
- return nil , err
785
+ return nil , nil , err
781
786
}
782
787
case * instructions.ArgCommand :
783
788
for _ , arg := range cmd .Args {
784
789
k , v , err := commands .ParseArg (arg .Key , arg .Value , cfg .Config .Env , ba )
785
790
if err != nil {
786
- return nil , err
791
+ return nil , nil , err
787
792
}
788
793
ba .AddArg (k , v )
789
794
}
790
795
}
791
796
}
792
797
images = append (images , image )
793
798
}
794
- return depGraph , nil
799
+ return stageDepGraph , imageDepGraph , nil
795
800
}
796
801
797
802
// DoBuild executes building the Dockerfile
@@ -816,15 +821,17 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
816
821
return nil , err
817
822
}
818
823
819
- // Some stages may refer to other random images, not previous stages
820
- if err := fetchExtraStages (kanikoStages , opts ); err != nil {
821
- return nil , err
822
- }
823
- crossStageDependencies , err := CalculateDependencies (kanikoStages , opts , stageNameToIdx )
824
+ crossStageDependencies , imageDependencies , err := CalculateDependencies (kanikoStages , opts , stageNameToIdx )
824
825
if err != nil {
825
826
return nil , err
826
827
}
827
828
logrus .Infof ("Built cross stage deps: %v" , crossStageDependencies )
829
+ logrus .Infof ("Built image deps: %v" , imageDependencies )
830
+
831
+ // Some stages may refer to other random images, not previous stages
832
+ if err := fetchExtraStages (kanikoStages , opts , false , imageDependencies ); err != nil {
833
+ return nil , errors .Wrap (err , "fetch extra stages failed" )
834
+ }
828
835
829
836
var args * dockerfile.BuildArgs
830
837
@@ -940,6 +947,12 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
940
947
// cache without modifying the filesystem.
941
948
// Returns an error if any layers are missing from build cache.
942
949
func DoCacheProbe (opts * config.KanikoOptions ) (v1.Image , error ) {
950
+ // Restore the filesystem after we're done since we're using imagefs.
951
+ origFS := filesystem .FS
952
+ defer func () {
953
+ filesystem .SetFS (origFS )
954
+ }()
955
+
943
956
digestToCacheKey := make (map [string ]string )
944
957
stageIdxToDigest := make (map [string ]string )
945
958
@@ -959,15 +972,16 @@ func DoCacheProbe(opts *config.KanikoOptions) (v1.Image, error) {
959
972
return nil , err
960
973
}
961
974
962
- // Some stages may refer to other random images, not previous stages
963
- if err := fetchExtraStages (kanikoStages , opts ); err != nil {
964
- return nil , err
965
- }
966
- crossStageDependencies , err := CalculateDependencies (kanikoStages , opts , stageNameToIdx )
975
+ crossStageDependencies , imageDependencies , err := CalculateDependencies (kanikoStages , opts , stageNameToIdx )
967
976
if err != nil {
968
977
return nil , err
969
978
}
970
979
logrus .Infof ("Built cross stage deps: %v" , crossStageDependencies )
980
+ logrus .Infof ("Built image deps: %v" , imageDependencies )
981
+ // Some stages may refer to other random images, not previous stages
982
+ if err := fetchExtraStages (kanikoStages , opts , true , imageDependencies ); err != nil {
983
+ return nil , errors .Wrap (err , "fetch extra stages failed" )
984
+ }
971
985
972
986
var args * dockerfile.BuildArgs
973
987
@@ -1021,6 +1035,19 @@ func DoCacheProbe(opts *config.KanikoOptions) (v1.Image, error) {
1021
1035
digestToCacheKey [d .String ()] = sb .finalCacheKey
1022
1036
logrus .Infof ("Mapping digest %v to cachekey %v" , d .String (), sb .finalCacheKey )
1023
1037
1038
+ if filesToCache , ok := crossStageDependencies [sb .stage .Index ]; ok {
1039
+ ifs , err := imagefs .New (
1040
+ filesystem .FS ,
1041
+ filepath .Join (config .KanikoDir , strconv .Itoa (sb .stage .Index )),
1042
+ sourceImage ,
1043
+ filesToCache ,
1044
+ )
1045
+ if err != nil {
1046
+ return nil , errors .Wrap (err , "could not create image filesystem" )
1047
+ }
1048
+ filesystem .SetFS (ifs )
1049
+ }
1050
+
1024
1051
if stage .Final {
1025
1052
sourceImage , err = mutateCanonicalWithoutLayerEdit (sourceImage )
1026
1053
if err != nil {
@@ -1143,7 +1170,7 @@ func deduplicatePaths(paths []string) []string {
1143
1170
return deduped
1144
1171
}
1145
1172
1146
- func fetchExtraStages (stages []config.KanikoStage , opts * config.KanikoOptions ) error {
1173
+ func fetchExtraStages (stages []config.KanikoStage , opts * config.KanikoOptions , cacheProbe bool , imageDependencies map [ string ][] string ) error {
1147
1174
t := timing .Start ("Fetching Extra Stages" )
1148
1175
defer timing .DefaultRun .Stop (t )
1149
1176
@@ -1177,8 +1204,21 @@ func fetchExtraStages(stages []config.KanikoStage, opts *config.KanikoOptions) e
1177
1204
if err := saveStageAsTarball (c .From , sourceImage ); err != nil {
1178
1205
return err
1179
1206
}
1180
- if err := extractImageToDependencyDir (c .From , sourceImage ); err != nil {
1181
- return err
1207
+ if ! cacheProbe {
1208
+ if err := extractImageToDependencyDir (c .From , sourceImage ); err != nil {
1209
+ return err
1210
+ }
1211
+ } else {
1212
+ ifs , err := imagefs .New (
1213
+ filesystem .FS ,
1214
+ filepath .Join (config .KanikoDir , c .From ),
1215
+ sourceImage ,
1216
+ imageDependencies [c .From ],
1217
+ )
1218
+ if err != nil {
1219
+ return errors .Wrap (err , "could not create image filesystem" )
1220
+ }
1221
+ filesystem .SetFS (ifs )
1182
1222
}
1183
1223
}
1184
1224
// Store the name of the current stage in the list with names, if applicable.
0 commit comments