diff --git a/README.md b/README.md index c087c60013..3a18eb6d20 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,7 @@ _If you are interested in contributing to kaniko, see - [Flag `--custom-platform`](#flag---custom-platform) - [Flag `--digest-file`](#flag---digest-file) - [Flag `--dockerfile`](#flag---dockerfile) + - [Flag `--exclude-root-dir-tarball`](#flag---exclude-root-dir-tarball) - [Flag `--force`](#flag---force) - [Flag `--git`](#flag---git) - [Flag `--image-name-with-digest-file`](#flag---image-name-with-digest-file) @@ -891,6 +892,10 @@ the digest to that file, which is picked up by Kubernetes automatically as the Path to the dockerfile to be built. (default "Dockerfile") +#### Flag `--exclude-root-dir-tarball` + +Set this flag to exclude root directory in tar archive. This can enable tools like Flux that use non-GNU tar to extract images created by Kaniko. + #### Flag `--force` Force building outside of a container diff --git a/cmd/executor/cmd/root.go b/cmd/executor/cmd/root.go index 7f0339c5df..f852e07936 100644 --- a/cmd/executor/cmd/root.go +++ b/cmd/executor/cmd/root.go @@ -280,6 +280,7 @@ func addKanikoOptionsFlags() { RootCmd.PersistentFlags().VarP(&opts.IgnorePaths, "ignore-path", "", "Ignore these paths when taking a snapshot. Set it repeatedly for multiple paths.") RootCmd.PersistentFlags().BoolVarP(&opts.ForceBuildMetadata, "force-build-metadata", "", false, "Force add metadata layers to build image") RootCmd.PersistentFlags().BoolVarP(&opts.SkipPushPermissionCheck, "skip-push-permission-check", "", false, "Skip check of the push permission") + RootCmd.PersistentFlags().BoolVarP(&opts.ExcludeRootDirTarball, "exclude-root-dir-tarball", "", false, "Exclude root directory in tarball") // Deprecated flags. RootCmd.PersistentFlags().StringVarP(&opts.SnapshotModeDeprecated, "snapshotMode", "", "", "This flag is deprecated. Please use '--snapshot-mode'.") diff --git a/pkg/config/options.go b/pkg/config/options.go index dbc1e02976..ea4e676c00 100644 --- a/pkg/config/options.go +++ b/pkg/config/options.go @@ -91,6 +91,7 @@ type KanikoOptions struct { ForceBuildMetadata bool InitialFSUnpacked bool SkipPushPermissionCheck bool + ExcludeRootDirTarball bool } type KanikoGitOptions struct { diff --git a/pkg/executor/build.go b/pkg/executor/build.go index 73b2f0df23..277b0fd80c 100644 --- a/pkg/executor/build.go +++ b/pkg/executor/build.go @@ -112,6 +112,7 @@ func newStageBuilder(args *dockerfile.BuildArgs, opts *config.KanikoOptions, sta } l := snapshot.NewLayeredMap(hasher) snapshotter := snapshot.NewSnapshotter(l, config.RootDir) + snapshotter.SetExcludeRootDirTarball(opts.ExcludeRootDirTarball) digest, err := sourceImage.Digest() if err != nil { diff --git a/pkg/snapshot/snapshot.go b/pkg/snapshot/snapshot.go index 2a9244693e..8d5450f988 100644 --- a/pkg/snapshot/snapshot.go +++ b/pkg/snapshot/snapshot.go @@ -39,9 +39,10 @@ var snapshotPathPrefix = "" // Snapshotter holds the root directory from which to take snapshots, and a list of snapshots taken type Snapshotter struct { - l *LayeredMap - directory string - ignorelist []util.IgnoreListEntry + l *LayeredMap + directory string + ignorelist []util.IgnoreListEntry + excludeRootDirTarball bool } // NewSnapshotter creates a new snapshotter rooted at d @@ -114,7 +115,7 @@ func (s *Snapshotter) TakeSnapshot(files []string, shdCheckDelete bool, forceBui t := util.NewTar(f) defer t.Close() - if err := writeToTar(t, filesToAdd, filesToWhiteout); err != nil { + if err := writeToTar(t, filesToAdd, filesToWhiteout, s.excludeRootDirTarball); err != nil { return "", err } return f.Name(), nil @@ -136,12 +137,17 @@ func (s *Snapshotter) TakeSnapshotFS() (string, error) { return "", err } - if err := writeToTar(t, filesToAdd, filesToWhiteOut); err != nil { + if err := writeToTar(t, filesToAdd, filesToWhiteOut, s.excludeRootDirTarball); err != nil { return "", err } return f.Name(), nil } +// SetExcludeRootDirTarball sets the flag to exclude root directory from the tar archive. +func (s *Snapshotter) SetExcludeRootDirTarball(e bool) { + s.excludeRootDirTarball = e +} + func (s *Snapshotter) getSnashotPathPrefix() string { if snapshotPathPrefix == "" { return config.KanikoDir @@ -230,7 +236,7 @@ func removeObsoleteWhiteouts(deletedFiles map[string]struct{}) (filesToWhiteout return filesToWhiteout } -func writeToTar(t util.Tar, files, whiteouts []string) error { +func writeToTar(t util.Tar, files, whiteouts []string, excludeRootDirTarball bool) error { timer := timing.Start("Writing tar file") defer timing.DefaultRun.Stop(timer) @@ -246,7 +252,7 @@ func writeToTar(t util.Tar, files, whiteouts []string) error { continue } - if err := addParentDirectories(t, addedPaths, path); err != nil { + if err := addParentDirectories(t, addedPaths, path, excludeRootDirTarball); err != nil { return err } if err := t.Whiteout(path); err != nil { @@ -255,12 +261,15 @@ func writeToTar(t util.Tar, files, whiteouts []string) error { } for _, path := range files { - if err := addParentDirectories(t, addedPaths, path); err != nil { + if err := addParentDirectories(t, addedPaths, path, excludeRootDirTarball); err != nil { return err } if _, pathAdded := addedPaths[path]; pathAdded { continue } + if path == config.RootDir && excludeRootDirTarball { + continue + } if err := t.AddFileToTar(path); err != nil { return err } @@ -284,11 +293,14 @@ func parentPathIncludesNonDirectory(path string) (bool, error) { return false, nil } -func addParentDirectories(t util.Tar, addedPaths map[string]bool, path string) error { +func addParentDirectories(t util.Tar, addedPaths map[string]bool, path string, excludeRootDirTarball bool) error { for _, parentPath := range util.ParentDirectories(path) { if _, pathAdded := addedPaths[parentPath]; pathAdded { continue } + if parentPath == config.RootDir && excludeRootDirTarball { + continue + } if err := t.AddFileToTar(parentPath); err != nil { return err }