Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support multi stage builds #141

Merged
merged 12 commits into from
May 14, 2018
12 changes: 8 additions & 4 deletions cmd/executor/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,10 @@ import (
"os"
"path/filepath"

"github.com/GoogleContainerTools/kaniko/pkg/executor"
"github.com/genuinetools/amicontained/container"

"github.com/GoogleContainerTools/kaniko/pkg/constants"
"github.com/GoogleContainerTools/kaniko/pkg/executor"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/genuinetools/amicontained/container"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
)
Expand Down Expand Up @@ -78,7 +77,12 @@ var RootCmd = &cobra.Command{
logrus.Error(err)
os.Exit(1)
}
if err := executor.DoBuild(dockerfilePath, srcContext, destination, snapshotMode, dockerInsecureSkipTLSVerify, buildArgs); err != nil {
ref, image, err := executor.DoBuild(dockerfilePath, srcContext, snapshotMode, buildArgs)
if err != nil {
logrus.Error(err)
os.Exit(1)
}
if err := executor.DoPush(ref, image, destination); err != nil {
logrus.Error(err)
os.Exit(1)
}
Expand Down
10 changes: 10 additions & 0 deletions integration_tests/dockerfiles/Dockerfile_test_multistage
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
FROM gcr.io/distroless/base:latest
COPY . .

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

FROM gcr.io/distroless/base:latest
ARG file
COPY --from=second /foo $file
12 changes: 12 additions & 0 deletions integration_tests/dockerfiles/config_test_multistage.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[
{
"Image1": "gcr.io/kaniko-test/docker-test-multistage:latest",
"Image2": "gcr.io/kaniko-test/kaniko-test-multistage:latest",
"DiffType": "File",
"Diff": {
"Adds": null,
"Dels": null,
"Mods": null
}
}
]
11 changes: 11 additions & 0 deletions integration_tests/integration_test_yaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,17 @@ var fileTests = []struct {
"file3=context/b*",
},
},
{
description: "test multistage",
dockerfilePath: "/workspace/integration_tests/dockerfiles/Dockerfile_test_multistage",
configPath: "/workspace/integration_tests/dockerfiles/config_test_multistage.json",
dockerContext: buildcontextPath,
kanikoContext: buildcontextPath,
repo: "test-multistage",
args: []string{
"file=/foo2",
},
},
}

