Skip to content

Commit

Permalink
Add --target flag for multistage builds
Browse files Browse the repository at this point in the history
  • Loading branch information
Priya Wadhwa authored and Priya Wadhwa committed Jul 25, 2018
1 parent acf0688 commit 9dc7043
Show file tree
Hide file tree
Showing 8 changed files with 93 additions and 13 deletions.
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,10 @@ Set this flag to strip timestamps out of the built image and make it reproducibl

Set this flag as `--tarPath=<path>` to save the image as a tarball at path instead of pushing the image.

#### --target

Set this flag to indicate which build stage is the target build stage.

### Debug Image

The kaniko executor image is based off of scratch and doesn't contain a shell.
Expand Down
3 changes: 3 additions & 0 deletions cmd/executor/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ var (
tarPath string
singleSnapshot bool
reproducible bool
target string
)

func init() {
Expand All @@ -60,6 +61,7 @@ func init() {
RootCmd.PersistentFlags().StringVarP(&tarPath, "tarPath", "", "", "Path to save the image in as a tarball instead of pushing")
RootCmd.PersistentFlags().BoolVarP(&singleSnapshot, "single-snapshot", "", false, "Set this flag to take a single snapshot at the end of the build.")
RootCmd.PersistentFlags().BoolVarP(&reproducible, "reproducible", "", false, "Strip timestamps out of the image to make it reproducible")
RootCmd.PersistentFlags().StringVarP(&target, "target", "", "", " Set the target build stage to build")
}

var RootCmd = &cobra.Command{
Expand Down Expand Up @@ -92,6 +94,7 @@ var RootCmd = &cobra.Command{
Args: buildArgs,
SingleSnapshot: singleSnapshot,
Reproducible: reproducible,
Target: target,
})
if err != nil {
logrus.Error(err)
Expand Down
10 changes: 10 additions & 0 deletions integration/dockerfiles/Dockerfile_test_target
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM gcr.io/distroless/base:latest as base
COPY . .

FROM scratch as second
ENV foopath context/foo
COPY --from=0 $foopath context/b* /foo/

FROM base
ARG file
COPY --from=second /foo $file
21 changes: 14 additions & 7 deletions integration/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ package integration
import (
"encoding/json"
"fmt"
"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/daemon"
"math"
"os"
"os/exec"
Expand All @@ -31,6 +28,10 @@ import (
"strings"
"testing"

"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/daemon"

"github.com/GoogleContainerTools/kaniko/testutil"
)

Expand Down Expand Up @@ -113,10 +114,15 @@ func TestRun(t *testing.T) {
"Dockerfile_test_multistage": {"file=/foo2"},
}

// Map for additional flags
additionalFlagsMap := map[string][]string{
// Map for additional docker flags
additionalDockerFlagsMap := map[string][]string{
"Dockerfile_test_target": {"--target=second"},
}
// Map for additional kaniko flags
additionalKanikoFlagsMap := map[string][]string{
"Dockerfile_test_add": {"--single-snapshot"},
"Dockerfile_test_scratch": {"--single-snapshot"},
"Dockerfile_test_target": {"--target=second"},
}

// TODO: remove test_user_run from this when https://github.com/GoogleContainerTools/container-diff/issues/237 is fixed
Expand Down Expand Up @@ -144,13 +150,14 @@ func TestRun(t *testing.T) {
buildArgs = append(buildArgs, arg)
}
// build docker image
additionalFlags := append(buildArgs, additionalDockerFlagsMap[dockerfile]...)
dockerImage := strings.ToLower(testRepo + dockerPrefix + dockerfile)
dockerCmd := exec.Command("docker",
append([]string{"build",
"-t", dockerImage,
"-f", path.Join(dockerfilesPath, dockerfile),
"."},
buildArgs...)...,
additionalFlags...)...,
)
RunCommand(dockerCmd, t)

Expand All @@ -173,7 +180,7 @@ func TestRun(t *testing.T) {
}

// build kaniko image
additionalFlags := append(buildArgs, additionalFlagsMap[dockerfile]...)
additionalFlags = append(buildArgs, additionalKanikoFlagsMap[dockerfile]...)
kanikoImage := strings.ToLower(testRepo + kanikoPrefix + dockerfile)
kanikoCmd := exec.Command("docker",
append([]string{"run",
Expand Down
17 changes: 14 additions & 3 deletions pkg/dockerfile/dockerfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ package dockerfile

import (
"bytes"
"fmt"
"path/filepath"
"strconv"
"strings"

"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/docker/docker/builder/dockerfile/parser"
"path/filepath"
"strconv"
"strings"
)

// Parse parses the contents of a Dockerfile and returns a list of commands
Expand All @@ -40,6 +42,15 @@ func Parse(b []byte) ([]instructions.Stage, error) {
return stages, err
}

func Validate(stages []instructions.Stage, target string) error {
for _, stage := range stages {
if stage.Name == target {
return nil
}
}
return fmt.Errorf("%s is not a valid target build stage", target)
}

// ResolveStages resolves any calls to previous stages with names to indices
// Ex. --from=second_stage should be --from=1 for easier processing later on
func ResolveStages(stages []instructions.Stage) {
Expand Down
44 changes: 42 additions & 2 deletions pkg/dockerfile/dockerfile_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,14 @@ package dockerfile

import (
"fmt"
"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/docker/docker/builder/dockerfile/instructions"
"io/ioutil"
"os"
"path/filepath"
"strconv"
"testing"

"github.com/GoogleContainerTools/kaniko/testutil"
"github.com/docker/docker/builder/dockerfile/instructions"
)

func Test_ResolveStages(t *testing.T) {
Expand Down Expand Up @@ -55,6 +56,45 @@ func Test_ResolveStages(t *testing.T) {
}
}

func Test_Validate(t *testing.T) {
dockerfile := `
FROM scratch
RUN echo hi > /hi
FROM scratch AS second
COPY --from=0 /hi /hi2
FROM scratch
COPY --from=second /hi2 /hi3
`
stages, err := Parse([]byte(dockerfile))
if err != nil {
t.Fatal(err)
}
tests := []struct {
name string
target string
shouldErr bool
}{
{
name: "test valid target",
target: "second",
shouldErr: false,
},
{
name: "test invalid target",
target: "invalid",
shouldErr: true,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
actualErr := Validate(stages, test.target)
testutil.CheckError(t, test.shouldErr, actualErr)
})
}
}

func Test_Dependencies(t *testing.T) {
testDir, err := ioutil.TempDir("", "")
if err != nil {
Expand Down
6 changes: 5 additions & 1 deletion pkg/executor/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type KanikoBuildArgs struct {
Args []string
SingleSnapshot bool
Reproducible bool
Target string
}

func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
Expand All @@ -65,14 +66,17 @@ func DoBuild(k KanikoBuildArgs) (v1.Image, error) {
if err != nil {
return nil, err
}
if err := dockerfile.Validate(stages, k.Target); err != nil {
return nil, err
}
dockerfile.ResolveStages(stages)

hasher, err := getHasher(k.SnapshotMode)
if err != nil {
return nil, err
}
for index, stage := range stages {
finalStage := index == len(stages)-1
finalStage := (index == len(stages)-1) || (k.Target == stage.Name)
// Unpack file system to root
sourceImage, err := util.RetrieveSourceImage(index, k.Args, stages)
if err != nil {
Expand Down
1 change: 1 addition & 0 deletions pkg/util/image_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ func tarballImage(index int) (v1.Image, error) {
}

func remoteImage(image string) (v1.Image, error) {
logrus.Infof("Downloading base image %s", image)
ref, err := name.ParseReference(image, name.WeakValidation)
if err != nil {
return nil, err
Expand Down

0 comments on commit 9dc7043

Please sign in to comment.