Skip to content

Commit f2f8f0e

Browse files
committed
Merge pull request #462 from hqhq/hq_fix_libcontainer_readme
Update README of libcontainer
2 parents 96982e3 + d87ac4a commit f2f8f0e

File tree

1 file changed

+138
-67
lines changed

1 file changed

+138
-67
lines changed

libcontainer/README.md

Lines changed: 138 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -10,104 +10,176 @@ host system and which is (optionally) isolated from other containers in the syst
1010

1111
#### Using libcontainer
1212

13-
To create a container you first have to initialize an instance of a factory
14-
that will handle the creation and initialization for a container.
13+
Because containers are spawned in a two step process you will need a binary that
14+
will be executed as the init process for the container. In libcontainer, we use
15+
the current binary (/proc/self/exe) to be executed as the init process, and use
16+
arg "init", we call the first step process "bootstrap", so you always need a "init"
17+
function as the entry of "bootstrap".
1518

16-
Because containers are spawned in a two step process you will need to provide
17-
arguments to a binary that will be executed as the init process for the container.
18-
To use the current binary that is spawning the containers and acting as the parent
19-
you can use `os.Args[0]` and we have a command called `init` setup.
19+
```go
20+
func init() {
21+
if len(os.Args) > 1 && os.Args[1] == "init" {
22+
runtime.GOMAXPROCS(1)
23+
runtime.LockOSThread()
24+
factory, _ := libcontainer.New("")
25+
if err := factory.StartInitialization(); err != nil {
26+
logrus.Fatal(err)
27+
}
28+
panic("--this line should have never been executed, congratulations--")
29+
}
30+
}
31+
```
32+
33+
Then to create a container you first have to initialize an instance of a factory
34+
that will handle the creation and initialization for a container.
2035

2136
```go
22-
root, err := libcontainer.New("/var/lib/container", libcontainer.InitArgs(os.Args[0], "init"))
37+
factory, err := libcontainer.New("/var/lib/container", libcontainer.Cgroupfs, libcontainer.InitArgs(os.Args[0], "init"))
2338
if err != nil {
24-
log.Fatal(err)
39+
logrus.Fatal(err)
40+
return
2541
}
2642
```
2743

2844
Once you have an instance of the factory created we can create a configuration
29-
struct describing how the container is to be created. A sample would look similar to this:
45+
struct describing how the container is to be created. A sample would look similar to this:
3046

