package main import ( "fmt" "os" "os/exec" "strconv" "syscall" "time" ) // docker run // go main.go run func main() { if len(os.Args) < 3 { panic("found too few arguments for the program.") } switch os.Args[1] { case "run": executeRun() case "child": executeChild() default: panic(fmt.Sprintf("found an unsupported command: %s", os.Args[0])) } } func executeRun() { fmt.Printf("starting: 'run' in PID: %d\n", 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, } must(cmd.Run()) } func executeChild() { fmt.Printf("starting: %s in PID: %d\n", os.Args[2], os.Getpid()) setupCgroup() syscall.Sethostname([]byte("container")) syscall.Chroot("./container-root") os.Chdir("/") syscall.Mount("proc", "proc", "proc", 0, "") defer syscall.Unmount("/proc", 0) cmd := exec.Command(os.Args[2]) cmd.Stdin = os.Stdin cmd.Stdout = os.Stdout cmd.Stderr = os.Stderr must(cmd.Run()) } func setupCgroup() { cgroupDir := fmt.Sprintf("/sys/fs/cgroup/pids/%d", time.Now().Unix()) must(os.Mkdir(cgroupDir, 0755)) os.WriteFile(fmt.Sprintf("%s/pids.max", cgroupDir), []byte("20"), 0644) os.WriteFile(fmt.Sprintf("%s/notify_on_release", cgroupDir), []byte("1"), 0644) os.WriteFile(fmt.Sprintf("%s/cgroup.procs", cgroupDir), []byte(strconv.Itoa(os.Getpid())), 0644) } func must(err error) { if err != nil { panic(err) } }