什么是 docker 镜像
Docker 镜像是 Docker 容器的基础组件,它包含了运行一个应用程序所需的一切,包括代码、运行时环境、系统工具、库和依赖等。Docker 镜像的本质,可以分为以下几个方面来解释。
- 文件系统层:Docker 镜像是由多个文件系统层(Filesystem Layers)组成的。每个层都是只读的,并且包含了文件和目录的变更。这种分层的文件系统结构使得镜像的构建和复用变得非常高效。每个层只需要存储差异部分,大大减小了镜像的体积。
- 只读性:Docker 镜像是只读的,一旦创建就不能被修改。当需要修改一个镜像时,Docker 会在原有的镜像上创建一个新的镜像,这个新镜像会包含原有镜像的所有层,并在其基础上添加新的层。
- 分层存储:Docker 镜像的文件系统采用分层存储的方式。这意味着多个镜像可以共享同一个文件系统层,从而节省存储空间。当多个容器同时运行时,它们可以共享相同的基础镜像,只需在其基础上添加自己的可写层。
- 镜像的构建与复用:Docker 镜像的构建是通过 Dockerfile 文件来定义的。Dockerfile 中包含了一系列构建指令,用于描述如何从基础镜像中构建一个新的镜像。这种构建方式使得镜像的构建过程可自动化,并且易于复用和共享。
从操作系统原理角度来看,Docker 镜像可以从操作系统原理角度来看,Docker 镜像可以类比为操作系统中的文件系统快照。一个 Docker 镜像可以看作是一个只读的文件系统快照,它包含了应用程序运行所需的所有文件和目录。每个镜像层都相当于文件系统中的一个增量变更,它们按照层级的方式进行组织,使得镜像的构建和复用更加高效。
类似于操作系统中的进程,Docker 容器是基于镜像创建的运行实体。当创建一个 Docker 容器时,Docker 会在镜像的基础上添加一层可写的文件系统层,这个层称为容器层。容器层可以进行读写操作,而镜像层是只读的,这样就实现了镜像的复用和容器的隔离。
镜像相关命令
docker pull
# 用法docker pull [OPTIONS] NAME[:TAG|@DIGEST]OPTIONS 说明:
- -a : 拉取所有 tagged 镜像
- –disable-content-trust : 忽略镜像的校验,默认开启
- -q: 可简化拉取过程中的日志输出。
除此之外,docker pull 也可通过镜像的 digest 进行拉取。语法格式为 docker pull <repository>@<digest>。
digest,是镜像内容的一个 Hash 值,即所谓的 Content Hash(内容散列)。只要镜像内容发生了变更,其内容散列值就一定会发生改变。注意,digest 是包含前面的 sha256 的,表示该 digest 的产生所采用的 Hash 算法是 SHA256。

docker images
# 用法docker images [OPTIONS] [REPOSITORY[:TAG]]OPTIONS 说明:
-
-a : 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);
-
–digests : 显示镜像的摘要信息;

-
-f : 显示满足条件的镜像;
使用 reference 作为筛选条件

在使用 reference 时可以使用通配符
*进行筛选。需要注意的是,reference 只能筛选经过认证的镜像,未经过认证的镜像即使满足条件也不会被筛选。使用 before 作为筛选条件

-f before 用于列举出本地镜像中指定镜像创建时间之前创建的所有镜像。
使用 since 作为筛选条件

-f since 用于列举出本地镜像中指定镜像创建时间之后的创建的所有镜像。
-
–format : 指定返回值的模板文件;

{{ }}里面的内容与 Go 语言的模板语法一样。
-
–no-trunc : 显示完整的镜像信息;

默认的 docker images 显示的镜像 id 是经过截取后的显示结果,仅显示了前 12 位。使用 --no-trunc 参数后显示的是完整的镜像 id。
-
-q : 只显示镜像 ID。

docker search
# 用法docker search [OPTIONS] TERMOPTIONS 说明:
- –limit: 对结果进行数量限制;
- –format: 指定返回值的模板文件;
- –no-trunc : 显示完整的镜像描述;
- -f <过滤条件>: 列出收藏数大于指定值的镜像。
从 Docker Hub 查找所有镜像名包含 zookeeper,并且收藏数大于 10 的镜像。

参数说明:
-
NAME: 镜像仓库源的名称
-
DESCRIPTION: 镜像的描述
-
OFFICIAL: 是否 docker 官方发布
-
STARTS: 类似 Github 里面的 star,表示点赞、喜欢的意思。
-
AUTOMATED: 自动构建。
AUTOMATED 表示当前镜像是否是“自动化镜像”。什么是自动化镜像?就是使用 Docker Hub 连接一个包含 Dockerfile 文件(专门构建镜像用的文件)的 GitHub 仓库或 Bitbucket 仓库的源码托管平台,然后 Docker Hub 就会自动根据 Dockerfile 内容构建镜像。这种构建出的镜像会被标记为 AUTOMATED,这种构建镜像的方式称为 Trusted Build(受信构建)。只要 Dockerfile 文件内容发生变化,那么 Docker Hub 就会构建出新的镜像。
docker rmi
基本使用
rmi,remove images。该命令用于删除指定的本地镜像。镜像通过

