github.com/demonoid81/containerd@v1.3.4/cmd/ctr/commands/run/run_unix.go (about)

     1  // +build !windows
     2  
     3  /*
     4     Copyright The containerd Authors.
     5  
     6     Licensed under the Apache License, Version 2.0 (the "License");
     7     you may not use this file except in compliance with the License.
     8     You may obtain a copy of the License at
     9  
    10         http://www.apache.org/licenses/LICENSE-2.0
    11  
    12     Unless required by applicable law or agreed to in writing, software
    13     distributed under the License is distributed on an "AS IS" BASIS,
    14     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15     See the License for the specific language governing permissions and
    16     limitations under the License.
    17  */
    18  
    19  package run
    20  
    21  import (
    22  	gocontext "context"
    23  	"path/filepath"
    24  	"strings"
    25  
    26  	"github.com/containerd/containerd"
    27  	"github.com/containerd/containerd/cmd/ctr/commands"
    28  	"github.com/containerd/containerd/contrib/nvidia"
    29  	"github.com/containerd/containerd/contrib/seccomp"
    30  	"github.com/containerd/containerd/oci"
    31  	"github.com/containerd/containerd/platforms"
    32  	"github.com/opencontainers/runtime-spec/specs-go"
    33  	"github.com/pkg/errors"
    34  	"github.com/urfave/cli"
    35  )
    36  
    37  var platformRunFlags []cli.Flag
    38  
    39  // NewContainer creates a new container
    40  func NewContainer(ctx gocontext.Context, client *containerd.Client, context *cli.Context) (containerd.Container, error) {
    41  	var (
    42  		id     string
    43  		config = context.IsSet("config")
    44  	)
    45  	if config {
    46  		id = context.Args().First()
    47  	} else {
    48  		id = context.Args().Get(1)
    49  	}
    50  
    51  	var (
    52  		opts  []oci.SpecOpts
    53  		cOpts []containerd.NewContainerOpts
    54  		spec  containerd.NewContainerOpts
    55  	)
    56  
    57  	cOpts = append(cOpts, containerd.WithContainerLabels(commands.LabelArgs(context.StringSlice("label"))))
    58  	if config {
    59  		opts = append(opts, oci.WithSpecFromFile(context.String("config")))
    60  	} else {
    61  		var (
    62  			ref = context.Args().First()
    63  			//for container's id is Args[1]
    64  			args = context.Args()[2:]
    65  		)
    66  		opts = append(opts, oci.WithDefaultSpec(), oci.WithDefaultUnixDevices)
    67  		if ef := context.String("env-file"); ef != "" {
    68  			opts = append(opts, oci.WithEnvFile(ef))
    69  		}
    70  		opts = append(opts, oci.WithEnv(context.StringSlice("env")))
    71  		opts = append(opts, withMounts(context))
    72  
    73  		if context.Bool("rootfs") {
    74  			rootfs, err := filepath.Abs(ref)
    75  			if err != nil {
    76  				return nil, err
    77  			}
    78  			opts = append(opts, oci.WithRootFSPath(rootfs))
    79  		} else {
    80  			snapshotter := context.String("snapshotter")
    81  			var image containerd.Image
    82  			i, err := client.ImageService().Get(ctx, ref)
    83  			if err != nil {
    84  				return nil, err
    85  			}
    86  			if ps := context.String("platform"); ps != "" {
    87  				platform, err := platforms.Parse(ps)
    88  				if err != nil {
    89  					return nil, err
    90  				}
    91  				image = containerd.NewImageWithPlatform(client, i, platforms.Only(platform))
    92  			} else {
    93  				image = containerd.NewImage(client, i)
    94  			}
    95  
    96  			unpacked, err := image.IsUnpacked(ctx, snapshotter)
    97  			if err != nil {
    98  				return nil, err
    99  			}
   100  			if !unpacked {
   101  				if err := image.Unpack(ctx, snapshotter); err != nil {
   102  					return nil, err
   103  				}
   104  			}
   105  			opts = append(opts, oci.WithImageConfig(image))
   106  			cOpts = append(cOpts,
   107  				containerd.WithImage(image),
   108  				containerd.WithSnapshotter(snapshotter),
   109  				// Even when "readonly" is set, we don't use KindView snapshot here. (#1495)
   110  				// We pass writable snapshot to the OCI runtime, and the runtime remounts it as read-only,
   111  				// after creating some mount points on demand.
   112  				containerd.WithNewSnapshot(id, image),
   113  				containerd.WithImageStopSignal(image, "SIGTERM"))
   114  		}
   115  		if context.Bool("readonly") {
   116  			opts = append(opts, oci.WithRootFSReadonly())
   117  		}
   118  		if len(args) > 0 {
   119  			opts = append(opts, oci.WithProcessArgs(args...))
   120  		}
   121  		if cwd := context.String("cwd"); cwd != "" {
   122  			opts = append(opts, oci.WithProcessCwd(cwd))
   123  		}
   124  		if context.Bool("tty") {
   125  			opts = append(opts, oci.WithTTY)
   126  		}
   127  		if context.Bool("privileged") {
   128  			opts = append(opts, oci.WithPrivileged)
   129  		}
   130  		if context.Bool("net-host") {
   131  			opts = append(opts, oci.WithHostNamespace(specs.NetworkNamespace), oci.WithHostHostsFile, oci.WithHostResolvconf)
   132  		}
   133  		if context.Bool("seccomp") {
   134  			opts = append(opts, seccomp.WithDefaultProfile())
   135  		}
   136  
   137  		joinNs := context.StringSlice("with-ns")
   138  		for _, ns := range joinNs {
   139  			parts := strings.Split(ns, ":")
   140  			if len(parts) != 2 {
   141  				return nil, errors.New("joining a Linux namespace using --with-ns requires the format 'nstype:path'")
   142  			}
   143  			if !validNamespace(parts[0]) {
   144  				return nil, errors.New("the Linux namespace type specified in --with-ns is not valid: " + parts[0])
   145  			}
   146  			opts = append(opts, oci.WithLinuxNamespace(specs.LinuxNamespace{
   147  				Type: specs.LinuxNamespaceType(parts[0]),
   148  				Path: parts[1],
   149  			}))
   150  		}
   151  		if context.IsSet("gpus") {
   152  			opts = append(opts, nvidia.WithGPUs(nvidia.WithDevices(context.Int("gpus")), nvidia.WithAllCapabilities))
   153  		}
   154  		if context.IsSet("allow-new-privs") {
   155  			opts = append(opts, oci.WithNewPrivileges)
   156  		}
   157  		if context.IsSet("cgroup") {
   158  			// NOTE: can be set to "" explicitly for disabling cgroup.
   159  			opts = append(opts, oci.WithCgroup(context.String("cgroup")))
   160  		}
   161  		limit := context.Uint64("memory-limit")
   162  		if limit != 0 {
   163  			opts = append(opts, oci.WithMemoryLimit(limit))
   164  		}
   165  		for _, dev := range context.StringSlice("device") {
   166  			opts = append(opts, oci.WithLinuxDevice(dev, "rwm"))
   167  		}
   168  	}
   169  
   170  	cOpts = append(cOpts, containerd.WithRuntime(context.String("runtime"), nil))
   171  
   172  	opts = append(opts, oci.WithAnnotations(commands.LabelArgs(context.StringSlice("label"))))
   173  	var s specs.Spec
   174  	spec = containerd.WithSpec(&s, opts...)
   175  
   176  	cOpts = append(cOpts, spec)
   177  
   178  	// oci.WithImageConfig (WithUsername, WithUserID) depends on access to rootfs for resolving via
   179  	// the /etc/{passwd,group} files. So cOpts needs to have precedence over opts.
   180  	return client.NewContainer(ctx, id, cOpts...)
   181  }
   182  
   183  func getNewTaskOpts(context *cli.Context) []containerd.NewTaskOpts {
   184  	if context.Bool("no-pivot") {
   185  		return []containerd.NewTaskOpts{containerd.WithNoPivotRoot}
   186  	}
   187  	return nil
   188  }
   189  
   190  func validNamespace(ns string) bool {
   191  	linuxNs := specs.LinuxNamespaceType(ns)
   192  	switch linuxNs {
   193  	case specs.PIDNamespace,
   194  		specs.NetworkNamespace,
   195  		specs.UTSNamespace,
   196  		specs.MountNamespace,
   197  		specs.UserNamespace,
   198  		specs.IPCNamespace,
   199  		specs.CgroupNamespace:
   200  		return true
   201  	default:
   202  		return false
   203  	}
   204  }