加入收藏 | 设为首页 | 会员中心 | 我要投稿 济南站长网 (https://www.0531zz.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 站长资讯 > 动态 > 正文

正在重塑IT的5种方式

发布时间:2021-02-20 15:00:36 所属栏目:动态 来源:互联网
导读:首先,我们通过调用 createContainerID() 创建唯一的容器 ID。然后,我们调用 downloadImageIfRequired(),以便可以从Docker Hub 下载容器镜像(如果本地尚不可用)。Gocker 使用 /var/run/gocker/containers 中的子目录来挂载容器根文件系统。createContain

首先,我们通过调用 createContainerID() 创建唯一的容器 ID。然后,我们调用 downloadImageIfRequired(),以便可以从Docker Hub 下载容器镜像(如果本地尚不可用)。Gocker 使用 /var/run/gocker/containers 中的子目录来挂载容器根文件系统。createContainerDirectories() 会解决这个问题。mountOverlayFileSystem() 知道如何处理多层 Docker 镜像,并在 /var/run/gocker/containers/<container-id>/fs/mnt 上为可用镜像安装合并的文件系统。尽管这看起来令人生畏,但如果您阅读源代码,这并不难理解。覆盖(Overlay)文件系统允许您创建一个堆叠的文件系统,其中较低的层(在这种情况下是 Docker 根文件系统)是只读的,而任何更改都将保存到 “upperdir”,而无需更改较低层中的任何文件。这允许许多容器共享一个 Docker 镜像。当我们在虚拟机上下文中说“镜像”时,它通常是指磁盘镜像。但是在这里,它只是一个目录或一组目录(奇特的名字:layers),带有构成 Docker “镜像”根文件系统的文件,可以使用 Overlay 文件系统挂载该文件来创建根文件系统一个新的容器。

接下来,我们创建一个虚拟的以太网配对设备,它非常类似于调用 setupVirtualEthOnHost() 的管道。它们采用名称 veth0_ <container-id> 和 veth1_ <container-id> 的形式。我们将一对中的 veth0 部分连接到主机上的网桥 gocker0。稍后,我们将在容器内部使用该对的 veth1 部分。它们就像管道一样,是从具有自己的网络命名空间的容器内部进行网络通信的秘钥。随后,我们将介绍如何在容器内设置 veth1 部件。

最后,调用 prepareAndExecuteContainer(),它实际上在容器中执行该过程。当此函数返回时,容器已完成执行。最后,我们进行一些清理并退出。让我们看看 prepareAndExecuteContainer() 的作用。它实际上创建了我们看到的日志的 3 个进程,并使用 setup-netns,setup-veth 和 child-mode 参数运行相同的 gocker 二进制文件。

设置可在容器内工作的网络

设置新的网络命名空间非常容易。您只需将 CLONE_NEWNET 包含在传递给 clone() 系统调用的标志位掩码中即可。棘手的是确保容器内部可以具有网络接口,通过该接口可以与外部进行通信。在 Gocker 中,我们创建的第一个新命名空间是网络的命名空间。当使用 setup-ns 和 setup-veth 参数调用 gocker 时会发生这种情况。首先,我们设置一个新的网络命名空间。setns() 系统调用可以将调用进程的命名空间设置为由文件描述符所引用的命名空间,该文件描述符指向 /proc/<pid>/ns 中的文件,该文件列出了进程所属的所有命名空间。让我们看一下 setupNewNetworkNamespace() 函数,该函数是通过使用 setup-netns 作为参数调用 gocker 而被调用的。(译注:即上文提到的 Cmd args: [/proc/self/exe setup-netns 33c20f9ee600] )


 

在这里,我们要求 Gocker 从 Alpine Linux 镜像运行 shell。稍后我们将了解如何管理镜像(Image)。现在,请注意以 “ Cmd args:” 开头的日志行。此行表示产生了一个新进程。第一行日志向我们显示了由于运行 Gocker 命令而使 shell 程序启动的过程。但是,到最后,我们看到了另外三个进程。最后一个是带有参数 “child-mode” 的 /bin/sh,我们在 Alpine Linux 镜像中使用它。在此之前,我们看到其他两个进程分别带有参数 “setup-netns” 和 “setup-veth”。这些命令设置了一个新的网络命名空间,并设置了一个虚拟以太网设备对的容器端,使容器分别与外界通信。

由于各种原因,Go 语言不直接支持 fork() 系统调用。我们通过创建一个新进程来解决此限制,但是要在其中再次执行当前程序。/proc/self/exe 指向当前正在运行的可执行文件的路径。我们根据命令行传递不同的命令行参数来调用适当的函数(当在子进程中 fork() 返回时将调用该函数)。

源代码的组织

Gocker 源代码通过命令(如参数)组织在文件中。例如,主要服务于 gocker run 命令行参数的函数位于 run.go 文件中。类似地,gocker exec 主要需要的功能在 exec.go 文件中。这并不意味着这些文件是独立的。它们从其他文件中自由调用函数。还有一些文件可以实现通用功能,例如 cgroups.go 和 utils.go。

运行容器

在 main.go[17] 中,您可以看到是否运行了 Gocker 命令,我们检查以确保 gocker0 桥接器已启动并正在运行。否则,我们通过调用完成工作的 setupGockerBridge() 来启动它。最后,我们调用函数 initContainer(),该函数在 run.go 中实现。让我们仔细看看该函数:


 

在 syscall.SysProcAttr 中,我们可以传入 Cloneflags,然后将其传递给对 clone() 系统调用。细心的读者会注意到,我们不在这里设置单独的网络命名空间。在 Gocker 中,我们设置了一个虚拟以太网接口,将其添加到新的网络命名空间,并使用另一个 Linux 系统调用使容器加入该命名空间。我们将在后面讨论。

使用 unshare() 创建和加入新的命名空间

如果要为现有进程创建新的命名空间,则不必使用 clone() 创建新的子进程,Linux 提供了 unshare()[15] 系统调用。

加入其他进程所属的命名空间

为了加入文件引用的命名空间或加入其他进程所属的命名空间,Linux 提供了setns()[16] 系统调用。我们将很快看到,这非常有用。

Gocker 如何创建容器

由于 Gocker 的主要目的是帮助理解 Linux 容器,因此保留了一些来自 Gocker 的日志消息。从这个意义上讲,它比运行 Docker 更为冗长。让我们看一下日志,以指导我们执行程序。然后,我们可以进行深入分析,看看实际情况如何:



 

(编辑:济南站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!