删除多个镜像
docker rmi 命令可一次性删除多个镜像,多个要删除的镜像间使用空格分隔。

通过 ImageID 删除镜像

强制删除镜像
默认情况下,对于已经运行了容器的镜像是不能删除的,必须要先停止并删除了相关容器然后才能删除其对应的镜像。不过,也可以通过添加-f 选项进行强制删除。

删除所有镜像
使用组合命令删除所有镜像。当然,如果不携带-f 选项,则不会删除已打开容器的镜像。
# 命令[root@centos ~]#docker rmi -f $(docker images -q)导出 / 导入镜像
导出镜像 save
docker save -o "导出的文件名" "多个镜像名,用空格分隔"
导入镜像 load
docker load 用于将一个 tar 文件导入并加载为一个或多个镜像。
docker load -i "要导入的tar文件"
镜像分层
当构建一个 Docker 镜像时,Docker 会将镜像分解为多个文件系统层,每个层都是只读的,并且包含了文件和目录的变更。这种分层的文件系统结构使得镜像的构建和复用变得非常高效。

上面的示意图展示了一个由 3 个扩展镜像层和一个基础镜像层组成的 Docker 镜像。在基础镜像层之上的镜像层称为扩展镜像层。顾名思义,其是对基础镜像层功能的扩展。
在 Dockerfile 中,每条指令都是用于完成某项特定功能的,而每条指令都会生成一个扩展镜像层。
当创建一个新的 Docker 容器时,Docker 会在只读层(扩展镜像层)的基础上添加一个可写层,这个可写层会包含容器运行时所需的文件和目录变更。这样,多个容器就可以共享同一个基础镜像层和多个只读层。分层存储的优势在于镜像的复用和共享。如果有多个镜像使用了相同的基础镜像层,它们可以共享这个基础层,只需在其基础上添加自己的可写层。这样就可以大大减小镜像的体积,并提高镜像的构建和复用效率。

在上面的示意图中,Docker 镜像的分层存储通过联合文件系统来实现。可写层是容器运行时的一部分,用于存储容器运行时的变更和数据。只读层包含了基础镜像的内容,它们是只读的,并且可以被多个容器共享。
需要注意的是,这里的分层并不是物理上的分层,而是逻辑上的分层。在底层实现上,Docker 使用了联合文件系统(UnionFS)来实现镜像的分层存储。联合文件系统是一种特殊的文件系统,它可以将多个不同的文件系统层合并为一个单一的文件系统。在 Docker 中,常用的联合文件系统有 AUFS、OverlayFS 和 DeviceMapper 等。
镜像摘要
Docker 镜像摘要是镜像内容的唯一标识符,它是通过对镜像二进制数据进行哈希运算生成的。摘要可以确保所引用的映像在整个生命周期中始终是相同的。如果镜像内容发生改变,即使名字和标签相同,摘要也会发生改变。
在 docker pull 镜像结束后会给出该拉取的镜像的摘要 digest。并且通过 docker images --digests 命令也可以查看到镜像的摘要信息。

镜像摘要的作用
摘要的主要作用是区分相同<repository>:<tag>的不同镜像。
例如某个镜像在生产运行过程中发现存在一个 BUG。现对其进行了修复,并使用原标签将其 push 回了仓库,那么原镜像被覆盖。但生产环境中遗留了大量运行中的修复前镜像的容器。此时,通过镜像标签已经无法区分镜像是修复前的还是修复后的了,因为它们的标签是相同的。此时通过查看镜像的 digest 就可以区分出修改前后版本,因为内容发生了变化,digest 一定会变。为了确保再次拉取到的是修复后的镜像,可通过 digest 进行镜像拉取。其用法是:docker pull <repository>@<digest>
分发散列值
在 push 或 pull 镜像时,都会对镜像进行压缩以减少网络带宽和传输时长。但压缩会改变镜像内容,会导致经过网络传输后,镜像内容与其 digest 不相符。为了避免该问题,Docker 又为镜像配置了 Distribution Hash(分发散列值)。在镜像被压缩后立即计算分发散列值,然后使该值随压缩过的镜像一同进行发送。在接收方接收后,立即计算压缩镜像的分发散列值,再与携带的分发散列值对比。如果相同,则说明传输没有问题。