README.md
1# libcontainer
2
3[![GoDoc](https://godoc.org/github.com/opencontainers/runc/libcontainer?status.svg)](https://godoc.org/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
60config := &configs.Config{
61 Rootfs: "/your/path/to/rootfs",
62 Capabilities: &configs.Capabilities{
63 Bounding: []string{
64 "CAP_CHOWN",
65 "CAP_DAC_OVERRIDE",
66 "CAP_FSETID",
67 "CAP_FOWNER",
68 "CAP_MKNOD",
69 "CAP_NET_RAW",
70 "CAP_SETGID",
71 "CAP_SETUID",
72 "CAP_SETFCAP",
73 "CAP_SETPCAP",
74 "CAP_NET_BIND_SERVICE",
75 "CAP_SYS_CHROOT",
76 "CAP_KILL",
77 "CAP_AUDIT_WRITE",
78 },
79 Effective: []string{
80 "CAP_CHOWN",
81 "CAP_DAC_OVERRIDE",
82 "CAP_FSETID",
83 "CAP_FOWNER",
84 "CAP_MKNOD",
85 "CAP_NET_RAW",
86 "CAP_SETGID",
87 "CAP_SETUID",
88 "CAP_SETFCAP",
89 "CAP_SETPCAP",
90 "CAP_NET_BIND_SERVICE",
91 "CAP_SYS_CHROOT",
92 "CAP_KILL",
93 "CAP_AUDIT_WRITE",
94 },
95 Inheritable: []string{
96 "CAP_CHOWN",
97 "CAP_DAC_OVERRIDE",
98 "CAP_FSETID",
99 "CAP_FOWNER",
100 "CAP_MKNOD",
101 "CAP_NET_RAW",
102 "CAP_SETGID",
103 "CAP_SETUID",
104 "CAP_SETFCAP",
105 "CAP_SETPCAP",
106 "CAP_NET_BIND_SERVICE",
107 "CAP_SYS_CHROOT",
108 "CAP_KILL",
109 "CAP_AUDIT_WRITE",
110 },
111 Permitted: []string{
112 "CAP_CHOWN",
113 "CAP_DAC_OVERRIDE",
114 "CAP_FSETID",
115 "CAP_FOWNER",
116 "CAP_MKNOD",
117 "CAP_NET_RAW",
118 "CAP_SETGID",
119 "CAP_SETUID",
120 "CAP_SETFCAP",
121 "CAP_SETPCAP",
122 "CAP_NET_BIND_SERVICE",
123 "CAP_SYS_CHROOT",
124 "CAP_KILL",
125 "CAP_AUDIT_WRITE",
126 },
127 Ambient: []string{
128 "CAP_CHOWN",
129 "CAP_DAC_OVERRIDE",
130 "CAP_FSETID",
131 "CAP_FOWNER",
132 "CAP_MKNOD",
133 "CAP_NET_RAW",
134 "CAP_SETGID",
135 "CAP_SETUID",
136 "CAP_SETFCAP",
137 "CAP_SETPCAP",
138 "CAP_NET_BIND_SERVICE",
139 "CAP_SYS_CHROOT",
140 "CAP_KILL",
141 "CAP_AUDIT_WRITE",
142 },
143 },
144 Namespaces: configs.Namespaces([]configs.Namespace{
145 {Type: configs.NEWNS},
146 {Type: configs.NEWUTS},
147 {Type: configs.NEWIPC},
148 {Type: configs.NEWPID},
149 {Type: configs.NEWUSER},
150 {Type: configs.NEWNET},
151 {Type: configs.NEWCGROUP},
152 }),
153 Cgroups: &configs.Cgroup{
154 Name: "test-container",
155 Parent: "system",
156 Resources: &configs.Resources{
157 MemorySwappiness: nil,
158 Devices: specconv.AllowedDevices,
159 },
160 },
161 MaskPaths: []string{
162 "/proc/kcore",
163 "/sys/firmware",
164 },
165 ReadonlyPaths: []string{
166 "/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
167 },
168 Devices: specconv.AllowedDevices,
169 Hostname: "testing",
170 Mounts: []*configs.Mount{
171 {
172 Source: "proc",
173 Destination: "/proc",
174 Device: "proc",
175 Flags: defaultMountFlags,
176 },
177 {
178 Source: "tmpfs",
179 Destination: "/dev",
180 Device: "tmpfs",
181 Flags: unix.MS_NOSUID | unix.MS_STRICTATIME,
182 Data: "mode=755",
183 },
184 {
185 Source: "devpts",
186 Destination: "/dev/pts",
187 Device: "devpts",
188 Flags: unix.MS_NOSUID | unix.MS_NOEXEC,
189 Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
190 },
191 {
192 Device: "tmpfs",
193 Source: "shm",
194 Destination: "/dev/shm",
195 Data: "mode=1777,size=65536k",
196 Flags: defaultMountFlags,
197 },
198 {
199 Source: "mqueue",
200 Destination: "/dev/mqueue",
201 Device: "mqueue",
202 Flags: defaultMountFlags,
203 },
204 {
205 Source: "sysfs",
206 Destination: "/sys",
207 Device: "sysfs",
208 Flags: defaultMountFlags | unix.MS_RDONLY,
209 },
210 },
211 UidMappings: []configs.IDMap{
212 {
213 ContainerID: 0,
214 HostID: 1000,
215 Size: 65536,
216 },
217 },
218 GidMappings: []configs.IDMap{
219 {
220 ContainerID: 0,
221 HostID: 1000,
222 Size: 65536,
223 },
224 },
225 Networks: []*configs.Network{
226 {
227 Type: "loopback",
228 Address: "127.0.0.1/0",
229 Gateway: "localhost",
230 },
231 },
232 Rlimits: []configs.Rlimit{
233 {
234 Type: unix.RLIMIT_NOFILE,
235 Hard: uint64(1025),
236 Soft: uint64(1025),
237 },
238 },
239}
240```
241
242Once you have the configuration populated you can create a container:
243
244```go
245container, err := factory.Create("container-id", config)
246if err != nil {
247 logrus.Fatal(err)
248 return
249}
250```
251
252To spawn bash as the initial process inside the container and have the
253processes pid returned in order to wait, signal, or kill the process:
254
255```go
256process := &libcontainer.Process{
257 Args: []string{"/bin/bash"},
258 Env: []string{"PATH=/bin"},
259 User: "daemon",
260 Stdin: os.Stdin,
261 Stdout: os.Stdout,
262 Stderr: os.Stderr,
263 Init: true,
264}
265
266err := container.Run(process)
267if err != nil {
268 container.Destroy()
269 logrus.Fatal(err)
270 return
271}
272
273// wait for the process to finish.
274_, err := process.Wait()
275if err != nil {
276 logrus.Fatal(err)
277}
278
279// destroy the container.
280container.Destroy()
281```
282
283Additional ways to interact with a running container are:
284
285```go
286// return all the pids for all processes running inside the container.
287processes, err := container.Processes()
288
289// get detailed cpu, memory, io, and network statistics for the container and
290// it's processes.
291stats, err := container.Stats()
292
293// pause all processes inside the container.
294container.Pause()
295
296// resume all paused processes.
297container.Resume()
298
299// send signal to container's init process.
300container.Signal(signal)
301
302// update container resource constraints.
303container.Set(config)
304
305// get current status of the container.
306status, err := container.Status()
307
308// get current container's state information.
309state, err := container.State()
310```
311
312
313#### Checkpoint & Restore
314
315libcontainer now integrates [CRIU](http://criu.org/) for checkpointing and restoring containers.
316This let's you save the state of a process running inside a container to disk, and then restore
317that state into a new process, on the same machine or on another machine.
318
319`criu` version 1.5.2 or higher is required to use checkpoint and restore.
320If you don't already have `criu` installed, you can build it from source, following the
321[online instructions](http://criu.org/Installation). `criu` is also installed in the docker image
322generated when building libcontainer with docker.
323
324
325## Copyright and license
326
327Code and documentation copyright 2014 Docker, inc.
328The code and documentation are released under the [Apache 2.0 license](../LICENSE).
329The documentation is also released under Creative Commons Attribution 4.0 International License.
330You may obtain a copy of the license, titled CC-BY-4.0, at http://creativecommons.org/licenses/by/4.0/.
331