镜像、Docker 镜像、容器镜像 和 OCI 镜像 都指的是同一种东西。它是一个只读的包,包含了运行应用程序所需的一切。它包括应用程序代码、依赖项、最小的 OS 构造以及可以用来启动一个或多个容器的元数据。开发者可以将它们视为类似于类。你可以从一个类创建一个或多个对象——你可以从一个镜像创建一个或多个容器。
你也可以将镜像视为停止的容器。实际上,你可以停止一个容器并从它创建一个新的镜像。考虑到这一点,镜像是在构建时创建的,而容器是在运行时创建的。
你通过从 注册表 中 拉取 容器镜像。最常见的注册表是 Docker Hub。拉取 操作会将镜像下载到你的本地 Docker 主机,在该主机上 Docker 可以使用该镜像启动一个或多个容器。
让我们深入探讨容器的整个目的是运行一个单一的应用程序或服务。这意味着它只需要运行该应用程序的代码和依赖项,不需要其他任何东西。这也就意味着镜像是小巧的,并且去除了所有非必需的部分。
例如,Alpine Linux 镜像大小为 5MB。这是因为它没有包含 6 种不同的 shell、三个不同的包管理器和其他对我们应用程序来说“不必要的”东西。
镜像中不包含内核。这是因为容器会与运行它们的主机共享内核。镜像中通常只包含一些重要的文件系统组件和其他基本构建块,这也是为什么你有时会听到人们说“镜像中只包含足够的操作系统组件”。
在Linux主机上的本地镜像仓库通常位于 /var/lib/docker/<storage-driver>。Docker镜像是由一组松散连接的只读层组成的,每一层包含一个或多个文件。
Docker 负责将各层堆叠起来,并将它们表示为一个单一的统一对象。有几种方法可以查看和检查构成一个镜像的各层。
$ docker pull ubuntu:latest
latest: 正在从 library/ubuntu 拉取
952132ac251a: 拉取完成
82659f8f1b76: 拉取完成
c19118ca682d: 拉取完成
8296858250fe: 拉取完成
24e0251a0e2c: 拉取完成
Digest: sha256:f4691c96e6bbaa99d...28ae95a60369c506dd6e6f6ab
状态: 下载了更新的 ubuntu:latest 镜像
docker.io/ubuntu:latest
每一行以“Pull complete”结尾的输出都代表了一个被拉取的镜像层。
另一种查看镜像层次结构的方法是使用 docker inspect 命令来检查镜像,这是一个查看镜像详细信息的好方法。所有 Docker 镜像都以一个基础层开始,随着更改的进行和新内容的添加,新的层次会叠加在上面。重要的是要理解,随着额外层次的添加,镜像始终是按添加顺序堆叠的所有层次的组合。
更多关于层的内容Docker 使用存储驱动程序来负责将各层叠加并呈现为单一的统一文件系统/镜像。Linux 上的存储驱动程序示例包括 overlay2、devicemapper、btrfs 和 zfs。正如它们的名字所暗示的,每个驱动程序都基于一种 Linux 文件系统或块设备技术,并且每个驱动程序都有自己独特的性能特性。无论使用哪种存储驱动程序,用户的体验都是一样的。
多个镜像可以并且确实会共享层。这导致了空间和性能上的效率提升。Docker 足够智能,能够识别出当被要求拉取一个它已经本地拥有的层时。
镜像的摘要Docker 支持内容可寻址存储模型。作为该模型的一部分,所有镜像都会获得一个加密的 内容哈希。我们将这个哈希称为 摘要。由于摘要是对镜像内容的哈希值,因此无法在不生成新的唯一摘要的情况下更改镜像的内容。这意味着你不能更改镜像的内容并保留旧的摘要。这表示摘要具有不可变性。
每次你拉取一个镜像时,docker pull
命令会将该镜像的摘要作为返回信息的一部分。你也可以通过在 docker images
命令中添加 —digests 标志来查看 Docker 主机本地仓库中镜像的摘要。例如:
docker images --digests alpine
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
alpine latest sha256:0a4eaa0eecf5f8c050e5bba433f58c052be7587ee8af3e8b3910ef9ab5fbe9f5 0b4426ad4bf2 12 天前 8.83MB
现在我们知道了镜像的摘要,当我们再次拉取镜像时可以使用它。这将确保我们获得预期的确切镜像!
多架构镜像幸运的是,有一种巧妙的方法来支持多架构镜像。这意味着像 golang:latest 这样的单个镜像可以为 x64 架构的 Linux、PowerPC 架构的 Linux、Windows x64、不同版本的 ARM 架构的 Linux 等提供镜像。说得更清楚一点,我们说的是一个镜像标签支持多个平台和架构。我们马上会看到它的实际应用,这意味着你可以从任何平台或架构运行简单的 docker pull golang:latest 命令,Docker 会拉取正确的镜像。
为了实现这一点,Registry API 支持两个重要的构造:
- 配置列表
- 配置文件
清单列表正是听起来的样子:一个由特定镜像标签支持的架构列表。每个支持的架构都有自己的清单,列出了用于构建它的各层。
左边是包含每个架构条目的清单列表。箭头表明清单列表中的每个条目都指向一个包含镜像配置和层数据的清单。
假设你在 Raspberry Pi(ARM 上的 Linux)上运行 Docker。当你拉取一个镜像时,Docker 会向 Docker Hub 发出相应的请求。如果该镜像存在一个清单列表(manifest list),则会解析该清单列表以查看是否包含针对 Linux ARM 的条目。如果存在,将会获取并解析针对 Linux ARM 的镜像清单,以获取每一层的加密 ID。然后,每一层将从 Docker Hub 拉取并组装到 Docker 主机上。
docker manifest inspect alpine | grep 'architecture\|os'
"architecture": "amd64",
"os": "linux"
"architecture": "arm",
"os": "linux",
"architecture": "arm",
"os": "linux",
"architecture": "arm64",
"os": "linux",
"architecture": "386",
"os": "linux"
"architecture": "ppc64le",
"os": "linux"
"architecture": "riscv64",
"os": "linux"
"architecture": "s390x",
"os": "linux"
感谢阅读。👏 并订阅以获取更多文章! 🖥️
来源:[什么是镜像? | Docker 文档]
Nigel Poulton 的 Docker Deep Dive
共同學習,寫下你的評論
評論加載中...
作者其他優質文章