var structureTests = []struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (a *AddCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
logrus.Infof("dest: %s", dest)

// First, resolve any environment replacement
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(a.cmd.SourcesAndDest, replacementEnvs, true)
if err != nil {
return err
Expand Down
6 changes: 5 additions & 1 deletion pkg/commands/copy.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,11 @@ func (c *CopyCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
logrus.Infof("cmd: copy %s", srcs)
logrus.Infof("dest: %s", dest)

replacementEnvs := util.ReplacementEnvs(config, buildArgs)
// Resolve from
if c.cmd.From != "" {
c.buildcontext = filepath.Join(constants.KanikoDir, c.cmd.From)
}
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
// First, resolve any environment replacement
resolvedEnvs, err := util.ResolveEnvironmentReplacementList(c.cmd.SourcesAndDest, replacementEnvs, true)
if err != nil {
Expand Down
53 changes: 2 additions & 51 deletions pkg/commands/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,57 +33,8 @@ type EnvCommand struct {
func (e *EnvCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: ENV")
newEnvs := e.cmd.Env
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
for index, pair := range newEnvs {
expandedKey, err := util.ResolveEnvironmentReplacement(pair.Key, replacementEnvs, false)
if err != nil {
return err
}
expandedValue, err := util.ResolveEnvironmentReplacement(pair.Value, replacementEnvs, false)
if err != nil {
return err
}
newEnvs[index] = instructions.KeyValuePair{
Key: expandedKey,
Value: expandedValue,
}
}
return updateConfigEnv(newEnvs, config)
}

func updateConfigEnv(newEnvs []instructions.KeyValuePair, config *v1.Config) error {
// First, convert config.Env array to []instruction.KeyValuePair
var kvps []instructions.KeyValuePair
for _, env := range config.Env {
entry := strings.Split(env, "=")
kvps = append(kvps, instructions.KeyValuePair{
Key: entry[0],
Value: entry[1],
})
}
// Iterate through new environment variables, and replace existing keys
// We can't use a map because we need to preserve the order of the environment variables
Loop:
for _, newEnv := range newEnvs {
for index, kvp := range kvps {
// If key exists, replace the KeyValuePair...
if kvp.Key == newEnv.Key {
logrus.Debugf("Replacing environment variable %v with %v in config", kvp, newEnv)
kvps[index] = newEnv
continue Loop
}
}
// ... Else, append it as a new env variable
kvps = append(kvps, newEnv)
}
// Convert back to array and set in config
envArray := []string{}
for _, kvp := range kvps {
entry := kvp.Key + "=" + kvp.Value
envArray = append(envArray, entry)
}
config.Env = envArray
return nil
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
return util.UpdateConfigEnv(newEnvs, config, replacementEnvs)
}

// We know that no files have changed, so return an empty array
Expand Down
31 changes: 0 additions & 31 deletions pkg/commands/env_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,37 +23,6 @@ import (
"testing"
)

func TestUpdateEnvConfig(t *testing.T) {
cfg := &v1.Config{
Env: []string{
"PATH=/path/to/dir",
"hey=hey",
},
}

newEnvs := []instructions.KeyValuePair{
{
Key: "foo",
Value: "foo2",
},
{
Key: "PATH",
Value: "/new/path/",
},
{
Key: "foo",
Value: "newfoo",
},
}

expectedEnvArray := []string{
"PATH=/new/path/",
"hey=hey",
"foo=newfoo",
}
updateConfigEnv(newEnvs, cfg)
testutil.CheckErrorAndDeepEqual(t, false, nil, expectedEnvArray, cfg.Env)
}
func Test_EnvExecute(t *testing.T) {
cfg := &v1.Config{
Env: []string{
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/expose.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (r *ExposeCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.
if existingPorts == nil {
existingPorts = make(map[string]struct{})
}
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
// Add any new ones in
for _, p := range r.cmd.Ports {
// Resolve any environment variables
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/label.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func updateLabels(labels []instructions.KeyValuePair, config *v1.Config, buildAr
existingLabels = make(map[string]string)
}
// Let's unescape values before setting the label
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
for index, kvp := range labels {
key, err := util.ResolveEnvironmentReplacement(kvp.Key, replacementEnvs, false)
if err != nil {
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/onbuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type OnBuildCommand struct {
func (o *OnBuildCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: ONBUILD")
logrus.Infof("args: %s", o.cmd.Expression)
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
resolvedExpression, err := util.ResolveEnvironmentReplacement(o.cmd.Expression, replacementEnvs, false)
if err != nil {
return err
Expand Down
3 changes: 1 addition & 2 deletions pkg/commands/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package commands

import (
"github.com/GoogleContainerTools/kaniko/pkg/dockerfile"
"github.com/GoogleContainerTools/kaniko/pkg/util"
"github.com/docker/docker/builder/dockerfile/instructions"
"github.com/google/go-containerregistry/v1"
"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -55,7 +54,7 @@ func (r *RunCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bui
cmd := exec.Command(newCommand[0], newCommand[1:]...)
cmd.Dir = config.WorkingDir
cmd.Stdout = os.Stdout
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
cmd.Env = replacementEnvs

// If specified, run the command as a specific user
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/stopsignal.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ func (s *StopSignalCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerf
logrus.Info("cmd: STOPSIGNAL")

// resolve possible environment variables
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
resolvedEnvs, err := util.ResolveEnvironmentReplacementList([]string{s.cmd.Signal}, replacementEnvs, false)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (r *UserCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.Bu
logrus.Info("cmd: USER")
u := r.cmd.User
userAndGroup := strings.Split(u, ":")
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
userStr, err := util.ResolveEnvironmentReplacement(userAndGroup[0], replacementEnvs, false)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/volume.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type VolumeCommand struct {
func (v *VolumeCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: VOLUME")
volumes := v.cmd.Volumes
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
resolvedVolumes, err := util.ResolveEnvironmentReplacementList(volumes, replacementEnvs, true)
if err != nil {
return err
Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/workdir.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ type WorkdirCommand struct {
func (w *WorkdirCommand) ExecuteCommand(config *v1.Config, buildArgs *dockerfile.BuildArgs) error {
logrus.Info("cmd: workdir")
workdirPath := w.cmd.Path
replacementEnvs := util.ReplacementEnvs(config, buildArgs)
replacementEnvs := buildArgs.ReplacementEnvs(config.Env)
resolvedWorkingDir, err := util.ResolveEnvironmentReplacement(workdirPath, replacementEnvs, true)
if err != nil {
return err
Expand Down
6 changes: 6 additions & 0 deletions pkg/dockerfile/buildargs.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,9 @@ func NewBuildArgs(args []string) *BuildArgs {
*d.NewBuildArgs(argsFromOptions),
}
}

// ReplacementEnvs returns a list of filtered environment variables
func (b *BuildArgs) ReplacementEnvs(envs []string) []string {
filtered := b.FilterAllowed(envs)
return append(envs, filtered...)
}
Loading