mirror of
https://github.com/opencontainers/runc.git
synced 2025-09-27 03:46:19 +08:00

This enables the support for the rootless container mode. There are many restrictions on what rootless containers can do, so many different runC commands have been disabled: * runc checkpoint * runc events * runc pause * runc ps * runc restore * runc resume * runc update The following commands work: * runc create * runc delete * runc exec * runc kill * runc list * runc run * runc spec * runc state In addition, any specification options that imply joining cgroups have also been disabled. This is due to support for unprivileged subtree management not being available from Linux upstream. Signed-off-by: Aleksa Sarai <asarai@suse.de>
147 lines
4.2 KiB
Go
147 lines
4.2 KiB
Go
// +build linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/opencontainers/runc/libcontainer/configs"
|
|
"github.com/opencontainers/runc/libcontainer/specconv"
|
|
"github.com/opencontainers/runtime-spec/specs-go"
|
|
"github.com/urfave/cli"
|
|
)
|
|
|
|
var specCommand = cli.Command{
|
|
Name: "spec",
|
|
Usage: "create a new specification file",
|
|
ArgsUsage: "",
|
|
Description: `The spec command creates the new specification file named "` + specConfig + `" for
|
|
the bundle.
|
|
|
|
The spec generated is just a starter file. Editing of the spec is required to
|
|
achieve desired results. For example, the newly generated spec includes an args
|
|
parameter that is initially set to call the "sh" command when the container is
|
|
started. Calling "sh" may work for an ubuntu container or busybox, but will not
|
|
work for containers that do not include the "sh" program.
|
|
|
|
EXAMPLE:
|
|
To run docker's hello-world container one needs to set the args parameter
|
|
in the spec to call hello. This can be done using the sed command or a text
|
|
editor. The following commands create a bundle for hello-world, change the
|
|
default args parameter in the spec from "sh" to "/hello", then run the hello
|
|
command in a new hello-world container named container1:
|
|
|
|
mkdir hello
|
|
cd hello
|
|
docker pull hello-world
|
|
docker export $(docker create hello-world) > hello-world.tar
|
|
mkdir rootfs
|
|
tar -C rootfs -xf hello-world.tar
|
|
runc spec
|
|
sed -i 's;"sh";"/hello";' ` + specConfig + `
|
|
runc run container1
|
|
|
|
In the run command above, "container1" is the name for the instance of the
|
|
container that you are starting. The name you provide for the container instance
|
|
must be unique on your host.
|
|
|
|
An alternative for generating a customized spec config is to use "oci-runtime-tool", the
|
|
sub-command "oci-runtime-tool generate" has lots of options that can be used to do any
|
|
customizations as you want, see [runtime-tools](https://github.com/opencontainers/runtime-tools)
|
|
to get more information.
|
|
|
|
When starting a container through runc, runc needs root privilege. If not
|
|
already running as root, you can use sudo to give runc root privilege. For
|
|
example: "sudo runc start container1" will give runc root privilege to start the
|
|
container on your host.`,
|
|
Flags: []cli.Flag{
|
|
cli.StringFlag{
|
|
Name: "bundle, b",
|
|
Value: "",
|
|
Usage: "path to the root of the bundle directory",
|
|
},
|
|
},
|
|
Action: func(context *cli.Context) error {
|
|
if err := checkArgs(context, 0, exactArgs); err != nil {
|
|
return err
|
|
}
|
|
spec := specconv.ExampleSpec()
|
|
|
|
checkNoFile := func(name string) error {
|
|
_, err := os.Stat(name)
|
|
if err == nil {
|
|
return fmt.Errorf("File %s exists. Remove it first", name)
|
|
}
|
|
if !os.IsNotExist(err) {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
bundle := context.String("bundle")
|
|
if bundle != "" {
|
|
if err := os.Chdir(bundle); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
if err := checkNoFile(specConfig); err != nil {
|
|
return err
|
|
}
|
|
data, err := json.MarshalIndent(spec, "", "\t")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if err := ioutil.WriteFile(specConfig, data, 0666); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
},
|
|
}
|
|
|
|
func sPtr(s string) *string { return &s }
|
|
|
|
// loadSpec loads the specification from the provided path.
|
|
func loadSpec(cPath string) (spec *specs.Spec, err error) {
|
|
cf, err := os.Open(cPath)
|
|
if err != nil {
|
|
if os.IsNotExist(err) {
|
|
return nil, fmt.Errorf("JSON specification file %s not found", cPath)
|
|
}
|
|
return nil, err
|
|
}
|
|
defer cf.Close()
|
|
|
|
if err = json.NewDecoder(cf).Decode(&spec); err != nil {
|
|
return nil, err
|
|
}
|
|
if err = validatePlatform(&spec.Platform); err != nil {
|
|
return nil, err
|
|
}
|
|
return spec, validateProcessSpec(&spec.Process)
|
|
}
|
|
|
|
func createLibContainerRlimit(rlimit specs.LinuxRlimit) (configs.Rlimit, error) {
|
|
rl, err := strToRlimit(rlimit.Type)
|
|
if err != nil {
|
|
return configs.Rlimit{}, err
|
|
}
|
|
return configs.Rlimit{
|
|
Type: rl,
|
|
Hard: rlimit.Hard,
|
|
Soft: rlimit.Soft,
|
|
}, nil
|
|
}
|
|
|
|
func validatePlatform(platform *specs.Platform) error {
|
|
if platform.OS != runtime.GOOS {
|
|
return fmt.Errorf("target os %s mismatch with current os %s", platform.OS, runtime.GOOS)
|
|
}
|
|
if platform.Arch != runtime.GOARCH {
|
|
return fmt.Errorf("target arch %s mismatch with current arch %s", platform.Arch, runtime.GOARCH)
|
|
}
|
|
return nil
|
|
}
|