内容简介:要使用 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/img
、 Buildah
以及 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"
上述过程是个极度简化的过程,其中缺乏一些常见指令,例如 ENTRYPOINT
、 ENV
等。这些内容会被写入元数据,和文件层封装在一起。
结论
这种将根文件系统和每个差异层都进行打包的思路非常强大。它不仅是 Docker 的基础,我想还能用在其它一些领域里,以后可能会诞生更多这类工具。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- [译] 理想数据科学家的画像是什么样的?
- NeurIPS「提前拒稿」直接刷掉11%,投稿人质疑:像是为了完成KPI随机分配的理由
- CodeTengu Weekly 碼天狗週刊 - Issue 88 除錯就像是推理劇,你擔任偵探,同時也是兇手 - May 15t...
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。