(译)镜像是怎样炼成的

栏目: IT技术 · 发布时间: 4年前

内容简介:要使用 Docker,就不可避免地要和 Docker 镜像打交道。本文将会讲述 Docker 镜像的基石: Overlay 文件系统。首先我会简单介绍一下这个文件系统,接下来会看看如何把这个技术用在 Docker 镜像上,以及 Docker 是怎样从 Dockerfile 构建出 Docker 镜像的。最后还会介绍分层缓存以及 OCI 格式的容器镜像。遵循我的一贯风格,我会尽可能的让本文具备更好的操作性。Overlay 文件系统(也被称为联合文件系统),能够使用两个或更多的目录创建一个联合:它由低层和高层的

要使用 Docker,就不可避免地要和 Docker 镜像打交道。本文将会讲述 Docker 镜像的基石: Overlay 文件系统。首先我会简单介绍一下这个文件系统,接下来会看看如何把这个技术用在 Docker 镜像上,以及 Docker 是怎样从 Dockerfile 构建出 Docker 镜像的。最后还会介绍分层缓存以及 OCI 格式的容器镜像。

遵循我的一贯风格,我会尽可能的让本文具备更好的操作性。

Overlay 文件系统是什么

Overlay 文件系统(也被称为联合文件系统),能够使用两个或更多的目录创建一个联合:它由低层和高层的目录组成。文件系统中低层的目录是只读的,而高层的文件系统则是可读可写的。我们可以试试加载一个,看看操作效果。

创建 Overlay 文件系统

我们可以创建几个目录然后把它们联合起来。首先会创建一个叫做 “mount” 的目录,我们将它作为这个联合的父目录。接下来会创建 “layer-1”、“layer-2”、“layer-3”、“layer-4” 着几个目录。最后还要创建一个叫做 “workdir” 的目录, Overlay 文件系统必须有这个目录才能正常工作。

这些目录可以随意命名,不过 “layer-1”、“layer-2” 这样的命名方式,和 Docker 镜像对比起来会比较容易理解。

$ cd /tmp && mkdir overlay-example && cd overlay-example

[2020-04-19 16:02:35] [ubuntu] [/tmp/overlay-example]  
> mkdir mount layer-1 layer-2 layer-3 layer-4 workdir

[2020-04-19 16:02:38] [ubuntu] [/tmp/overlay-example]  
$ ls
layer-1  layer-2  layer-3  layer-4 mount  workdir

然后要在除 “layer-4” 之外的每个目录下创建文件,这个步骤也不是必要的,只是为了更像镜像:

[2020-04-19 16:02:40] [ubuntu] [/tmp/overlay-example]  
$ echo "Layer-1 file" > ./layer-1/some-file-in-layer-1

[2020-04-19 16:03:36] [ubuntu] [/tmp/overlay-example]  
$ echo "Layer-2 file" > ./layer-2/some-file-in-layer-2

[2020-04-19 16:03:53] [ubuntu] [/tmp/overlay-example]  
$ echo "Layer-3 file" > ./layer-3/some-file-in-layer-3

我们来挂载这个文件系统:

sudo mount -t overlay overlay-example \
-o lowerdir=/tmp/overlay-example/layer-1:/tmp/overlay-example/layer-2:/tmp/overlay-example/layer-3,upperdir=/tmp/overlay-example/layer-4,workdir=/tmp/overlay-example/workdir \
/tmp/overlay-example/mount

看看挂载目录的内容:

[2020-04-19 16:13:28] [ubuntu] [/tmp/overlay-example]  
> cd mount/

[2020-04-19 16:13:31] [ubuntu] [/tmp/overlay-example/mount]  
> ls -la
total 20
drwxr-xr-x 1 napicell domain^users 4096 Apr 19 16:07 .
drwxr-xr-x 8 napicell domain^users 4096 Apr 19 16:07 ..
-rw-r--r-- 1 napicell domain^users   13 Apr 19 16:03 some-file-in-layer-1
-rw-r--r-- 1 napicell domain^users   13 Apr 19 16:03 some-file-in-layer-2
-rw-r--r-- 1 napicell domain^users   13 Apr 19 16:03 some-file-in-layer-3

不出所料,前三层的文件都被加载到了挂载根目录。可以看到我们之前写入文件的内容:

$ cat some-file-in-layer-3
Layer-3 file

试试创建文件

$ echo "new content" > new-file

$ ls
new-file  some-file-in-layer-1  some-file-in-layer-2  some-file-in-layer-3

新文件在哪里呢?自然是在上层,我们的例子里就是 “layer-4”:

[2020-04-19 16:23:49] [ubuntu] [/tmp/overlay-example]  
 pactvm > tree
.
├── layer-1
│   └── some-file-in-layer-1
├── layer-2
│   └── some-file-in-layer-2
├── layer-3
│   └── some-file-in-layer-3
├── layer-4
│   └── new-file
├── mount
│   ├── new-file
│   ├── some-file-in-layer-1
│   ├── some-file-in-layer-2
│   └── some-file-in-layer-3
└── workdir
    └── work [error opening dir]

7 directories, 8 files

试试看删除文件:

[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
new-file  some-file-in-layer-1  some-file-in-layer-3

你猜猜,原始文件系统中的 “layer-2” 目录会怎么样:

[2020-04-19 16:29:57] [ubuntu] [/tmp/overlay-example]  
 pactvm > tree
.
├── layer-1
│   └── some-file-in-layer-1
├── layer-2
│   └── some-file-in-layer-2
├── layer-3
│   └── some-file-in-layer-3
├── layer-4
│   ├── new-file
│   └── some-file-in-layer-2
├── mount
│   ├── new-file
│   ├── some-file-in-layer-1
│   └── some-file-in-layer-3
└── workdir
    └── work [error opening dir]

7 directories, 8 files

“layer-4” 中出现了个新文件 “some-file-in-layer-2”。奇怪的是这个文件的属性(”Character file“),这种文件在 Overlay 文件系统中被称为 ”Whitout“,用于表达被删除的文件。

[2020-04-19 16:31:09] [ubuntu] [/tmp/overlay-example/layer-4]  
 pactvm > ls -la
total 12
drwxr-xr-x 2 napicell domain^users 4096 Apr 19 16:28 .
drwxr-xr-x 8 napicell domain^users 4096 Apr 19 16:07 ..
-rw-r--r-- 1 napicell domain^users   12 Apr 19 16:23 new-file
c--------- 1 root     root         0, 0 Apr 19 16:28 some-file-in-layer-2

完成之后,卸载这个文件系统,然后删除目录:

[2020-04-19 16:37:11] [ubuntu] [/tmp/overlay-example]  
$ sudo umount /tmp/overlay-example/mount && rm -rf *

理顺概念

正如开篇所说, Overlay 文件系统上可以把多个目录联合在一起。在前边的例子里,这个联合过程由 “layer-{1,2,3,4}” 在  “mount” 目录里组成。对文件的修改、创建和删除都在上层发生——也就是这里的 “layer-4”,因此这一层也被称为差异层。上层的文件会对下层文件造成遮盖。假设 “layer-2” 和 “layer-1” 中,在相同的相对目录下有同名的文件,那么在 “mount” 目录中就会以 “layer-2” 为准。下一节将会看看这一技术在 Docker 镜像中的应用。

什么是 Docker 镜像

简单总结,Docker 镜像就是一个 Tar 文件,其中包含一个根文件系统和一些愿数据。你可能听说过,Dockerfile 中的每一行都会生成一个层。例如下面的代码就会生成一个三层的镜像:

FROM scratch
ADD my-files /doc
ADD hello /
CMD ["/hello"]

“docker run” 的过程很复杂,但是本文中只会关注和镜像有关的一点点内容。概括的说,Docker 会下载这个文件包,把每个层解压到单独的目录中,然后用 Overlay 文件系统将这些目录以及用于进行写入的一个上层空目录联合起来。当你在容器中进行修改、创建或者删除操作时,这些变更都会保存到这个空目录中。容器退出时,Docker 会清理这个目录——这就是在容器中的变更无法保持的原因。

层缓存

要运行容器,就要构建镜像,Docker 将这两个步骤分离开来独立运作,是它得以流行的重要原因。OCI 就是业界公认的规范。

OCI 当前包括两个规范:运行规范和镜像规范。运行规范描述了如何运行一个解压到磁盘上的 “复合文件系统” 。简单说来,OCI 实现会把 OCI 镜像下载回来,然后解压到一个 OCI 运行时复合文件系统之中。这一操作完成后就可以让 OCI 运行时运行了。

标准化的意义就是让其他人可以自己开发容器的构建 工具 和运行时。例如 jess/imgBuildah 以及 Skopeo 都是可以脱离 Docker 构建镜像的工具。类似地还有很多容器运行时,例如 runc(Docker 使用) 和 rkt。

## 其他的 Overlay 文件系统

Docker 能够使用的联合文件系统不止这一种。任何有差异层和联合特性的文件系统都是可能的候选者。例如 Docker 还能运行在 aufs、btrfs、zfs 和 devicemapper 系统上。

构建镜像时发生了什么

假设我们要使用下面的 Dockerfile 来构建镜像:

FROM ubuntu
RUN apt-get update
...

简单描述一下这个过程:

RUN: chroot . /bin/bash -c "apt get update"

上述过程是个极度简化的过程,其中缺乏一些常见指令,例如 ENTRYPOINTENV 等。这些内容会被写入元数据,和文件层封装在一起。

结论

这种将根文件系统和每个差异层都进行打包的思路非常强大。它不仅是 Docker 的基础,我想还能用在其它一些领域里,以后可能会诞生更多这类工具。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

面向对象技术UML教程

面向对象技术UML教程

王少峰 / 清华大学出版社 / 2004-2 / 24.00元

《面向对象技术UML教程》主要介绍统一建模语言UML及其应用。全书内容丰富,包括UML的用例图、顺序图、协作图、类图、对象图、状态图、活动图、构件图和部署图等9个图中所涉及的术语、规则和应用,以及数据建模、OCL、业务建模、Web建模、设计模式、OO实现语言、RUP等方面的内容,同时介绍了Rose开发工具中的一些用法。《面向对象技术UML教程》最后是一个课程注册系统的实例研究,以及一些思考题和设计......一起来看看 《面向对象技术UML教程》 这本书的介绍吧!

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具