github.com/containerd/nerdctl@v1.7.7/cmd/nerdctl/builder_build.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package main
    18  
    19  import (
    20  	"errors"
    21  	"fmt"
    22  	"os"
    23  	"strings"
    24  
    25  	"github.com/containerd/nerdctl/pkg/api/types"
    26  	"github.com/containerd/nerdctl/pkg/buildkitutil"
    27  	"github.com/containerd/nerdctl/pkg/clientutil"
    28  	"github.com/containerd/nerdctl/pkg/cmd/builder"
    29  	"github.com/containerd/nerdctl/pkg/defaults"
    30  	"github.com/containerd/nerdctl/pkg/strutil"
    31  
    32  	"github.com/spf13/cobra"
    33  )
    34  
    35  func newBuildCommand() *cobra.Command {
    36  	var buildCommand = &cobra.Command{
    37  		Use:   "build [flags] PATH",
    38  		Short: "Build an image from a Dockerfile. Needs buildkitd to be running.",
    39  		Long: `Build an image from a Dockerfile. Needs buildkitd to be running.
    40  If Dockerfile is not present and -f is not specified, it will look for Containerfile and build with it. `,
    41  		RunE:          buildAction,
    42  		SilenceUsage:  true,
    43  		SilenceErrors: true,
    44  	}
    45  	AddStringFlag(buildCommand, "buildkit-host", nil, defaults.BuildKitHost(), "BUILDKIT_HOST", "BuildKit address")
    46  	buildCommand.Flags().StringArrayP("tag", "t", nil, "Name and optionally a tag in the 'name:tag' format")
    47  	buildCommand.Flags().StringP("file", "f", "", "Name of the Dockerfile")
    48  	buildCommand.Flags().String("target", "", "Set the target build stage to build")
    49  	buildCommand.Flags().StringArray("build-arg", nil, "Set build-time variables")
    50  	buildCommand.Flags().Bool("no-cache", false, "Do not use cache when building the image")
    51  	buildCommand.Flags().StringP("output", "o", "", "Output destination (format: type=local,dest=path)")
    52  	buildCommand.Flags().String("progress", "auto", "Set type of progress output (auto, plain, tty). Use plain to show container output")
    53  	buildCommand.Flags().StringArray("secret", nil, "Secret file to expose to the build: id=mysecret,src=/local/secret")
    54  	buildCommand.Flags().StringArray("allow", nil, "Allow extra privileged entitlement, e.g. network.host, security.insecure")
    55  	buildCommand.RegisterFlagCompletionFunc("allow", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    56  		return []string{"network.host", "security.insecure"}, cobra.ShellCompDirectiveNoFileComp
    57  	})
    58  	buildCommand.Flags().StringArray("ssh", nil, "SSH agent socket or keys to expose to the build (format: default|<id>[=<socket>|<key>[,<key>]])")
    59  	buildCommand.Flags().BoolP("quiet", "q", false, "Suppress the build output and print image ID on success")
    60  	buildCommand.Flags().StringArray("cache-from", nil, "External cache sources (eg. user/app:cache, type=local,src=path/to/dir)")
    61  	buildCommand.Flags().StringArray("cache-to", nil, "Cache export destinations (eg. user/app:cache, type=local,dest=path/to/dir)")
    62  	buildCommand.Flags().Bool("rm", true, "Remove intermediate containers after a successful build")
    63  	buildCommand.Flags().String("network", "default", "Set type of network for build (format:network=default|none|host)")
    64  	buildCommand.RegisterFlagCompletionFunc("network", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
    65  		return []string{"default", "host", "none"}, cobra.ShellCompDirectiveNoFileComp
    66  	})
    67  	// #region platform flags
    68  	// platform is defined as StringSlice, not StringArray, to allow specifying "--platform=amd64,arm64"
    69  	buildCommand.Flags().StringSlice("platform", []string{}, "Set target platform for build (e.g., \"amd64\", \"arm64\")")
    70  	buildCommand.RegisterFlagCompletionFunc("platform", shellCompletePlatforms)
    71  	// #endregion
    72  
    73  	buildCommand.Flags().String("iidfile", "", "Write the image ID to the file")
    74  	buildCommand.Flags().StringArray("label", nil, "Set metadata for an image")
    75  
    76  	return buildCommand
    77  }
    78  
    79  func processBuildCommandFlag(cmd *cobra.Command, args []string) (types.BuilderBuildOptions, error) {
    80  	globalOptions, err := processRootCmdFlags(cmd)
    81  	if err != nil {
    82  		return types.BuilderBuildOptions{}, err
    83  	}
    84  	buildKitHost, err := getBuildkitHost(cmd, globalOptions.Namespace)
    85  	if err != nil {
    86  		return types.BuilderBuildOptions{}, err
    87  	}
    88  	platform, err := cmd.Flags().GetStringSlice("platform")
    89  	if err != nil {
    90  		return types.BuilderBuildOptions{}, err
    91  	}
    92  	platform = strutil.DedupeStrSlice(platform)
    93  	if len(args) < 1 {
    94  		return types.BuilderBuildOptions{}, errors.New("context needs to be specified")
    95  	}
    96  	buildContext := args[0]
    97  	if buildContext == "-" || strings.Contains(buildContext, "://") {
    98  		return types.BuilderBuildOptions{}, fmt.Errorf("unsupported build context: %q", buildContext)
    99  	}
   100  	output, err := cmd.Flags().GetString("output")
   101  	if err != nil {
   102  		return types.BuilderBuildOptions{}, err
   103  	}
   104  	tagValue, err := cmd.Flags().GetStringArray("tag")
   105  	if err != nil {
   106  		return types.BuilderBuildOptions{}, err
   107  	}
   108  	progress, err := cmd.Flags().GetString("progress")
   109  	if err != nil {
   110  		return types.BuilderBuildOptions{}, err
   111  	}
   112  	filename, err := cmd.Flags().GetString("file")
   113  	if err != nil {
   114  		return types.BuilderBuildOptions{}, err
   115  	}
   116  	target, err := cmd.Flags().GetString("target")
   117  	if err != nil {
   118  		return types.BuilderBuildOptions{}, err
   119  	}
   120  	buildArgs, err := cmd.Flags().GetStringArray("build-arg")
   121  	if err != nil {
   122  		return types.BuilderBuildOptions{}, err
   123  	}
   124  	label, err := cmd.Flags().GetStringArray("label")
   125  	if err != nil {
   126  		return types.BuilderBuildOptions{}, err
   127  	}
   128  	noCache, err := cmd.Flags().GetBool("no-cache")
   129  	if err != nil {
   130  		return types.BuilderBuildOptions{}, err
   131  	}
   132  	secret, err := cmd.Flags().GetStringArray("secret")
   133  	if err != nil {
   134  		return types.BuilderBuildOptions{}, err
   135  	}
   136  	allow, err := cmd.Flags().GetStringArray("allow")
   137  	if err != nil {
   138  		return types.BuilderBuildOptions{}, err
   139  	}
   140  	ssh, err := cmd.Flags().GetStringArray("ssh")
   141  	if err != nil {
   142  		return types.BuilderBuildOptions{}, err
   143  	}
   144  	cacheFrom, err := cmd.Flags().GetStringArray("cache-from")
   145  	if err != nil {
   146  		return types.BuilderBuildOptions{}, err
   147  	}
   148  	cacheTo, err := cmd.Flags().GetStringArray("cache-to")
   149  	if err != nil {
   150  		return types.BuilderBuildOptions{}, err
   151  	}
   152  	rm, err := cmd.Flags().GetBool("rm")
   153  	if err != nil {
   154  		return types.BuilderBuildOptions{}, err
   155  	}
   156  	iidfile, err := cmd.Flags().GetString("iidfile")
   157  	if err != nil {
   158  		return types.BuilderBuildOptions{}, err
   159  	}
   160  	quiet, err := cmd.Flags().GetBool("quiet")
   161  	if err != nil {
   162  		return types.BuilderBuildOptions{}, err
   163  	}
   164  	network, err := cmd.Flags().GetString("network")
   165  	if err != nil {
   166  		return types.BuilderBuildOptions{}, err
   167  	}
   168  	return types.BuilderBuildOptions{
   169  		GOptions:     globalOptions,
   170  		BuildKitHost: buildKitHost,
   171  		BuildContext: buildContext,
   172  		Output:       output,
   173  		Tag:          tagValue,
   174  		Progress:     progress,
   175  		File:         filename,
   176  		Target:       target,
   177  		BuildArgs:    buildArgs,
   178  		Label:        label,
   179  		NoCache:      noCache,
   180  		Secret:       secret,
   181  		Allow:        allow,
   182  		SSH:          ssh,
   183  		CacheFrom:    cacheFrom,
   184  		CacheTo:      cacheTo,
   185  		Rm:           rm,
   186  		IidFile:      iidfile,
   187  		Quiet:        quiet,
   188  		Platform:     platform,
   189  		Stdout:       cmd.OutOrStdout(),
   190  		Stderr:       cmd.OutOrStderr(),
   191  		Stdin:        cmd.InOrStdin(),
   192  		NetworkMode:  network,
   193  	}, nil
   194  }
   195  
   196  func getBuildkitHost(cmd *cobra.Command, namespace string) (string, error) {
   197  	if cmd.Flags().Changed("buildkit-host") || os.Getenv("BUILDKIT_HOST") != "" {
   198  		// If address is explicitly specified, use it.
   199  		buildkitHost, err := cmd.Flags().GetString("buildkit-host")
   200  		if err != nil {
   201  			return "", err
   202  		}
   203  		if err := buildkitutil.PingBKDaemon(buildkitHost); err != nil {
   204  			return "", err
   205  		}
   206  		return buildkitHost, nil
   207  	}
   208  	return buildkitutil.GetBuildkitHost(namespace)
   209  }
   210  
   211  func buildAction(cmd *cobra.Command, args []string) error {
   212  	options, err := processBuildCommandFlag(cmd, args)
   213  	if err != nil {
   214  		return err
   215  	}
   216  
   217  	client, ctx, cancel, err := clientutil.NewClient(cmd.Context(), options.GOptions.Namespace, options.GOptions.Address)
   218  	if err != nil {
   219  		return err
   220  	}
   221  	defer cancel()
   222  
   223  	return builder.Build(ctx, client, options)
   224  }