package libcontainer_test import ( "log" "os" "golang.org/x/sys/unix" "github.com/opencontainers/cgroups" "github.com/opencontainers/cgroups/devices/config" // To enable device management code, import cgroups/devices package. // Without it, cgroup manager won't be able to set up device access rules, // and will fail if devices are specified in the container configuration. _ "github.com/opencontainers/cgroups/devices" "github.com/opencontainers/runc/libcontainer" "github.com/opencontainers/runc/libcontainer/configs" "github.com/opencontainers/runc/libcontainer/specconv" // Required for container enter functionality. _ "github.com/opencontainers/runc/libcontainer/nsenter" ) func Example_container() { const defaultMountFlags = unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV // Default set of allowed devices. var devices []*config.Rule for _, device := range specconv.AllowedDevices { devices = append(devices, &device.Rule) } // To create a container you first have to create a configuration // struct describing how the container is to be created. config := &configs.Config{ Rootfs: "/your/path/to/rootfs", Capabilities: &configs.Capabilities{ Bounding: []string{ "CAP_KILL", "CAP_AUDIT_WRITE", }, Effective: []string{ "CAP_KILL", "CAP_AUDIT_WRITE", }, Permitted: []string{ "CAP_KILL", "CAP_AUDIT_WRITE", }, }, Namespaces: configs.Namespaces([]configs.Namespace{ {Type: configs.NEWNS}, {Type: configs.NEWUTS}, {Type: configs.NEWIPC}, {Type: configs.NEWPID}, {Type: configs.NEWUSER}, {Type: configs.NEWNET}, {Type: configs.NEWCGROUP}, }), Cgroups: &cgroups.Cgroup{ Name: "test-container", Parent: "system", Resources: &cgroups.Resources{ MemorySwappiness: nil, Devices: devices, }, }, MaskPaths: []string{ "/proc/kcore", "/sys/firmware", }, ReadonlyPaths: []string{ "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus", }, Devices: specconv.AllowedDevices, Hostname: "testing", Mounts: []*configs.Mount{ { Source: "proc", Destination: "/proc", Device: "proc", Flags: defaultMountFlags, }, { Source: "tmpfs", Destination: "/dev", Device: "tmpfs", Flags: unix.MS_NOSUID | unix.MS_STRICTATIME, Data: "mode=755", }, { Source: "devpts", Destination: "/dev/pts", Device: "devpts", Flags: unix.MS_NOSUID | unix.MS_NOEXEC, Data: "newinstance,ptmxmode=0666,mode=0620,gid=5", }, { Device: "tmpfs", Source: "shm", Destination: "/dev/shm", Data: "mode=1777,size=65536k", Flags: defaultMountFlags, }, { Source: "mqueue", Destination: "/dev/mqueue", Device: "mqueue", Flags: defaultMountFlags, }, { Source: "sysfs", Destination: "/sys", Device: "sysfs", Flags: defaultMountFlags | unix.MS_RDONLY, }, }, UIDMappings: []configs.IDMap{ { ContainerID: 0, HostID: 1000, Size: 65536, }, }, GIDMappings: []configs.IDMap{ { ContainerID: 0, HostID: 1000, Size: 65536, }, }, Networks: []*configs.Network{ { Type: "loopback", Address: "127.0.0.1/0", Gateway: "localhost", }, }, Rlimits: []configs.Rlimit{ { Type: unix.RLIMIT_NOFILE, Hard: uint64(1025), Soft: uint64(1025), }, }, } // Once you have the configuration populated you can create a container // with a specified ID under a specified state directory: container, err := libcontainer.Create("/run/containers", "container-id", config) if err != nil { log.Fatal(err) return } // To spawn bash as the initial process inside the container and have the // processes pid returned in order to wait, signal, or kill the process: process := &libcontainer.Process{ Args: []string{"/bin/bash"}, Env: []string{"PATH=/bin"}, UID: 0, Stdin: os.Stdin, Stdout: os.Stdout, Stderr: os.Stderr, Init: true, } err = container.Run(process) if err != nil { _ = container.Destroy() log.Fatal(err) return } // Wait for the process to finish. _, err = process.Wait() if err != nil { log.Fatal(err) } // Destroy the container. err = container.Destroy() if err != nil { log.Fatal(err) } // Additional ways to interact with a running container are: // Return all the pids for all processes running inside the container. processes, err := container.Processes() if err != nil { log.Fatal(err) } log.Print(processes) // Get detailed cpu, memory, io, and network statistics for the container and // it's processes. stats, err := container.Stats() if err != nil { log.Fatal(err) } log.Print(stats) // Pause all processes inside the container. err = container.Pause() if err != nil { log.Fatal(err) } // Resume all paused processes. err = container.Resume() if err != nil { log.Fatal(err) } // Send signal to container's init process. err = container.Signal(unix.SIGHUP) if err != nil { log.Fatal(err) } // Update container resource constraints. err = container.Set(*config) if err != nil { log.Fatal(err) } // Get current status of the container. status, err := container.Status() if err != nil { log.Fatal(err) } log.Print(status) // Get current container's state information. state, err := container.State() if err != nil { log.Fatal(err) } log.Print(state) }