Docker镜像是如何构建的? 覆盖文件系统研究

2021-01-01 08:11:43

没有docker镜像的docker容器是不可能的。在这篇文章中,我想谈谈使docker映像成为可能的原因:覆盖文件系统。我将从覆盖文件系统的简要说明开始。然后,我们将了解它如何应用于docker映像以及docker如何从dockerfile生成映像。我将以容器图像的图层缓存和OCI格式结束。

像往常一样,我将尽量使该博客文章实用。

覆盖文件系统(也称为联合文件系统)允许创建两个或更多目录的联合:下层目录列表和上层目录。文件系统的下部目录是只读的,而上部目录可用于读取和写入。

让我们创建一些文件夹并将其合并。首先,我将创建一个名为“ mount”的文件夹,其中将包含所有其他文件夹的并集。然后,我将创建一堆名为“ layer-1”,“ layer-2”,“ layer-3”,“ layer-4”的文件夹。最后,覆盖文件系统需要一个名为“ workdir”的文件夹才能正常工作。您可以随意调用任何文件夹,但是将它们称为“ layer-1”,“ layer-2”等将使我们更容易理解与docker镜像的相似之处。 cd / tmp&& mkdir overlay-example&& cd overlay-example

[2020-04-19 16:02:35] [ubuntu] [/ tmp / overlay-example]> mkdir挂载第1层第2层第3层第4层工作目录[2020-04-19 16:02:38] [ubuntu] [/ tmp / overlay-example]> ls 1层2层3 3层4挂载工作目录

我们还要在1层,2层和3层文件夹中创建一些文件。我们将第4层(我们的上层文件夹)留空。同样,这不是必须的,这只会使我们与docker镜像的并行变得更容易。

[2020-04-19 16:02:40] [ubuntu] [/ tmp / overlay-example]>回显"第1层文件" > ./layer-1/some-file-in-layer-1 [2020-04-19 16:03:36] [ubuntu] [/ tmp / overlay-example]>回显"第2层文件" > ./layer-2/some-file-in-layer-2 [2020-04-19 16:03:53] [ubuntu] [/ tmp / overlay-example]>回显"第3层文件" > ./layer-3/some-file-in-layer-3

与预期的一样,第1层,第2层和第3层文件夹的内容已被安装/合并在mount文件夹中。当然,如果我们查看文件的内容,就会发现我们在上一步中编写的内容。

[2020-04-19 16:23:31] [ubuntu] [/ tmp / overlay-example / mount]>回显"新内容" >新文件[2020-04-19 16:27:33] [ubuntu] [/ tmp / overlay-example / mount]> ls新文件一些文件在第1层一些文件在第2层一些文件在第3层

新文件应该在哪里?在上层,在我们的例子中是名为“ layer-4”的文件夹:

[2020-04-19 16:23:49] [ubuntu] [/ tmp / overlay-example] pactvm>树。 ├──第1层│└──第1层有文件├──第2层│└──第2层有文件├──第3层│└──某些-第3层文件├──第4层│└──新文件├──安装│├──新文件│├──某些文件在第1层│├──某些-文件层2│└──某些文件层3└──workdir└──work [错误打开目录] 7个目录,8个文件

[2020-04-19 16:27:33] [ubuntu] [/ tmp / overlay-example / mount]> rm some-file-in-layer-2 [2020-04-19 16:28:58] [ubuntu] [/ tmp / overlay-example / mount]> ls新文件第1层的某些文件第3层的一些文件

您认为“ layer-2”文件夹中的原始文件发生了什么?

[2020-04-19 16:29:57] [ubuntu] [/ tmp / overlay-example] pactvm>树。 ├──第1层│└──第1层有文件├──第2层│└──第2层有文件├──第3层│└──某些-第3层文件├──第4层│├──新文件│└──某些文件在第2层├──挂载│├──新文件│├──某些-文件层1│└──某些文件层3└──workdir└──work [错误打开目录] 7个目录,8个文件

在“第4层”中创建了一个名为“ some-file-in-layer-2”的新文件。奇怪的是文件是字符文件。这些类型的文件称为“白化”文件,它们是覆盖文件系统表示要删除的文件的方式:

