suport multistage onbuild
This commit is contained in:
parent
2609944787
commit
70eb7ebcfa
|
|
@ -87,6 +87,75 @@ func Stages(opts *config.KanikoOptions) ([]config.KanikoStage, error) {
|
||||||
return kanikoStages, nil
|
return kanikoStages, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ParseInstructions(opts *config.KanikoOptions) ([]instructions.Stage, []instructions.ArgCommand, error) {
|
||||||
|
var err error
|
||||||
|
var d []uint8
|
||||||
|
match, _ := regexp.MatchString("^https?://", opts.DockerfilePath)
|
||||||
|
if match {
|
||||||
|
response, e := http.Get(opts.DockerfilePath)
|
||||||
|
if e != nil {
|
||||||
|
return nil, nil, e
|
||||||
|
}
|
||||||
|
d, err = ioutil.ReadAll(response.Body)
|
||||||
|
} else {
|
||||||
|
d, err = ioutil.ReadFile(opts.DockerfilePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, fmt.Sprintf("reading dockerfile at path %s", opts.DockerfilePath))
|
||||||
|
}
|
||||||
|
|
||||||
|
stages, metaArgs, err := Parse(d)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, errors.Wrap(err, "parsing dockerfile")
|
||||||
|
}
|
||||||
|
|
||||||
|
return stages, metaArgs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ResolveCrossStageInstructions(stages []instructions.Stage) map[string]string {
|
||||||
|
nameToIndex := make(map[string]string)
|
||||||
|
for i, stage := range stages {
|
||||||
|
index := strconv.Itoa(i)
|
||||||
|
if stage.Name != "" {
|
||||||
|
nameToIndex[stage.Name] = index
|
||||||
|
}
|
||||||
|
ResolveCommands(stage.Commands, nameToIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
logrus.Debugf("Built stage name to index map: %v", nameToIndex)
|
||||||
|
return nameToIndex
|
||||||
|
}
|
||||||
|
|
||||||
|
func MakeKanikoStages(opts *config.KanikoOptions, stages []instructions.Stage, metaArgs []instructions.ArgCommand) ([]config.KanikoStage, error) {
|
||||||
|
targetStage, err := targetStage(stages, opts.Target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Error finding target stage")
|
||||||
|
}
|
||||||
|
var kanikoStages []config.KanikoStage
|
||||||
|
for index, stage := range stages {
|
||||||
|
resolvedBaseName, err := util.ResolveEnvironmentReplacement(stage.BaseName, opts.BuildArgs, false)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "resolving base name")
|
||||||
|
}
|
||||||
|
stage.Name = resolvedBaseName
|
||||||
|
logrus.Infof("Resolved base name %s to %s", stage.BaseName, stage.Name)
|
||||||
|
kanikoStages = append(kanikoStages, config.KanikoStage{
|
||||||
|
Stage: stage,
|
||||||
|
BaseImageIndex: baseImageIndex(index, stages),
|
||||||
|
BaseImageStoredLocally: (baseImageIndex(index, stages) != -1),
|
||||||
|
SaveStage: saveStage(index, stages),
|
||||||
|
Final: index == targetStage,
|
||||||
|
MetaArgs: metaArgs,
|
||||||
|
Index: index,
|
||||||
|
})
|
||||||
|
if index == targetStage {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return kanikoStages, nil
|
||||||
|
}
|
||||||
|
|
||||||
// baseImageIndex returns the index of the stage the current stage is built off
|
// baseImageIndex returns the index of the stage the current stage is built off
|
||||||
// returns -1 if the current stage isn't built off a previous stage
|
// returns -1 if the current stage isn't built off a previous stage
|
||||||
func baseImageIndex(currentStage int, stages []instructions.Stage) int {
|
func baseImageIndex(currentStage int, stages []instructions.Stage) int {
|
||||||
|
|
@ -221,7 +290,6 @@ func resolveStages(stages []instructions.Stage) {
|
||||||
if val, ok := nameToIndex[strings.ToLower(c.From)]; ok {
|
if val, ok := nameToIndex[strings.ToLower(c.From)]; ok {
|
||||||
c.From = val
|
c.From = val
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -264,3 +332,18 @@ func saveStage(index int, stages []instructions.Stage) bool {
|
||||||
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO move it to private method or put elsewhere
|
||||||
|
func ResolveCommands(cmds []instructions.Command, stageNameToIdx map[string]string) () {
|
||||||
|
for _, cmd := range cmds {
|
||||||
|
switch c := cmd.(type) {
|
||||||
|
case *instructions.CopyCommand:
|
||||||
|
if c.From != "" {
|
||||||
|
if val, ok := stageNameToIdx[strings.ToLower(c.From)]; ok {
|
||||||
|
c.From = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -25,6 +25,7 @@ import (
|
||||||
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
"github.com/GoogleContainerTools/kaniko/pkg/config"
|
||||||
"github.com/GoogleContainerTools/kaniko/testutil"
|
"github.com/GoogleContainerTools/kaniko/testutil"
|
||||||
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
"github.com/moby/buildkit/frontend/dockerfile/instructions"
|
||||||
|
"github.com/sirupsen/logrus"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_Stages_ArgValueWithQuotes(t *testing.T) {
|
func Test_Stages_ArgValueWithQuotes(t *testing.T) {
|
||||||
|
|
@ -364,3 +365,30 @@ func Test_baseImageIndex(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
func Test_ResolveStages(t *testing.T) {
|
||||||
|
in := &instructions.CopyCommand{
|
||||||
|
SourcesAndDest: []string{
|
||||||
|
"/var/bo", "foo.txt",
|
||||||
|
},
|
||||||
|
From: "boo",
|
||||||
|
Chown: "",
|
||||||
|
}
|
||||||
|
ibn := &instructions.CopyCommand{
|
||||||
|
SourcesAndDest: []string{
|
||||||
|
"/var/bo", "foo.txt",
|
||||||
|
},
|
||||||
|
From: "poo",
|
||||||
|
Chown: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
foo := []instructions.Command{in, ibn}
|
||||||
|
stageMap := map[string]string{"boo": "1"}
|
||||||
|
logrus.Infof("%#v", foo)
|
||||||
|
ResolveCommands(foo, stageMap)
|
||||||
|
logrus.Infof("%#v", foo)
|
||||||
|
logrus.Infof("%#v", foo[0])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -78,7 +78,7 @@ type stageBuilder struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
// newStageBuilder returns a new type stageBuilder which contains all the information required to build the stage
|
// newStageBuilder returns a new type stageBuilder which contains all the information required to build the stage
|
||||||
func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, crossStageDeps map[int][]string, dcm map[string]string, sid map[string]string) (*stageBuilder, error) {
|
func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, crossStageDeps map[int][]string, dcm map[string]string, sid map[string]string, stageNameToIdx map[string]string) (*stageBuilder, error) {
|
||||||
sourceImage, err := util.RetrieveSourceImage(stage, opts)
|
sourceImage, err := util.RetrieveSourceImage(stage, opts)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -89,7 +89,7 @@ func newStageBuilder(opts *config.KanikoOptions, stage config.KanikoStage, cross
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := resolveOnBuild(&stage, &imageConfig.Config); err != nil {
|
if err := resolveOnBuild(&stage, &imageConfig.Config, stageNameToIdx); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -550,8 +550,25 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
|
||||||
digestToCacheKey := make(map[string]string)
|
digestToCacheKey := make(map[string]string)
|
||||||
stageIdxToDigest := make(map[string]string)
|
stageIdxToDigest := make(map[string]string)
|
||||||
|
|
||||||
|
//* dani plan
|
||||||
|
// 1. parse opts - to []instruction.Stages
|
||||||
|
// 2. resolve environment - get map stageidx-->name
|
||||||
|
// 3. convert []instruction.Stages to []config.KanikoStages
|
||||||
|
// 4. pass to newStageBuilder() the map to resolve on build
|
||||||
|
//*/
|
||||||
|
|
||||||
// Parse dockerfile
|
// Parse dockerfile
|
||||||
stages, err := dockerfile.Stages(opts)
|
//stages, err := dockerfile.Stages(opts)
|
||||||
|
//if err != nil {
|
||||||
|
// return nil, err
|
||||||
|
//}
|
||||||
|
instrct, metaArgs, err := dockerfile.ParseInstructions(opts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
stageNameToIdx := dockerfile.ResolveCrossStageInstructions(instrct)
|
||||||
|
|
||||||
|
stages, err := dockerfile.MakeKanikoStages(opts, instrct, metaArgs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -571,7 +588,7 @@ func DoBuild(opts *config.KanikoOptions) (v1.Image, error) {
|
||||||
logrus.Infof("Built cross stage deps: %v", crossStageDependencies)
|
logrus.Infof("Built cross stage deps: %v", crossStageDependencies)
|
||||||
|
|
||||||
for index, stage := range stages {
|
for index, stage := range stages {
|
||||||
sb, err := newStageBuilder(opts, stage, crossStageDependencies, digestToCacheKey, stageIdxToDigest)
|
sb, err := newStageBuilder(opts, stage, crossStageDependencies, digestToCacheKey, stageIdxToDigest, stageNameToIdx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -771,7 +788,7 @@ func getHasher(snapshotMode string) (func(string) (string, error), error) {
|
||||||
return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode)
|
return nil, fmt.Errorf("%s is not a valid snapshot mode", snapshotMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveOnBuild(stage *config.KanikoStage, config *v1.Config) error {
|
func resolveOnBuild(stage *config.KanikoStage, config *v1.Config, stageNameToIdx map[string]string) error {
|
||||||
if config.OnBuild == nil || len(config.OnBuild) == 0 {
|
if config.OnBuild == nil || len(config.OnBuild) == 0 {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
@ -780,6 +797,10 @@ func resolveOnBuild(stage *config.KanikoStage, config *v1.Config) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Iterate over commands and replace references to other stages with their index
|
||||||
|
dockerfile.ResolveCommands(cmds, stageNameToIdx)
|
||||||
|
|
||||||
// Append to the beginning of the commands in the stage
|
// Append to the beginning of the commands in the stage
|
||||||
stage.Commands = append(cmds, stage.Commands...)
|
stage.Commands = append(cmds, stage.Commands...)
|
||||||
logrus.Infof("Executing %v build triggers", len(cmds))
|
logrus.Infof("Executing %v build triggers", len(cmds))
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue