【发布时间】:2020-09-24 08:32:01
【问题描述】:
我正在学习容器,尤其是 docker。我刚刚观看了这个 Liz Rice 视频,其中她从头开始创建了一个容器(repo 在 github.com/lizrice)。我无法完全遵循它,因为我是 Docker 和容器的新手,而且我不懂 Go 编程语言。但是,我想看看是否有人可以非常快速地解释代码中的这些项目是/试图完成什么:
package main
import (
"fmt"
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
)
// go run main.go run <cmd> <args>
func main() {
switch os.Args[1] {
case "run":
run()
case "child":
child()
default:
panic("help")
}
}
func run() {
fmt.Printf("Running %v \n", os.Args[2:])
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 child() {
fmt.Printf("Running %v \n", os.Args[2:])
cg()
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
must(syscall.Sethostname([]byte("container")))
must(syscall.Chroot("/home/liz/ubuntufs"))
must(os.Chdir("/"))
must(syscall.Mount("proc", "proc", "proc", 0, ""))
must(syscall.Mount("thing", "mytemp", "tmpfs", 0, ""))
must(cmd.Run())
must(syscall.Unmount("proc", 0))
must(syscall.Unmount("thing", 0))
}
func cg() {
cgroups := "/sys/fs/cgroup/"
pids := filepath.Join(cgroups, "pids")
os.Mkdir(filepath.Join(pids, "liz"), 0755)
must(ioutil.WriteFile(filepath.Join(pids, "liz/pids.max"), []byte("20"), 0700))
// Removes the new cgroup in place after the container exits
must(ioutil.WriteFile(filepath.Join(pids, "liz/notify_on_release"), []byte("1"), 0700))
must(ioutil.WriteFile(filepath.Join(pids, "liz/cgroup.procs"), []byte(strconv.Itoa(os.Getpid())), 0700))
}
func must(err error) {
if err != nil {
panic(err)
}
}
特别是,我对容器的理解是,它是一个虚拟化的运行时环境,用户可以在其中将应用程序与底层系统隔离开来,并且容器只是在单个主机上运行的隔离进程组,它们满足一组“共同特征。我很清楚容器是什么,并试图在更广泛的意义上完成,但我想帮助理解这样一个具体的例子。如果有人很好地理解这一点 - 导入块中正在导入什么;主要功能中的情况是什么; run 函数中的语句有什么用,child 和 cg 函数正在完成什么?
我认为以我目前的理解和阅读 Docker 教程,加上一个从头开始的真实代码示例的解释将非常有益。只是为了确认一下 - 此代码与 Docker 本身无关,代码创建容器之外,Docker 是一种使创建容器更容易的技术。
【问题讨论】:
-
我在想,这段代码是否以某种方式提供了依赖项或库,或者以某种方式(如 API)向操作系统提供这些项目的访问权限?
-
如果你想了解你必须学习Go的代码(从围棋之旅开始),问“在导入块中导入了什么是没有意义的[?]”。 Liz 的谈话非常好,并且更详细地解释了 main 的作用和原因,比在 SO 上可以回答更好。试图通过阅读您无法阅读的代码来理解容器,因为您不了解语言以及 Linux 的工作原理是没有意义的。
-
我不是想学习 Go 或 Linux——我只是想从一个实际的代码示例中学习——为了创建一个容器而实现了什么。我从初学者教程和阅读文章/教程中了解容器,但如果有人可以提供代码的简要解释并将其连接到容器完成的任务 - 我认为这将巩固我的(以及其他人学习容器和 Docker 等)理解无比。我不是在询问语法,而是想了解正在实现的内容以及它如何从代码中转换
标签: docker go containers