[2020-04-19 16:31:09] [ubuntu] [/ tmp / overlay-example / layer-4] pactvm> ls -la总共12个drwxr-xr-x 2个napicell domain ^ users 4096 Apr 19 16:28。 drwxr-xr-x 8个napicell域^用户4096 Apr 19 16:07 .. -rw-r--r-- 1个napicell域^用户19 Apr 19 16:23新文件c -------- -1 root root 0,0 Apr 19 16:28 some-file-in-layer-2

现在我们已经完成了它,让我们卸载文件系统并删除我们创建的文件夹:

正如我们在一开始所说的,覆盖文件系统允许创建目录的并集。在我们的例子中,联合是在“ mount”文件夹中创建的,这是合并“ layer- {1、2、3、4}”文件夹的结果。对文件的更改,删除或创建将存储在上层目录中,在本例中为“第4层”。这就是为什么该层也称为“差异”层的原因。较高层的文件会遮盖较低层的文件,即,如果您在第1层和第2层中具有相同名称和相对路径的文件,则第2层文件将最终位于“ mount”文件夹中。

泊坞窗映像本质上是一个具有根文件系统和一些元数据的tar文件。您可能已经听说过表达式图像层,并且docker文件中的每一行都会创建一个新层。例如,在下面的代码片段中,我们将获得一个包含三层的图像。

因此,当您键入“ docker run”时会发生什么。确实有很多事情,但是出于本文的目的,我们只对与图像有关的位感兴趣。在较高级别上,docker下载该映像的tarball,将每个层解压缩到一个单独的目录中,然后告诉覆盖文件系统将它们全部组合在一起,并在一个空的上层目录中,容器将对其进行更改。当您更改,创建或删除容器中的文件时,更改将存储在此空目录中。当容器退出时,docker会清理文件夹-这就是为什么您在容器中所做的更改不会持久的原因。

这种使用覆盖文件系统的方式使主机可以有效地缓存docker映像。例如,如果定义两个图像,则它们都可以使用相同的图层。无需多次下载或在磁盘上拥有许多副本!

高级别运行容器可以看成两个步骤:构建映像和从映像运行容器。 docker的流行使人们说服人们将这两个步骤标准化–允许两个部分分别发展。开放容器倡议(OCI)是一直与业界合作达到这些标准的治理。

OCI当前包含两个规范:运行时规范(runtime-spec)和映像规范(image-spec)。运行时规范概述了如何运行在磁盘上解压缩的“文件系统包”。在较高级别上,OCI实现将下载OCI映像,然后将该映像解压缩为OCI运行时文件系统包。此时,OCI运行时捆绑包将由OCI运行时运行。

标准化允许其他人开发自定义容器构建器和运行时。例如,jessfraz / img,buildah和Skopeo都是使您无需使用docker即可构建容器映像的工具。同样,出现了许多运行容器的工具(所谓的容器运行时),例如runc(由docker使用)和rkt。

覆盖不是docker可以使用的唯一联合文件系统。允许使用类似联合功能和差异层的任何文件系统都可以使用。例如,泊坞窗可以使用我们已经看到的覆盖,还可以使用aufs,btrfs,zfs和devicemapper。

假设我们要使用以下dockerfile来构建映像:

Docker下载“ FROM”中指定的映像的压缩包并解压缩。这是图像的第一层。

挂载一个联合文件系统,其较低的目录为刚刚下载的目录。上层目录是一个空文件夹

在chroot中启动bash并运行RUN中指定的命令:chroot。 / bin / bash -c“易于获取更新”

命令结束后,它将压缩上一层。这是我们正在构建的图像的新层

如果dockerfile包含其他命令,请从第二步开始使用到目前为止到目前为止所有已使用的层作为下层目录重复该过程。否则退出。

当然,这是简化的工作流程,它没有考虑不同类型的命令,例如“ ENV”,“ ENTRYPOINT”等。这些内容存储在元数据文件中,该文件将与图层捆绑在一起。

事实证明,将整个根文件系统压缩在tar中并为每个diff层保留tar的想法非常强大。它不仅启用了docker,而且事实证明它是可以在其他上下文中使用的概念。我想,将来我们会看到更多利用此工具的工具。

在Twitter上关注我,以在您的供稿中获取新帖子。封面图片应归功于unsplash-logo坦率的mckenna。