3147
```go
48+
defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV
3249
config := &configs.Config{
33-
Rootfs: rootfs,
34-
Capabilities: []string{
35-
"CAP_CHOWN",
36-
"CAP_DAC_OVERRIDE",
37-
"CAP_FSETID",
38-
"CAP_FOWNER",
39-
"CAP_MKNOD",
40-
"CAP_NET_RAW",
41-
"CAP_SETGID",
42-
"CAP_SETUID",
43-
"CAP_SETFCAP",
44-
"CAP_SETPCAP",
45-
"CAP_NET_BIND_SERVICE",
46-
"CAP_SYS_CHROOT",
47-
"CAP_KILL",
48-
"CAP_AUDIT_WRITE",
49-
},
50-
Namespaces: configs.Namespaces([]configs.Namespace{
51-
{Type: configs.NEWNS},
52-
{Type: configs.NEWUTS},
53-
{Type: configs.NEWIPC},
54-
{Type: configs.NEWPID},
55-
{Type: configs.NEWNET},
56-
}),
57-
Cgroups: &configs.Cgroup{
58-
Name: "test-container",
59-
Parent: "system",
60-
AllowAllDevices: false,
61-
AllowedDevices: configs.DefaultAllowedDevices,
62-
},
63-
64-
Devices: configs.DefaultAutoCreatedDevices,
65-
Hostname: "testing",
66-
Networks: []*configs.Network{
67-
{
68-
Type: "loopback",
69-
Address: "127.0.0.1/0",
70-
Gateway: "localhost",
71-
},
72-
},
73-
Rlimits: []configs.Rlimit{
74-
{
75-
Type: syscall.RLIMIT_NOFILE,
76-
Hard: uint64(1024),
77-
Soft: uint64(1024),
78-
},
79-
},
50+
Rootfs: "/your/path/to/rootfs",
51+
Capabilities: []string{
52+
"CAP_CHOWN",
53+
"CAP_DAC_OVERRIDE",
54+
"CAP_FSETID",
55+
"CAP_FOWNER",
56+
"CAP_MKNOD",
57+
"CAP_NET_RAW",
58+
"CAP_SETGID",
59+
"CAP_SETUID",
60+
"CAP_SETFCAP",
61+
"CAP_SETPCAP",
62+
"CAP_NET_BIND_SERVICE",
63+
"CAP_SYS_CHROOT",
64+
"CAP_KILL",
65+
"CAP_AUDIT_WRITE",
66+
},
67+
Namespaces: configs.Namespaces([]configs.Namespace{
68+
{Type: configs.NEWNS},
69+
{Type: configs.NEWUTS},
70+
{Type: configs.NEWIPC},
71+
{Type: configs.NEWPID},
72+
{Type: configs.NEWNET},
73+
}),
74+
Cgroups: &configs.Cgroup{
75+
Name: "test-container",
76+
Parent: "system",
77+
Resources: &configs.Resources{
78+
MemorySwappiness: -1,
79+
AllowAllDevices: false,
80+
AllowedDevices: configs.DefaultAllowedDevices,
81+
},
82+
},
83+
MaskPaths: []string{
84+
"/proc/kcore",
85+
},
86+
ReadonlyPaths: []string{
87+
"/proc/sys", "/proc/sysrq-trigger", "/proc/irq", "/proc/bus",
88+
},
89+
Devices: configs.DefaultAutoCreatedDevices,
90+
Hostname: "testing",
91+
Mounts: []*configs.Mount{
92+
{
93+
Source: "proc",
94+
Destination: "/proc",
95+
Device: "proc",
96+
Flags: defaultMountFlags,
97+
},
98+
{
99+
Source: "tmpfs",
100+
Destination: "/dev",
101+
Device: "tmpfs",
102+
Flags: syscall.MS_NOSUID | syscall.MS_STRICTATIME,
103+
Data: "mode=755",
104+
},
105+
{
106+
Source: "devpts",
107+
Destination: "/dev/pts",
108+
Device: "devpts",
109+
Flags: syscall.MS_NOSUID | syscall.MS_NOEXEC,
110+
Data: "newinstance,ptmxmode=0666,mode=0620,gid=5",
111+
},
112+
{
113+
Device: "tmpfs",
114+
Source: "shm",
115+
Destination: "/dev/shm",
116+
Data: "mode=1777,size=65536k",
117+
Flags: defaultMountFlags,
118+
},
119+
{
120+
Source: "mqueue",
121+
Destination: "/dev/mqueue",
122+
Device: "mqueue",
123+
Flags: defaultMountFlags,
124+
},
125+
{
126+
Source: "sysfs",
127+
Destination: "/sys",
128+
Device: "sysfs",
129+
Flags: defaultMountFlags | syscall.MS_RDONLY,
130+
},
131+
},
132+
Networks: []*configs.Network{
133+
{
134+
Type: "loopback",
135+
Address: "127.0.0.1/0",
136+
Gateway: "localhost",
137+
},
138+
},
139+
Rlimits: []configs.Rlimit{
140+
{
141+
Type: syscall.RLIMIT_NOFILE,
142+
Hard: uint64(1025),
143+
Soft: uint64(1025),
144+
},
145+
},
80146
}
81147
```
82148

83149
Once you have the configuration populated you can create a container:
84150

85151
```go
86-
container, err := root.Create("container-id", config)
152+
container, err := factory.Create("container-id", config)
153+
if err != nil {
154+
logrus.Fatal(err)
155+
return
156+
}
87157
```
88158

89159
To spawn bash as the initial process inside the container and have the
90160
processes pid returned in order to wait, signal, or kill the process:
91161

92162
```go
93163
process := &libcontainer.Process{
94-
Args: []string{"/bin/bash"},
95-
Env: []string{"PATH=/bin"},
96-
User: "daemon",
97-
Stdin: os.Stdin,
98-
Stdout: os.Stdout,
99-
Stderr: os.Stderr,
164+
Args: []string{"/bin/bash"},
165+
Env: []string{"PATH=/bin"},
166+
User: "daemon",
167+
Stdin: os.Stdin,
168+
Stdout: os.Stdout,
169+
Stderr: os.Stderr,
100170
}
101171

102172
err := container.Start(process)
103173
if err != nil {
104-
log.Fatal(err)
174+
logrus.Fatal(err)
175+
container.Destroy()
176+
return
105177
}
106178

107179
// wait for the process to finish.
108-
status, err := process.Wait()
180+
_, err := process.Wait()
109181
if err != nil {
110-
log.Fatal(err)
182+
logrus.Fatal(err)
111183
}
112184

113185
// destroy the container.
@@ -124,7 +196,6 @@ processes, err := container.Processes()
124196
// it's processes.
125197
stats, err := container.Stats()
126198

127-
128199
// pause all processes inside the container.
129200
container.Pause()
130201

0 commit comments

Comments
 (0)