@@ -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" ))
2338if err != nil {
24- log.Fatal (err)
39+ logrus.Fatal (err)
40+ return
2541}
2642```
2743
2844Once 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
3249config := &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
83149Once 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
89159To spawn bash as the initial process inside the container and have the
90160processes pid returned in order to wait, signal, or kill the process:
91161
92162``` go
93163process := &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
102172err := container.Start (process)
103173if 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 ()
109181if 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.
125197stats , err := container.Stats ()
126198
127-
128199// pause all processes inside the container.
129200container.Pause ()
130201
0 commit comments