Docker 镜像是松散连接的只读层的集合,每个层由一个或多个文件组成。下图显示了一个有 5 层的镜像。
Docker 负责堆叠各层,并将它们表示为一个统一的对象。
有几种方法可以查看和检查组成镜像的图层。事实上,我们在前面拉取镜像时就看到了一种方法。下面的示例将详细介绍镜像拉取操作。
上面输出中以 " Pull complete "结尾的每一行都代表镜像中被绘制的图层。如下图所示,该图像有 5 个图层,图层 ID 如图 所示。
另一种查看镜像层的方法是使用 docker inspect 命令检查镜像(如何使用 Docker Inspect 命令-CSDN博客)。下面的示例检查了同一个 ubuntu:latest 镜像。
修剪后的输出再次显示 5 层。只不过这次显示的是它们的 SHA256 哈希值。
docker inspect 命令是查看镜像细节的好方法。(如何使用 Docker Inspect 命令-CSDN博客)
docker history 命令是检查镜像和查看层数据的另一种方法。不过,它显示的是镜像的构建历史,而不是最终镜像中的严格图层列表。例如,某些 Dockerfile 指令("ENV"、"EXPOSE"、"CMD "和 "ENTRYPOINT")会向镜像添加元数据,但不会创建层。
所有 Docker 镜像都是从基础层开始的,随着更改的进行和新内容的添加,会在基础层上添加新的层。
请看下面这个过于简单的示例:构建一个简单的 Python 应用程序。您可能有一项公司政策,要求所有应用程序都基于 Ubuntu 22:04 官方镜像。这将是你的映像的基础层。添加 Python 软件包将在基础层上添加第二层。如果你随后添加了源代码文件,这些文件将作为附加层添加。最终的图像将有三个图层,如下图所示(请记住,这是一个过于简化的示例,仅供演示)。
重要的是要明白,在添加其他图层时,镜像始终是所有图层按添加顺序堆叠的组合。以图 下所示的两个镜像为例。每个图层有 3 个文件,但整个镜像有 6 个文件,因为它是两个图层的组合。
Docker 采用的存储驱动程序负责堆叠各层,并将它们显示为单一的统一文件系统/镜像。Linux 上的存储驱动程序包括 overlay2、devicemapper、btrfs 和 zfs。正如它们的名字所示,每个驱动程序都基于 Linux 文件系统或块设备技术,并且每个驱动程序都有自己独特的性能特点。无论使用哪种存储驱动程序,用户体验都是一样的。
共享镜像图层
多个镜像可以共享图层。这可以提高空间和性能效率。下面的示例显示了带有 -a 标志的 docker pull 命令的输出。该命令可用于下载版本库中的所有镜像。该命令有其局限性,如果版本库中有多个平台和架构的镜像,如 Linux 和 Windows,或 amd64 和 arm64,则该命令可能会失败。
注意以 "Already exists "结尾的行。
这几行文字告诉我们,Docker 很聪明,它能识别出什么时候会被要求拉取它已经有本地副本的镜像层。在这个例子中,Docker 首先调用了标记为latest的镜像。然后,当它拉取 v1 和 v2 镜像时,它发现自己已经拥有了组成这些镜像的某些层。出现这种情况是因为该版本库中的三个镜像几乎完全相同,因此共享了许多层。事实上,v1 和 v2 之间唯一的区别就是顶层。
如前所述,Linux 上的 Docker 支持多种存储驱动程序。每种驱动都可以自由地以自己的方式实现镜像分层、层共享和写时复制(CoW)行为。不过,最终结果和用户体验都是一样的。
以上步骤,并没有解释每个docker命令的含义,是比较基础的操作,如果您对以上的命令不太熟悉,可以参考我的docekr课程,有对各类命令的详细讲解:Docker 实战_在线视频教程-CSDN程序员研修院