commit 2893ff3c212f7e7c7e1fbdf32ce5f2797d693b61 Author: root Date: Wed Mar 20 19:14:31 2024 -0700 step011: run command diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d48c759 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +.vscode \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1fb540a --- /dev/null +++ b/go.mod @@ -0,0 +1,15 @@ +module upod + +go 1.22.1 + +require ( + github.com/sirupsen/logrus v1.9.3 + github.com/spf13/cast v1.6.0 + github.com/spf13/cobra v1.8.0 +) + +require ( + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..bcc2dcc --- /dev/null +++ b/go.sum @@ -0,0 +1,36 @@ +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= +github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= +github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0= +github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/cmd/init.go b/internal/cmd/init.go new file mode 100644 index 0000000..910d736 --- /dev/null +++ b/internal/cmd/init.go @@ -0,0 +1,6 @@ +package cmd + +func init() { + initRootCommand() + initRunCommand() +} diff --git a/internal/cmd/root.go b/internal/cmd/root.go new file mode 100644 index 0000000..93ae262 --- /dev/null +++ b/internal/cmd/root.go @@ -0,0 +1,16 @@ +package cmd + +import ( + "github.com/spf13/cobra" +) + +var ( + rootCommand = &cobra.Command{ + Use: "upod", + Short: "upod is a simple container runtime implementation", + } +) + +func initRootCommand() { + +} diff --git a/internal/cmd/run.go b/internal/cmd/run.go new file mode 100644 index 0000000..d6bb3e9 --- /dev/null +++ b/internal/cmd/run.go @@ -0,0 +1,44 @@ +package cmd + +import ( + "errors" + "os" + "upod/internal/container" + "upod/internal/log" + + "github.com/spf13/cobra" +) + +var ( + runCommand = &cobra.Command{ + Use: "run", + Short: "upod run [OPTIONS] IMAGE [COMMAND] [ARG...]", + RunE: func(ctx *cobra.Command, args []string) error { + var ( + err error + ) + + log.Debug("runCommand: args=%v", args) + + if len(args) == 0 { + return errors.New("upod run requires at least 1 argument") + } + + cmd := container.NewParentProcess(true, args[0]) + + if err = cmd.Start(); err != nil { + return err + } + + cmd.Wait() + + os.Exit(0) + + return nil + }, + } +) + +func initRunCommand() { + rootCommand.AddCommand(runCommand) +} diff --git a/internal/cmd/start.go b/internal/cmd/start.go new file mode 100644 index 0000000..d20c3e6 --- /dev/null +++ b/internal/cmd/start.go @@ -0,0 +1,19 @@ +package cmd + +import ( + "context" + "os" + "upod/internal/container" + "upod/internal/log" +) + +func Start(ctx context.Context) error { + + if len(os.Args) >= 3 && os.Args[1] == "init" { + log.Debug("cmd.Start: init args=%v", os.Args) + + container.RunContainerInitProcess(os.Args[2], os.Args[2:]) + } + + return rootCommand.ExecuteContext(ctx) +} diff --git a/internal/container/new.go b/internal/container/new.go new file mode 100644 index 0000000..f646d43 --- /dev/null +++ b/internal/container/new.go @@ -0,0 +1,32 @@ +package container + +import ( + "os" + "os/exec" + "syscall" +) + +// NewParentProcess 启动一个新进程 +/* +这里是父进程,也就是当前进程执行的内容。 +1.这里的/proc/se1f/exe调用中,/proc/self/ 指的是当前运行进程自己的环境,exec 其实就是自己调用了自己,使用这种方式对创建出来的进程进行初始化 +2.后面的args是参数,其中init是传递给本进程的第一个参数,在本例中,其实就是会去调用initCommand去初始化进程的一些环境和资源 +3.下面的clone参数就是去fork出来一个新进程,并且使用了namespace隔离新创建的进程和外部环境。 +4.如果用户指定了-it参数,就需要把当前进程的输入输出导入到标准输入输出上 +*/ +func NewParentProcess(tty bool, command string) *exec.Cmd { + args := []string{"init", command} + cmd := exec.Command("/proc/self/exe", args...) + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWNS | + syscall.CLONE_NEWNET | syscall.CLONE_NEWIPC, + } + + if tty { + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + } + + return cmd +} diff --git a/internal/container/run.go b/internal/container/run.go new file mode 100644 index 0000000..aa0f1b3 --- /dev/null +++ b/internal/container/run.go @@ -0,0 +1,35 @@ +package container + +import ( + "os" + "syscall" + "upod/internal/log" +) + +// RunContainerInitProcess 启动容器的init进程 +/* +这里的init函数是在容器内部执行的,也就是说,代码执行到这里后,容器所在的进程其实就已经创建出来了, +这是本容器执行的第一个进程。 +使用mount先去挂载proc文件系统,以便后面通过ps等系统命令去查看当前进程资源的情况。 +*/ +func RunContainerInitProcess(command string, args []string) error { + var ( + err error + ) + + log.Debug("RunContainerInitProcess: command=%s args=%v", command, args) + + syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "") + + defaultMountFlags := syscall.MS_NOEXEC | syscall.MS_NOSUID | syscall.MS_NODEV + + _ = syscall.Mount("proc", "/proc", "proc", uintptr(defaultMountFlags), "") + + argv := []string{command} + + if err = syscall.Exec(command, argv, os.Environ()); err != nil { + return err + } + + return nil +} diff --git a/internal/log/log.go b/internal/log/log.go new file mode 100644 index 0000000..d9cf4c7 --- /dev/null +++ b/internal/log/log.go @@ -0,0 +1,19 @@ +package log + +import ( + "os" + + "github.com/sirupsen/logrus" + "github.com/spf13/cast" +) + +func init() { + if cast.ToBool(os.Getenv("UPOD_DEBUG")) { + logrus.SetLevel(logrus.DebugLevel) + } + +} + +func Debug(msg string, args ...any) { + logrus.Debugf(msg, args...) +} diff --git a/main.go b/main.go new file mode 100644 index 0000000..11daa5b --- /dev/null +++ b/main.go @@ -0,0 +1,10 @@ +package main + +import ( + "context" + "upod/internal/cmd" +) + +func main() { + cmd.Start(context.TODO()) +}