github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/spec.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 9 "github.com/opencontainers/runc/libcontainer/configs" 10 "github.com/opencontainers/runc/libcontainer/specconv" 11 "github.com/opencontainers/runtime-spec/specs-go" 12 "github.com/urfave/cli" 13 ) 14 15 var specCommand = cli.Command{ 16 Name: "spec", 17 Usage: "create a new specification file", 18 ArgsUsage: "", 19 Description: `The spec command creates the new specification file named "` + specConfig + `" for 20 the bundle. 21 22 The spec generated is just a starter file. Editing of the spec is required to 23 achieve desired results. For example, the newly generated spec includes an args 24 parameter that is initially set to call the "sh" command when the container is 25 started. Calling "sh" may work for an ubuntu container or busybox, but will not 26 work for containers that do not include the "sh" program. 27 28 EXAMPLE: 29 To run docker's hello-world container one needs to set the args parameter 30 in the spec to call hello. This can be done using the sed command or a text 31 editor. The following commands create a bundle for hello-world, change the 32 default args parameter in the spec from "sh" to "/hello", then run the hello 33 command in a new hello-world container named container1: 34 35 mkdir hello 36 cd hello 37 docker pull hello-world 38 docker export $(docker create hello-world) > hello-world.tar 39 mkdir rootfs 40 tar -C rootfs -xf hello-world.tar 41 runc spec 42 sed -i 's;"sh";"/hello";' ` + specConfig + ` 43 runc run container1 44 45 In the run command above, "container1" is the name for the instance of the 46 container that you are starting. The name you provide for the container instance 47 must be unique on your host. 48 49 An alternative for generating a customized spec config is to use "oci-runtime-tool", the 50 sub-command "oci-runtime-tool generate" has lots of options that can be used to do any 51 customizations as you want, see runtime-tools (https://github.com/opencontainers/runtime-tools) 52 to get more information. 53 54 When starting a container through runc, runc needs root privilege. If not 55 already running as root, you can use sudo to give runc root privilege. For 56 example: "sudo runc start container1" will give runc root privilege to start the 57 container on your host. 58 59 Alternatively, you can start a rootless container, which has the ability to run 60 without root privileges. For this to work, the specification file needs to be 61 adjusted accordingly. You can pass the parameter --rootless to this command to 62 generate a proper rootless spec file. 63 64 Note that --rootless is not needed when you execute runc as the root in a user namespace 65 created by an unprivileged user. 66 `, 67 Flags: []cli.Flag{ 68 cli.StringFlag{ 69 Name: "bundle, b", 70 Value: "", 71 Usage: "path to the root of the bundle directory", 72 }, 73 cli.BoolFlag{ 74 Name: "rootless", 75 Usage: "generate a configuration for a rootless container", 76 }, 77 }, 78 Action: func(context *cli.Context) error { 79 if err := checkArgs(context, 0, exactArgs); err != nil { 80 return err 81 } 82 spec := specconv.Example() 83 84 rootless := context.Bool("rootless") 85 if rootless { 86 specconv.ToRootless(spec) 87 } 88 89 checkNoFile := func(name string) error { 90 _, err := os.Stat(name) 91 if err == nil { 92 return fmt.Errorf("File %s exists. Remove it first", name) 93 } 94 if !os.IsNotExist(err) { 95 return err 96 } 97 return nil 98 } 99 bundle := context.String("bundle") 100 if bundle != "" { 101 if err := os.Chdir(bundle); err != nil { 102 return err 103 } 104 } 105 if err := checkNoFile(specConfig); err != nil { 106 return err 107 } 108 data, err := json.MarshalIndent(spec, "", "\t") 109 if err != nil { 110 return err 111 } 112 return os.WriteFile(specConfig, data, 0o666) 113 }, 114 } 115 116 // loadSpec loads the specification from the provided path. 117 func loadSpec(cPath string) (spec *specs.Spec, err error) { 118 cf, err := os.Open(cPath) 119 if err != nil { 120 if os.IsNotExist(err) { 121 return nil, fmt.Errorf("JSON specification file %s not found", cPath) 122 } 123 return nil, err 124 } 125 defer cf.Close() 126 127 if err = json.NewDecoder(cf).Decode(&spec); err != nil { 128 return nil, err 129 } 130 if spec == nil { 131 return nil, errors.New("config cannot be null") 132 } 133 return spec, validateProcessSpec(spec.Process) 134 } 135 136 func createLibContainerRlimit(rlimit specs.POSIXRlimit) (configs.Rlimit, error) { 137 rl, err := strToRlimit(rlimit.Type) 138 if err != nil { 139 return configs.Rlimit{}, err 140 } 141 return configs.Rlimit{ 142 Type: rl, 143 Hard: rlimit.Hard, 144 Soft: rlimit.Soft, 145 }, nil 146 }