github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/libcontainer/README.md (about)

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