为了账号安全,请及时绑定邮箱和手机立即绑定

Container From Scratch 的解释

Container From Scratch 的解释

Go
catspeake 2022-06-06 18:03:30
我正在学习容器和码头工人。我刚刚观看了这个 Liz Rice 视频,其中她从头开始创建了一个容器(repo 在 github.com/lizrice)。我无法完全遵循它,因为我是 Docker 和容器的新手,而且我不懂 Go 编程语言。但是,我想看看是否有人可以非常快速地解释代码中的这些项目是/试图完成的内容:package mainimport (    "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))}特别是,我对容器的理解是,它是一个虚拟化的运行时环境,用户可以在其中将应用程序与底层系统隔离开来,而容器只是运行在单个主机上的隔离进程组,它们实现了一组“通用”特征。我很清楚容器是什么,并试图在更广泛的意义上完成,但我希望帮助理解这样的具体示例。如果有人很好地理解这一点 - 导入块中正在导入什么;主要功能中的情况是什么;run 函数中的语句有什么用,child 和 cg 函数正在完成什么?我认为以我目前的理解和阅读 Docker 教程,加上一个从头开始的真实代码示例的解释将非常有益。只是为了确认 - 此代码与 Docker 本身无关,除了代码创建容器之外,Docker 是一种使创建容器更容易的技术。
查看完整描述

2 回答

?
千万里不及你

TA贡献1784条经验 获得超9个赞

她正在通过这样做来创建一种容器:

  • 她将执行 main.go 并传递要在容器中执行的命令

  • 为此,她运行了一个执行 run() 函数的进程

  • 在 run() 函数中,她准备了一个要分叉的进程,该进程将执行 child() 函数

  • 但在实际分叉之前,通过 syscall.SysProcAttr,她配置了一个新的命名空间:

    • “unix 分时”(syscall.CLONE_NEWUTS)这本质上将允许在子进程中有一个单独的主机名

    • PIDs (syscall.CLONE_NEWPID) 这样在她正在创建的“容器”中,她将拥有从 1 开始的新 PID

    • mounts (syscall.CLONE_NEWNS) 将使“容器”拥有单独的挂载

  • 接下来她执行 fork (cmd.Run())

在分叉的进程中,child() 函数在这里执行:

  • 她通过 cg() 准备了一个控制组,它将限制“容器”可用的资源,这是通过在 /sys/fs/cgroup/ 中编写一些适当的文件来完成的

  • 接下来,她使用传递给 main.go 的 args 准备要执行的命令

  • 她使用 chroot 到 /home/liz/ubuntufs 下的新根目录

  • 她monuts特殊fs proc和另一个临时fs

  • 最后,她执行作为参数提供给 main.go 的命令

在从头开始的视频容器中,她很好地呈现了这一切。在那里,她在容器中执行了一个 bash,该容器看到了新的 PID,有一个新的主机名,并且限制为 20 个进程。

为了让它工作,她需要在 /home/liz/ubuntufs 下有一个完整的 ubuntu fs 克隆。

要带回家的 3 个关键点是容器(以及她的“容器”)本质上是这样做的:

  • 使用命名空间来定义容器将看到的 PID/挂载(在这个容器示例中她没有处理网络)

  • 使用 chroot 将容器限制为文件系统的一部分

  • 使用 cgroups 来限制容器可以使用的资源


查看完整回答
反对 回复 2022-06-06
?
天涯尽头无女友

TA贡献1831条经验 获得超9个赞

由于我缺乏 GO 经验以及对自定义 docker 容器的经验有限,我无法确认此代码的作用。

虽然这不是直接回答标题中的问题,但我想提供一个答案,帮助您学习 docker 的基础知识以帮助您入门。

你对容器的理解是正确的。尝试查找使用您熟悉的语言的更简单示例的教程。

一个让您入门的简单示例是创建一个您喜欢的 linux 操作系统的容器,将 docker 容器附加到您当前的终端,然后在容器中运行一些特定于操作系统的命令(例如在容器中安装软件或任何 linux 命令)


查看完整回答
反对 回复 2022-06-06
  • 2 回答
  • 0 关注
  • 185 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号