// Package container allows for running a process in a container. package container import ( "fmt" "os" "os/exec" "path/filepath" "github.com/coreos/go-systemd/activation" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/cgroups/systemd" "github.com/opencontainers/runc/libcontainer/specconv" specs "github.com/opencontainers/runtime-spec/specs-go" ) // Container defines the behavior and settings for a container object. type Container struct { ID string Spec *specs.Spec PIDFile string ConsoleSocket string Root string Detach bool UseSystemdCgroup bool NoPivotRoot bool NoNewKeyring bool Rootless bool } // Run starts the container. It returns the exit status or -1 and an // error. Signals sent to the current process will be forwarded to container. func (c *Container) Run() (int, error) { var err error // Convert pid-file to an absolute path so we can write to the // right file after chdir to bundle. if c.PIDFile != "" { c.PIDFile, err = filepath.Abs(c.PIDFile) if err != nil { return -1, err } } // Get the absolute path to the root. c.Root, err = filepath.Abs(c.Root) if err != nil { return -1, err } notifySocket := newNotifySocket(c.ID, c.Root) if notifySocket != nil { // Setup the spec for the notify socket. notifySocket.setupSpec(c.Spec) } // Create the libcontainer config. config, err := specconv.CreateLibcontainerConfig(&specconv.CreateOpts{ CgroupName: c.ID, UseSystemdCgroup: c.UseSystemdCgroup, NoPivotRoot: c.NoPivotRoot, NoNewKeyring: c.NoNewKeyring, Spec: c.Spec, Rootless: c.Rootless, }) if err != nil { return -1, err } // Setup the cgroups manager. Default is cgroupfs. cgroupManager := libcontainer.Cgroupfs if c.UseSystemdCgroup { if systemd.UseSystemd() { cgroupManager = libcontainer.SystemdCgroups } else { return -1, fmt.Errorf("systemd cgroup flag passed, but systemd support for managing cgroups is not available") } } // We resolve the paths for {newuidmap,newgidmap} from the context of runc, // to avoid doing a path lookup in the nsexec context. TODO: The binary // names are not currently configurable. newuidmap, err := exec.LookPath("newuidmap") if err != nil { newuidmap = "" } newgidmap, err := exec.LookPath("newgidmap") if err != nil { newgidmap = "" } // Create the new libcontainer factory. factory, err := libcontainer.New(c.Root, cgroupManager, nil, nil, libcontainer.NewuidmapPath(newuidmap), libcontainer.NewgidmapPath(newgidmap)) if err != nil { return -1, err } // Create the factory. container, err := factory.Create(c.ID, config) if err != nil { return -1, err } if notifySocket != nil { // Setup the socket for the notify socket. err := notifySocket.setupSocket() if err != nil { return -1, err } } // Support on-demand socket activation by passing file descriptors into // the container init process. listenFDs := []*os.File{} if os.Getenv("LISTEN_FDS") != "" { listenFDs = activation.Files(false) } // Initialize the runner. r := &runner{ enableSubreaper: true, shouldDestroy: true, container: container, listenFDs: listenFDs, notifySocket: notifySocket, consoleSocket: c.ConsoleSocket, detach: c.Detach, pidFile: c.PIDFile, } // Run the process. return r.run(c.Spec.Process) }