...

Text file src/github.com/opencontainers/runc/libcontainer/README.md

Documentation: github.com/opencontainers/runc/libcontainer

     1# libcontainer
     2
     3[![Go Reference](https://pkg.go.dev/badge/github.com/opencontainers/runc/libcontainer.svg)](https://pkg.go.dev/github.com/opencontainers/runc/libcontainer)
     4
     5Libcontainer provides a native Go implementation for creating containers
     6with namespaces, cgroups, capabilities, and filesystem access controls.
     7It allows you to manage the lifecycle of the container performing additional operations
     8after the container is created.
     9
    10
    11#### Container
    12A container is a self contained execution environment that shares the kernel of the
    13host system and which is (optionally) isolated from other containers in the system.
    14
    15#### Using libcontainer
    16
    17Because containers are spawned in a two step process you will need a binary that
    18will be executed as the init process for the container. In libcontainer, we use
    19the current binary (/proc/self/exe) to be executed as the init process, and use
    20arg "init", we call the first step process "bootstrap", so you always need a "init"
    21function as the entry of "bootstrap".
    22
    23In addition to the go init function the early stage bootstrap is handled by importing
    24[nsenter](https://github.com/opencontainers/runc/blob/master/libcontainer/nsenter/README.md).
    25
    26```go
    27import (
    28	_ "github.com/opencontainers/runc/libcontainer/nsenter"
    29)
    30
    31func init() {
    32	if len(os.Args) > 1 && os.Args[1] == "init" {
    33		runtime.GOMAXPROCS(1)
    34		runtime.LockOSThread()
    35		factory, _ := libcontainer.New("")
    36		if err := factory.StartInitialization(); err != nil {
    37			logrus.Fatal(err)
    38		}
    39		panic("--this line should have never been executed, congratulations--")
    40	}
    41}
    42```
    43
    44Then to create a container you first have to initialize an instance of a factory
    45that will handle the creation and initialization for a container.
    46
    47```go
    48factory, err := libcontainer.New("/var/lib/container", libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "init"))
    49if err != nil {
    50	logrus.Fatal(err)
    51	return
    52}
    53```
    54
    55Once you have an instance of the factory created we can create a configuration
    56struct describing how the container is to be created. A sample would look similar to this:
    57
    58```go
    59defaultMountFlags := unix.MS_NOEXEC | unix.MS_NOSUID | unix.MS_NODEV
    60var devices []*configs.DeviceRule
    61for _, device := range specconv.AllowedDevices {
    62	devices = append(devices, &device.Rule)
    63}
    64config := &configs.Config{
    65	Rootfs: "/your/path/to/rootfs",
    66	Capabilities: &configs.Capabilities{
    67		Bounding: []string{
    68			"CAP_CHOWN",
    69			"CAP_DAC_OVERRIDE",
    70			"CAP_FSETID",
    71			"CAP_FOWNER",
    72			"CAP_MKNOD",
    73			"CAP_NET_RAW",
    74			"CAP_SETGID",
    75			"CAP_SETUID",
    76			"CAP_SETFCAP",
    77			"CAP_SETPCAP",
    78			"CAP_NET_BIND_SERVICE",
    79			"CAP_SYS_CHROOT",
    80			"CAP_KILL",
    81			"CAP_AUDIT_WRITE",
    82		},
    83		Effective: []string{
    84			"CAP_CHOWN",
    85			"CAP_DAC_OVERRIDE",
    86			"CAP_FSETID",
    87			"CAP_FOWNER",
    88			"CAP_MKNOD",
    89			"CAP_NET_RAW",
    90			"CAP_SETGID",
    91			"CAP_SETUID",
    92			"CAP_SETFCAP",
    93			"CAP_SETPCAP",
    94			"CAP_NET_BIND_SERVICE",
    95			"CAP_SYS_CHROOT",
    96			"CAP_KILL",
    97			"CAP_AUDIT_WRITE",
    98		},
    99		Permitted: []string{
   100			"CAP_CHOWN",
   101			"CAP_DAC_OVERRIDE",
   102			"CAP_FSETID",
   103			"CAP_FOWNER",
   104			"CAP_MKNOD",
   105			"CAP_NET_RAW",
   106			"CAP_SETGID",
   107			"CAP_SETUID",
   108			"CAP_SETFCAP",
   109			"CAP_SETPCAP",
   110			"CAP_NET_BIND_SERVICE",
   111			"CAP_SYS_CHROOT",
   112			"CAP_KILL",
   113			"CAP_AUDIT_WRITE",
   114		},
   115		Ambient: []string{
   116			"CAP_CHOWN",
   117			"CAP_DAC_OVERRIDE",
   118			"CAP_FSETID",
   119			"CAP_FOWNER",
   120			"CAP_MKNOD",
   121			"CAP_NET_RAW",
   122			"CAP_SETGID",
   123			"CAP_SETUID",
   124			"CAP_SETFCAP",
   125			"CAP_SETPCAP",
   126			"CAP_NET_BIND_SERVICE",
   127			"CAP_SYS_CHROOT",
   128			"CAP_KILL",
   129			"CAP_AUDIT_WRITE",
   130		},
   131	},
   132	Namespaces: configs.Namespaces([]configs.Namespace{
   133		{Type: configs.NEWNS},
   134		{Type: configs.NEWUTS},
   135		{Type: configs.NEWIPC},
   136		{Type: configs.NEWPID},
   137		{Type: configs.NEWUSER},
   138		{Type: configs.NEWNET},
   139		{Type: configs.NEWCGROUP},
   140	}),
   141	Cgroups: &configs.Cgroup{
   142		Name:   "test-container",
   143		Parent: "system",
   144		Resources: &configs.Resources{
   145			MemorySwappiness: nil,
   146			Devices:          devices,
   147		},
   148	},
   149	MaskPaths: []string{
   150		"/proc/kcore",
   151		"/sys/firmware",
   152	},
   153	ReadonlyPaths: []string{
   154		"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
   155	},
   156	Devices:  specconv.AllowedDevices,
   157	Hostname: "testing",
   158	Mounts: []*configs.Mount{
   159		{
   160			Source:      "proc",
   161			Destination: "/proc",
   162			Device:      "proc",
   163			Flags:       defaultMountFlags,
   164		},
   165		{
   166			Source:      "tmpfs",
   167			Destination: "/dev",
   168			Device:      "tmpfs",
   169			Flags:       unix.MS_NOSUID | unix.MS_STRICTATIME,
   170			Data:        "mode=755",
   171		},
   172		{
   173			Source:      "devpts",
   174			Destination: "/dev/pts",
   175			Device:      "devpts",
   176			Flags:       unix.MS_NOSUID | unix.MS_NOEXEC,
   177			Data:        "newinstance,ptmxmode=0666,mode=0620,gid=5",
   178		},
   179		{
   180			Device:      "tmpfs",
   181			Source:      "shm",
   182			Destination: "/dev/shm",
   183			Data:        "mode=1777,size=65536k",
   184			Flags:       defaultMountFlags,
   185		},
   186		{
   187			Source:      "mqueue",
   188			Destination: "/dev/mqueue",
   189			Device:      "mqueue",
   190			Flags:       defaultMountFlags,
   191		},
   192		{
   193			Source:      "sysfs",
   194			Destination: "/sys",
   195			Device:      "sysfs",
   196			Flags:       defaultMountFlags | unix.MS_RDONLY,
   197		},
   198	},
   199	UidMappings: []configs.IDMap{
   200		{
   201			ContainerID: 0,
   202			HostID: 1000,
   203			Size: 65536,
   204		},
   205	},
   206	GidMappings: []configs.IDMap{
   207		{
   208			ContainerID: 0,
   209			HostID: 1000,
   210			Size: 65536,
   211		},
   212	},
   213	Networks: []*configs.Network{
   214		{
   215			Type:    "loopback",
   216			Address: "127.0.0.1/0",
   217			Gateway: "localhost",
   218		},
   219	},
   220	Rlimits: []configs.Rlimit{
   221		{
   222			Type: unix.RLIMIT_NOFILE,
   223			Hard: uint64(1025),
   224			Soft: uint64(1025),
   225		},
   226	},
   227}
   228```
   229
   230Once you have the configuration populated you can create a container:
   231
   232```go
   233container, err := factory.Create("container-id", config)
   234if err != nil {
   235	logrus.Fatal(err)
   236	return
   237}
   238```
   239
   240To spawn bash as the initial process inside the container and have the
   241processes pid returned in order to wait, signal, or kill the process:
   242
   243```go
   244process := &libcontainer.Process{
   245	Args:   []string{"/bin/bash"},
   246	Env:    []string{"PATH=/bin"},
   247	User:   "daemon",
   248	Stdin:  os.Stdin,
   249	Stdout: os.Stdout,
   250	Stderr: os.Stderr,
   251	Init:   true,
   252}
   253
   254err := container.Run(process)
   255if err != nil {
   256	container.Destroy()
   257	logrus.Fatal(err)
   258	return
   259}
   260
   261// wait for the process to finish.
   262_, err := process.Wait()
   263if err != nil {
   264	logrus.Fatal(err)
   265}
   266
   267// destroy the container.
   268container.Destroy()
   269```
   270
   271Additional ways to interact with a running container are:
   272
   273```go
   274// return all the pids for all processes running inside the container.
   275processes, err := container.Processes()
   276
   277// get detailed cpu, memory, io, and network statistics for the container and
   278// it's processes.
   279stats, err := container.Stats()
   280
   281// pause all processes inside the container.
   282container.Pause()
   283
   284// resume all paused processes.
   285container.Resume()
   286
   287// send signal to container's init process.
   288container.Signal(signal)
   289
   290// update container resource constraints.
   291container.Set(config)
   292
   293// get current status of the container.
   294status, err := container.Status()
   295
   296// get current container's state information.
   297state, err := container.State()
   298```
   299
   300
   301#### Checkpoint & Restore
   302
   303libcontainer now integrates [CRIU](http://criu.org/) for checkpointing and restoring containers.
   304This lets you save the state of a process running inside a container to disk, and then restore
   305that state into a new process, on the same machine or on another machine.
   306
   307`criu` version 1.5.2 or higher is required to use checkpoint and restore.
   308If you don't already  have `criu` installed, you can build it from source, following the
   309[online instructions](http://criu.org/Installation). `criu` is also installed in the docker image
   310generated when building libcontainer with docker.
   311
   312
   313## Copyright and license
   314
   315Code and documentation copyright 2014 Docker, inc.
   316The code and documentation are released under the [Apache 2.0 license](../LICENSE).
   317The documentation is also released under Creative Commons Attribution 4.0 International License.
   318You may obtain a copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.

View as plain text