-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.go
More file actions
133 lines (111 loc) · 3.01 KB
/
main.go
File metadata and controls
133 lines (111 loc) · 3.01 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
package main
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
)
// docker run <image> <command> <args>
// go run main.go <command> <args>
func main() {
switch os.Args[1] {
case "run":
run()
case "child":
child()
default:
panic("found wrong argument")
}
}
// Entry point for the container.
// This sets up the container environment and spawns the process that runs the command inside the container.
func run() {
fmt.Println("Running:", os.Args[2:], "as", os.Getpid())
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.Args[2:]...)...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS,
Unshareflags: syscall.CLONE_NEWNS,
}
err := cmd.Run()
if err != nil {
panic(err)
}
}
// Entry point for the child process.
// This actually runs the command inside the container.
func child() {
fmt.Println("Running child:", os.Args[2:], "as", os.Getpid())
cg()
syscall.Sethostname([]byte("container"))
syscall.Chroot("/")
syscall.Chdir("/")
syscall.Mount("proc", "proc", "proc", 0, "")
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
err := cmd.Run()
if err != nil {
panic(err)
}
syscall.Unmount("proc", 0)
}
// Setup cgroups for the container.
func cg() {
// Determine which cgroup version we're using
cgroupV2 := "/sys/fs/cgroup/cgroup.controllers"
_, err := os.Stat(cgroupV2)
isV2 := err == nil
if isV2 {
// Cgroups v2 (unified hierarchy)
cgroups := "/sys/fs/cgroup/rudr"
err := os.MkdirAll(cgroups, 0755)
if err != nil && !os.IsExist(err) {
panic(err)
}
// Enable pids controller for this cgroup
must(writeFile("/sys/fs/cgroup/cgroup.subtree_control", "+pids"))
// Set max pids
must(writeFile(filepath.Join(cgroups, "pids.max"), "20"))
// Add current process to the cgroup
must(writeFile(filepath.Join(cgroups, "cgroup.procs"), strconv.Itoa(os.Getpid())))
} else {
// Cgroups v1
cgroups := "/sys/fs/cgroup/"
pids := filepath.Join(cgroups, "pids")
err := os.MkdirAll(filepath.Join(pids, "rudr"), 0755)
if err != nil && !os.IsExist(err) {
panic(err)
}
// Set max pids
must(writeFile(filepath.Join(pids, "rudr/pids.max"), "20"))
// The notify_on_release doesn't exist in many modern systems
notifyPath := filepath.Join(pids, "rudr/notify_on_release")
if _, err := os.Stat(notifyPath); err == nil {
must(writeFile(notifyPath, "1"))
}
// Add current process to the cgroup
must(writeFile(filepath.Join(pids, "rudr/cgroup.procs"), strconv.Itoa(os.Getpid())))
}
}
// Helper function to write to cgroup files
func writeFile(path, content string) error {
// Open the file for writing, don't use create flags
file, err := os.OpenFile(path, os.O_WRONLY, 0)
if err != nil {
return err
}
defer file.Close()
_, err = file.WriteString(content)
return err
}
func must(err error) {
if err != nil {
panic(err)
}
}