1# libcontainer
2
3[](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