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 }