mirror of
https://github.com/opencontainers/runc.git
synced 2025-10-24 16:10:29 +08:00
Without this, multiple runc containers can accidentally share the same cgroup(s) (and change each other's limits), when runc is invoked from the same directory (i.e.: same cwd on multiple runc executions). After these changes, each runc container will run on its own cgroup(s). Before, the only workaround was to invoke runc from an unique (temporary?) cwd for each container. Common cgroup configuration (and hierarchical limits) can be set by having multiple runc containers share the same cgroup parent, which is the cgroup of the process executing runc. Signed-off-by: Fabio Kung <fabio.kung@gmail.com>
109 lines
2.7 KiB
Go
109 lines
2.7 KiB
Go
// +build linux
|
|
|
|
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"runtime"
|
|
|
|
"github.com/Sirupsen/logrus"
|
|
"github.com/codegangsta/cli"
|
|
"github.com/opencontainers/runc/libcontainer"
|
|
"github.com/opencontainers/specs"
|
|
)
|
|
|
|
func init() {
|
|
if len(os.Args) > 1 && os.Args[1] == "init" {
|
|
runtime.GOMAXPROCS(1)
|
|
runtime.LockOSThread()
|
|
factory, _ := libcontainer.New("")
|
|
if err := factory.StartInitialization(); err != nil {
|
|
fatal(err)
|
|
}
|
|
panic("--this line should have never been executed, congratulations--")
|
|
}
|
|
}
|
|
|
|
func execContainer(context *cli.Context, spec *specs.LinuxSpec) (int, error) {
|
|
config, err := createLibcontainerConfig(context.GlobalString("id"), spec)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
if _, err := os.Stat(config.Rootfs); err != nil {
|
|
if os.IsNotExist(err) {
|
|
return -1, fmt.Errorf("Rootfs (%q) does not exist", config.Rootfs)
|
|
}
|
|
return -1, err
|
|
}
|
|
rootuid, err := config.HostUID()
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
factory, err := loadFactory(context)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
container, err := factory.Create(context.GlobalString("id"), config)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
// ensure that the container is always removed if we were the process
|
|
// that created it.
|
|
defer destroy(container)
|
|
process := newProcess(spec.Process)
|
|
tty, err := newTty(spec.Process.Terminal, process, rootuid)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
handler := newSignalHandler(tty)
|
|
defer handler.Close()
|
|
if err := container.Start(process); err != nil {
|
|
return -1, err
|
|
}
|
|
return handler.forward(process)
|
|
}
|
|
|
|
// default action is to execute a container
|
|
func runAction(context *cli.Context) {
|
|
spec, err := loadSpec(context.Args().First())
|
|
|
|
notifySocket := os.Getenv("NOTIFY_SOCKET")
|
|
if notifySocket != "" {
|
|
setupSdNotify(spec, notifySocket)
|
|
}
|
|
|
|
if err != nil {
|
|
fatal(err)
|
|
}
|
|
if os.Geteuid() != 0 {
|
|
logrus.Fatal("runc should be run as root")
|
|
}
|
|
status, err := execContainer(context, spec)
|
|
if err != nil {
|
|
logrus.Fatalf("Container start failed: %v", err)
|
|
}
|
|
// exit with the container's exit status so any external supervisor is
|
|
// notified of the exit with the correct exit status.
|
|
os.Exit(status)
|
|
}
|
|
|
|
// If systemd is supporting sd_notify protocol, this function will add support
|
|
// for sd_notify protocol from within the container.
|
|
func setupSdNotify(spec *specs.LinuxSpec, notifySocket string) {
|
|
spec.Mounts = append(spec.Mounts, specs.Mount{Type: "bind", Source: notifySocket, Destination: notifySocket, Options: "bind"})
|
|
spec.Process.Env = append(spec.Process.Env, fmt.Sprintf("NOTIFY_SOCKET=%s", notifySocket))
|
|
}
|
|
|
|
func destroy(container libcontainer.Container) {
|
|
status, err := container.Status()
|
|
if err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
if status != libcontainer.Checkpointed {
|
|
if err := container.Destroy(); err != nil {
|
|
logrus.Error(err)
|
|
}
|
|
}
|
|
}
|