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