78 lines
1.7 KiB
Go
78 lines
1.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"strconv"
|
|
"syscall"
|
|
"time"
|
|
)
|
|
|
|
// docker run <container-name> <command> <args>
|
|
// go main.go run <command> <args>
|
|
|
|
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)
|
|
}
|
|
}
|