github.com/zhuohuang-hust/src-cbuild@v0.0.0-20230105071821-c7aab3e7c840/mergeCode/runc/spec.go (about)

     1  // +build linux
     2  
     3  package main
     4  
     5  import (
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"runtime"
    11  
    12  	"github.com/opencontainers/runc/libcontainer/configs"
    13  	"github.com/opencontainers/runtime-spec/specs-go"
    14  	"github.com/urfave/cli"
    15  )
    16  
    17  var specCommand = cli.Command{
    18  	Name:      "spec",
    19  	Usage:     "create a new specification file",
    20  	ArgsUsage: "",
    21  	Description: `The spec command creates the new specification file named "` + specConfig + `" for
    22  the bundle.
    23  
    24  The spec generated is just a starter file. Editing of the spec is required to
    25  achieve desired results. For example, the newly generated spec includes an args
    26  parameter that is initially set to call the "sh" command when the container is
    27  started. Calling "sh" may work for an ubuntu container or busybox, but will not
    28  work for containers that do not include the "sh" program.
    29  
    30  EXAMPLE:
    31    To run docker's hello-world container one needs to set the args parameter
    32  in the spec to call hello. This can be done using the sed command or a text
    33  editor. The following commands create a bundle for hello-world, change the
    34  default args parameter in the spec from "sh" to "/hello", then run the hello
    35  command in a new hello-world container named container1:
    36  
    37      mkdir hello
    38      cd hello
    39      docker pull hello-world
    40      docker export $(docker create hello-world) > hello-world.tar
    41      mkdir rootfs
    42      tar -C rootfs -xf hello-world.tar
    43      runc spec
    44      sed -i 's;"sh";"/hello";' ` + specConfig + `
    45      runc run container1
    46  
    47  In the run command above, "container1" is the name for the instance of the
    48  container that you are starting. The name you provide for the container instance
    49  must be unique on your host.
    50  
    51  An alternative for generating a customized spec config is to use "ocitools", the
    52  sub-command "ocitools generate" has lots of options that can be used to do any
    53  customizations as you want, see [ocitools](https://github.com/opencontainers/ocitools)
    54  to get more information.
    55  
    56  When starting a container through runc, runc needs root privilege. If not
    57  already running as root, you can use sudo to give runc root privilege. For
    58  example: "sudo runc start container1" will give runc root privilege to start the
    59  container on your host.`,
    60  	Flags: []cli.Flag{
    61  		cli.StringFlag{
    62  			Name:  "bundle, b",
    63  			Value: "",
    64  			Usage: "path to the root of the bundle directory",
    65  		},
    66  	},
    67  	Action: func(context *cli.Context) error {
    68  		spec := specs.Spec{
    69  			Version: specs.Version,
    70  			Platform: specs.Platform{
    71  				OS:   runtime.GOOS,
    72  				Arch: runtime.GOARCH,
    73  			},
    74  			Root: specs.Root{
    75  				Path:     "rootfs",
    76  				Readonly: true,
    77  			},
    78  			Process: specs.Process{
    79  				Terminal: true,
    80  				User:     specs.User{},
    81  				Args: []string{
    82  					"sh",
    83  				},
    84  				Env: []string{
    85  					"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
    86  					"TERM=xterm",
    87  				},
    88  				Cwd:             "/",
    89  				NoNewPrivileges: true,
    90  				Capabilities: []string{
    91  					"CAP_AUDIT_WRITE",
    92  					"CAP_KILL",
    93  					"CAP_NET_BIND_SERVICE",
    94  				},
    95  				Rlimits: []specs.Rlimit{
    96  					{
    97  						Type: "RLIMIT_NOFILE",
    98  						Hard: uint64(1024),
    99  						Soft: uint64(1024),
   100  					},
   101  				},
   102  			},
   103  			Hostname: "runc",
   104  			Mounts: []specs.Mount{
   105  				{
   106  					Destination: "/proc",
   107  					Type:        "proc",
   108  					Source:      "proc",
   109  					Options:     nil,
   110  				},
   111  				{
   112  					Destination: "/dev",
   113  					Type:        "tmpfs",
   114  					Source:      "tmpfs",
   115  					Options:     []string{"nosuid", "strictatime", "mode=755", "size=65536k"},
   116  				},
   117  				{
   118  					Destination: "/dev/pts",
   119  					Type:        "devpts",
   120  					Source:      "devpts",
   121  					Options:     []string{"nosuid", "noexec", "newinstance", "ptmxmode=0666", "mode=0620", "gid=5"},
   122  				},
   123  				{
   124  					Destination: "/dev/shm",
   125  					Type:        "tmpfs",
   126  					Source:      "shm",
   127  					Options:     []string{"nosuid", "noexec", "nodev", "mode=1777", "size=65536k"},
   128  				},
   129  				{
   130  					Destination: "/dev/mqueue",
   131  					Type:        "mqueue",
   132  					Source:      "mqueue",
   133  					Options:     []string{"nosuid", "noexec", "nodev"},
   134  				},
   135  				{
   136  					Destination: "/sys",
   137  					Type:        "sysfs",
   138  					Source:      "sysfs",
   139  					Options:     []string{"nosuid", "noexec", "nodev", "ro"},
   140  				},
   141  				{
   142  					Destination: "/sys/fs/cgroup",
   143  					Type:        "cgroup",
   144  					Source:      "cgroup",
   145  					Options:     []string{"nosuid", "noexec", "nodev", "relatime", "ro"},
   146  				},
   147  			},
   148  			Linux: &specs.Linux{
   149  				MaskedPaths: []string{
   150  					"/proc/kcore",
   151  					"/proc/latency_stats",
   152  					"/proc/timer_list",
   153  					"/proc/timer_stats",
   154  					"/proc/sched_debug",
   155  					"/sys/firmware",
   156  				},
   157  				ReadonlyPaths: []string{
   158  					"/proc/asound",
   159  					"/proc/bus",
   160  					"/proc/fs",
   161  					"/proc/irq",
   162  					"/proc/sys",
   163  					"/proc/sysrq-trigger",
   164  				},
   165  				Resources: &specs.Resources{
   166  					Devices: []specs.DeviceCgroup{
   167  						{
   168  							Allow:  false,
   169  							Access: sPtr("rwm"),
   170  						},
   171  					},
   172  				},
   173  				Namespaces: []specs.Namespace{
   174  					{
   175  						Type: "pid",
   176  					},
   177  					{
   178  						Type: "network",
   179  					},
   180  					{
   181  						Type: "ipc",
   182  					},
   183  					{
   184  						Type: "uts",
   185  					},
   186  					{
   187  						Type: "mount",
   188  					},
   189  				},
   190  			},
   191  		}
   192  
   193  		checkNoFile := func(name string) error {
   194  			_, err := os.Stat(name)
   195  			if err == nil {
   196  				return fmt.Errorf("File %s exists. Remove it first", name)
   197  			}
   198  			if !os.IsNotExist(err) {
   199  				return err
   200  			}
   201  			return nil
   202  		}
   203  		bundle := context.String("bundle")
   204  		if bundle != "" {
   205  			if err := os.Chdir(bundle); err != nil {
   206  				return err
   207  			}
   208  		}
   209  		if err := checkNoFile(specConfig); err != nil {
   210  			return err
   211  		}
   212  		data, err := json.MarshalIndent(&spec, "", "\t")
   213  		if err != nil {
   214  			return err
   215  		}
   216  		if err := ioutil.WriteFile(specConfig, data, 0666); err != nil {
   217  			return err
   218  		}
   219  		return nil
   220  	},
   221  }
   222  
   223  func sPtr(s string) *string      { return &s }
   224  func rPtr(r rune) *rune          { return &r }
   225  func iPtr(i int64) *int64        { return &i }
   226  func u32Ptr(i int64) *uint32     { u := uint32(i); return &u }
   227  func fmPtr(i int64) *os.FileMode { fm := os.FileMode(i); return &fm }
   228  
   229  // loadSpec loads the specification from the provided path.
   230  func loadSpec(cPath string) (spec *specs.Spec, err error) {
   231  	cf, err := os.Open(cPath)
   232  	if err != nil {
   233  		if os.IsNotExist(err) {
   234  			return nil, fmt.Errorf("JSON specification file %s not found", cPath)
   235  		}
   236  		return nil, err
   237  	}
   238  	defer cf.Close()
   239  
   240  	if err = json.NewDecoder(cf).Decode(&spec); err != nil {
   241  		return nil, err
   242  	}
   243  	if err = validatePlatform(&spec.Platform); err != nil {
   244  		return nil, err
   245  	}
   246  	return spec, validateProcessSpec(&spec.Process)
   247  }
   248  
   249  func createLibContainerRlimit(rlimit specs.Rlimit) (configs.Rlimit, error) {
   250  	rl, err := strToRlimit(rlimit.Type)
   251  	if err != nil {
   252  		return configs.Rlimit{}, err
   253  	}
   254  	return configs.Rlimit{
   255  		Type: rl,
   256  		Hard: uint64(rlimit.Hard),
   257  		Soft: uint64(rlimit.Soft),
   258  	}, nil
   259  }
   260  
   261  func validatePlatform(platform *specs.Platform) error {
   262  	if platform.OS != runtime.GOOS {
   263  		return fmt.Errorf("target os %s mismatch with current os %s", platform.OS, runtime.GOOS)
   264  	}
   265  	if platform.Arch != runtime.GOARCH {
   266  		return fmt.Errorf("target arch %s mismatch with current arch %s", platform.Arch, runtime.GOARCH)
   267  	}
   268  	return nil
   269  }