From a572774bbe9b0aac0da29228682cd16fe88938f3 Mon Sep 17 00:00:00 2001 From: Priya Wadhwa Date: Fri, 12 Oct 2018 11:55:09 -0700 Subject: [PATCH] Add --ignore flag Added a --ignore flag to ignore packages and files in the build context. This should mimic the .dockerignore file. Before starting the build, we go through and delete ignored files from the build context. --- README.md | 4 ++ cmd/executor/cmd/root.go | 33 +++++++++++ .../dockerfiles/Dockerfile_test_ignore | 2 + integration/images.go | 59 ++++++++++++++++++- pkg/config/options.go | 1 + 5 files changed, 96 insertions(+), 3 deletions(-) create mode 100644 integration/dockerfiles/Dockerfile_test_ignore diff --git a/README.md b/README.md index 39c24e310..de8116141 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,10 @@ _This flag must be used in conjunction with the `--cache=true` flag._ Set this flag to cleanup the filesystem at the end, leaving a clean kaniko container (if you want to build multiple images in the same container, using the debug kaniko image) +#### --ignore + +Set this flag to ignore files in your build context. For examples, set `--ignore pkg/*` to ignore all files in the `pkg` directory. + ### Debug Image The kaniko executor image is based off of scratch and doesn't contain a shell. diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 55d256f28..089378442 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -61,6 +61,9 @@ var RootCmd = &cobra.Command{ if err := resolveSourceContext(); err != nil { return errors.Wrap(err, "error resolving source context") } + if err := removeIgnoredFiles(); err != nil { + return errors.Wrap(err, "error removing ignored files from build context") + } return resolveDockerfilePath() }, Run: func(cmd *cobra.Command, args []string) { @@ -91,6 +94,7 @@ func addKanikoOptionsFlags(cmd *cobra.Command) { RootCmd.PersistentFlags().VarP(&opts.Destinations, "destination", "d", "Registry the final image should be pushed to. Set it repeatedly for multiple destinations.") RootCmd.PersistentFlags().StringVarP(&opts.SnapshotMode, "snapshotMode", "", "full", "Change the file attributes inspected during snapshotting") RootCmd.PersistentFlags().VarP(&opts.BuildArgs, "build-arg", "", "This flag allows you to pass in ARG values at build time. Set it repeatedly for multiple values.") + RootCmd.PersistentFlags().VarP(&opts.Ignore, "ignore", "", "Set this flag to ignore files in the build context. Set it repeatedly for multiple values.") RootCmd.PersistentFlags().BoolVarP(&opts.InsecurePush, "insecure", "", false, "Push to insecure registry using plain HTTP") RootCmd.PersistentFlags().BoolVarP(&opts.SkipTLSVerify, "skip-tls-verify", "", false, "Push to insecure registry ignoring TLS verify") RootCmd.PersistentFlags().StringVarP(&opts.TarPath, "tarPath", "", "", "Path to save the image in as a tarball instead of pushing") @@ -182,6 +186,35 @@ func resolveSourceContext() error { return nil } +func removeIgnoredFiles() error { + logrus.Infof("Removing ignored files from build context: %s", opts.Ignore) + for r, i := range opts.Ignore { + opts.Ignore[r] = filepath.Clean(filepath.Join(opts.SrcContext, i)) + } + err := filepath.Walk(opts.SrcContext, func(path string, fi os.FileInfo, _ error) error { + if ignoreFile(path) { + if err := os.RemoveAll(path); err != nil { + logrus.Debugf("error removing %s from buildcontext", path) + } + } + return nil + }) + return err +} + +func ignoreFile(path string) bool { + for _, i := range opts.Ignore { + matched, err := filepath.Match(i, path) + if err != nil { + return false + } + if matched { + return true + } + } + return false +} + func exit(err error) { fmt.Println(err) os.Exit(1) diff --git a/integration/dockerfiles/Dockerfile_test_ignore b/integration/dockerfiles/Dockerfile_test_ignore new file mode 100644 index 000000000..04fdc2701 --- /dev/null +++ b/integration/dockerfiles/Dockerfile_test_ignore @@ -0,0 +1,2 @@ +FROM scratch +COPY . . diff --git a/integration/images.go b/integration/images.go index 464db8cc8..daeeca24b 100644 --- a/integration/images.go +++ b/integration/images.go @@ -54,6 +54,16 @@ var argsMap = map[string][]string{ "Dockerfile_test_multistage": {"file=/foo2"}, } +var filesToIgnore = []string{"context/bar/*", "context/tars/"} + +func ignoreFlags() []string { + var f []string + for _, i := range filesToIgnore { + f = append(f, fmt.Sprintf("--ignore=%s", i)) + } + return f +} + // Arguments to build Dockerfiles with when building with docker var additionalDockerFlagsMap = map[string][]string{ "Dockerfile_test_target": {"--target=second"}, @@ -64,6 +74,7 @@ var additionalKanikoFlagsMap = map[string][]string{ "Dockerfile_test_add": {"--single-snapshot"}, "Dockerfile_test_scratch": {"--single-snapshot"}, "Dockerfile_test_target": {"--target=second"}, + "Dockerfile_test_ignore": ignoreFlags(), } var bucketContextTests = []string{"Dockerfile_test_copy_bucket"} @@ -110,9 +121,10 @@ func FindDockerFiles(dockerfilesPath string) ([]string, error) { // keeps track of which files have been built. type DockerFileBuilder struct { // Holds all available docker files and whether or not they've been built - FilesBuilt map[string]bool - DockerfilesToIgnore map[string]struct{} - TestCacheDockerfiles map[string]struct{} + FilesBuilt map[string]bool + DockerfilesToIgnore map[string]struct{} + TestCacheDockerfiles map[string]struct{} + TestIgnoreDockerfiles map[string]struct{} } // NewDockerFileBuilder will create a DockerFileBuilder initialized with dockerfiles, which @@ -130,6 +142,9 @@ func NewDockerFileBuilder(dockerfiles []string) *DockerFileBuilder { "Dockerfile_test_cache": {}, "Dockerfile_test_cache_install": {}, } + d.TestIgnoreDockerfiles = map[string]struct{}{ + "Dockerfile_test_ignore": {}, + } return &d } @@ -158,11 +173,23 @@ func (d *DockerFileBuilder) BuildImage(imageRepo, gcsBucket, dockerfilesPath, do "."}, additionalFlags...)..., ) + if d.includeDockerIgnore(dockerfile) { + if err := generateDockerIgnore(); err != nil { + return err + } + } + _, err := RunCommandWithoutTest(dockerCmd) if err != nil { return fmt.Errorf("Failed to build image %s with docker command \"%s\": %s", dockerImage, dockerCmd.Args, err) } + if d.includeDockerIgnore(dockerfilesPath) { + if err := deleteDockerIgnore(); err != nil { + return err + } + } + contextFlag := "-c" contextPath := buildContextPath for _, d := range bucketContextTests { @@ -252,3 +279,29 @@ func (d *DockerFileBuilder) buildCachedImages(imageRepo, cacheRepo, dockerfilesP } return nil } + +func (d *DockerFileBuilder) includeDockerIgnore(dockerfile string) bool { + for i := range d.TestIgnoreDockerfiles { + if i == dockerfile { + return true + } + } + return false +} + +func generateDockerIgnore() error { + f, err := os.Create(".dockerignore") + if err != nil { + return err + } + defer f.Close() + contents := strings.Join(filesToIgnore, "\n") + if _, err := f.Write([]byte(contents)); err != nil { + return err + } + return nil +} + +func deleteDockerIgnore() error { + return os.Remove(".dockerignore") +} diff --git a/pkg/config/options.go b/pkg/config/options.go index fc15c1f21..2c9195598 100644 --- a/pkg/config/options.go +++ b/pkg/config/options.go @@ -28,6 +28,7 @@ type KanikoOptions struct { CacheDir string Destinations multiArg BuildArgs multiArg + Ignore multiArg InsecurePush bool SkipTLSVerify bool SingleSnapshot bool