docker 镜像

标签:Docker首次发布:2024-01-19最近修改:2026-08-20

什么是 docker 镜像

Docker 镜像是 Docker 容器的基础组件,它包含了运行一个应用程序所需的一切,包括代码、运行时环境、系统工具、库和依赖等。Docker 镜像的本质,可以分为以下几个方面来解释。

  1. 文件系统层:Docker 镜像是由多个文件系统层(Filesystem Layers)组成的。每个层都是只读的,并且包含了文件和目录的变更。这种分层的文件系统结构使得镜像的构建和复用变得非常高效。每个层只需要存储差异部分,大大减小了镜像的体积。
  2. 只读性:Docker 镜像是只读的,一旦创建就不能被修改。当需要修改一个镜像时,Docker 会在原有的镜像上创建一个新的镜像,这个新镜像会包含原有镜像的所有层,并在其基础上添加新的层。
  3. 分层存储:Docker 镜像的文件系统采用分层存储的方式。这意味着多个镜像可以共享同一个文件系统层,从而节省存储空间。当多个容器同时运行时,它们可以共享相同的基础镜像,只需在其基础上添加自己的可写层。
  4. 镜像的构建与复用:Docker 镜像的构建是通过 Dockerfile 文件来定义的。Dockerfile 中包含了一系列构建指令,用于描述如何从基础镜像中构建一个新的镜像。这种构建方式使得镜像的构建过程可自动化,并且易于复用和共享。

从操作系统原理角度来看,Docker 镜像可以从操作系统原理角度来看,Docker 镜像可以类比为操作系统中的文件系统快照。一个 Docker 镜像可以看作是一个只读的文件系统快照,它包含了应用程序运行所需的所有文件和目录。每个镜像层都相当于文件系统中的一个增量变更,它们按照层级的方式进行组织,使得镜像的构建和复用更加高效。

类似于操作系统中的进程,Docker 容器是基于镜像创建的运行实体。当创建一个 Docker 容器时,Docker 会在镜像的基础上添加一层可写的文件系统层,这个层称为容器层。容器层可以进行读写操作,而镜像层是只读的,这样就实现了镜像的复用和容器的隔离。

镜像相关命令

docker pull

bash
# 用法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

bash
# 用法docker images [OPTIONS] [REPOSITORY[:TAG]]

OPTIONS 说明:

  • -a : 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);

  • –digests : 显示镜像的摘要信息;

    bash
    [root@centos ~]# docker images --digests nginxREPOSITORY   TAG       DIGEST                                                                    IMAGE ID       CREATED       SIZEnginx        latest    sha256:8541484afbc9c8a5a8a99b379568ebbc957f658583ec9448fc43104229c03cf8   5253dc86cc93   2 weeks ago   161MB
  • -f : 显示满足条件的镜像;

    使用 reference 作为筛选条件

    bash
    [root@centos ~]# docker images -f reference=*centos*REPOSITORY      TAG       IMAGE ID       CREATED          SIZEcentos          latest    5d0da3dc9764   24 months ago    231MB

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

    使用 before 作为筛选条件

    bash
    [root@centos ~]# docker imagesREPOSITORY    TAG       IMAGE ID       CREATED         SIZEnginx         latest    5253dc86cc93   2 weeks ago     161MBredis         latest    7614ae9453d1   20 months ago   113MBhello-world   latest    e2ac70e7319a   4 months ago    10.1kBcentos        latest    5d0da3dc9764   24 months ago   231MBi386/centos   latest    fe70670fcbec   4 years ago     201MB[root@centos ~]# docker images -f before=hello-worldREPOSITORY    TAG       IMAGE ID       CREATED         SIZEcentos        latest    5d0da3dc9764   24 months ago   231MBi386/centos   latest    fe70670fcbec   4 years ago     201MB

    -f before 用于列举出本地镜像中指定镜像创建时间之前创建的所有镜像。

    使用 since 作为筛选条件

    bash
    [root@centos ~]# docker images -f since=hello-worldREPOSITORY    TAG       IMAGE ID       CREATED         SIZEnginx         latest    5253dc86cc93   2 weeks ago     161MBredis         latest    7614ae9453d1   20 months ago   113MB

    -f since 用于列举出本地镜像中指定镜像创建时间之后的创建的所有镜像。

  • –format : 指定返回值的模板文件;

    bash
    [root@centos ~]# docker images --format {{.Repository}}:{{.Tag}}:{{.Size}}nginx:latest:161MBredis:latest:113MBhello-world:latest:10.1kBcentos:latest:231MBi386/centos:latest:201MB

    {{ }}里面的内容与 Go 语言的模板语法一样。

  • –no-trunc : 显示完整的镜像信息;

    bash
    [root@centos ~]# docker images --no-truncREPOSITORY     TAG       IMAGE ID                                                                  CREATED         SIZEnginx          latest    sha256:5253dc86cc93ac6249902934655c6f7c959d8caa45a8c2ecc0b95953834d8ee8   20 months ago   141MBredis          latest    sha256:7614ae9453d1d87e740a2056257a6de7135c84037c367e1fffa92ae922784631   20 months ago   113MBhello-world    latest    sha256:e2ac70e7319a02c5a477f5825259bd118b94e8b02c279c67afa63adab6d8685b   23 months ago   13.3kBcentos         latest    sha256:5d0da3dc976460b72c77d94c8a1ad043720b0416bfc16c52c45d4847e53fadb6   24 months ago   231MBi386/centos    latest    sha256:fe70670fcbec5e3b3081c6800cb531002474c36563689b450d678a34a89b62c3   4 years ago     201MB

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

  • -q : 只显示镜像 ID。

    bash
    [root@centos ~]# docker images -q605c77e624dd7614ae9453d1feb5d9fea6a55d0da3dc9764fe70670fcbec
bash
# 用法docker search [OPTIONS] TERM

OPTIONS 说明:

  • –limit: 对结果进行数量限制;
  • –format: 指定返回值的模板文件;
  • –no-trunc : 显示完整的镜像描述;
  • -f <过滤条件>: 列出收藏数大于指定值的镜像。

从 Docker Hub 查找所有镜像名包含 zookeeper,并且收藏数大于 100 的镜像。

bash
[root@centos ~]# docker search -f stars=100 zookeeperNAME                 DESCRIPTION                                     STARS     OFFICIAL   AUTOMATEDzookeeper            Apache ZooKeeper is an open-source server wh…   1382      [OK]jplock/zookeeper     Builds a docker image for ZooKeeper version    165                  [OK]

参数说明:

  • 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。该命令用于删除指定的本地镜像。镜像通过:指定。如果省略要删除镜像的 tag,默认删除的是 lastest 版本。

bash
[root@centos ~]# docker rmi mysqlUntagged: mysql:latest

删除多个镜像

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

bash
[root@centos ~]# docker rmi i386/centos redisUntagged: i386/centos:latestUntagged: i386/centos@sha256:1f832b4e3b9ddf67fd77831cdfb591ce5e968548a01581672e5f6b32ce1212feDeleted: sha256:fe70670fcbec5e3b3081c6800cb531002474c36563689b450d678a34a89b62c3Deleted: sha256:5cc80fd33358c1d86ead3fb68953e05a2f9aa347976e114533a2ac0fc63ee9c1Untagged: redis:latestUntagged: redis@sha256:db485f2e245b5b3329fdc7eff4eb00f913e09d8feb9ca720788059fdc2ed8339Deleted: sha256:7614ae9453d1d87e740a2056257a6de7135c84037c367e1fffa92ae922784631Deleted: sha256:49c70179bc923a7d48583d58e2b6c21bde1787edf42ed1f8de9e9b96e2e88e65Deleted: sha256:396e06df5d1120368a7a8a4fd1e5467cdc2dd4083660890df078c654596ddc1cDeleted: sha256:43dd118df2e9edb51238f6ba46e9efdfa21be68e88f54787531aa39a720a0740Deleted: sha256:2047f09c412ff06f4e2ee8a25d105055e714d99000711e27a55072e640796294Deleted: sha256:13d71c9ccb39b206211dd1900d06aa1984b0f5ab8abaa628c70b3eb733303a65

通过 ImageID 删除镜像

bash
[root@centos ~]# docker imagesREPOSITORY    TAG       IMAGE ID       CREATED         SIZEnginx         latest    5253dc86cc93   2 weeks ago     161MBmysql         5         c20987f18b13   20 months ago   448MBhello-world   latest    e2ac70e7319a   4 months ago    10.1kBcentos        latest    5d0da3dc9764   24 months ago   231MB[root@centos ~]# docker rmi 5253dc86cc93Untagged: nginx:latestUntagged: nginx@sha256:8541484afbc9c8a5a8a99b379568ebbc957f658583ec9448fc43104229c03cf8Deleted: sha256:5253dc86cc93ac6249902934655c6f7c959d8caa45a8c2ecc0b95953834d8ee8Deleted: sha256:2093f6af8b4c20ebd42365a9db9b331d55affe451d4bb514dc95eba4c979a719Deleted: sha256:ff945a2e0a5b9adff7c0fd652b649108e74e4ef04a07cd20048235e9cbd804d8Deleted: sha256:7f65ec5f0d380792b695678900b7a1f4bdbdbe200f1a5cc0513d5f8117ff3ddbDeleted: sha256:efa73b088942f96f6a2ececfe476a33ee6916ad2b48c13d2f43d53dc19bd33eeDeleted: sha256:2c9fd29062e2b1f7b34690934c77a3cb18362c6f612245e03034dba9a7b5e450Deleted: sha256:eaff11d1d08134415ef386b5eaba32488a456eeed60227a6ea280d5a94346f3eDeleted: sha256:6f94328331290cbd81edab450664d42da7b64c191416c9346cd5d28c84f76035

强制删除镜像

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

bash
[root@centos ~]# docker rmi hello-worldError response from daemon: conflict: unable to remove repository reference "hello-world" (must force) - container 19d24f04dbf3 is using its referenced image e2ac70e7319a[root@centos ~]# docker rmi -f hello-worldUntagged: hello-world:latestUntagged: hello-world@sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243ccDeleted: sha256:e2ac70e7319a02c5a477f5825259bd118b94e8b02c279c67afa63adab6d8685b

删除所有镜像

使用组合命令删除所有镜像。当然,如果不携带-f 选项,则不会删除已打开容器的镜像。

bash
# 语法[root@centos ~]#docker rmi -f $(docker images -q)

导出 / 导入镜像

导出镜像 save

bash
# 语法docker save -o "导出的文件名" "多个镜像名,用空格分隔"# 实践[root@centos ~]# docker imagesREPOSITORY    TAG       IMAGE ID       CREATED         SIZEmysql         5         c20987f18b13   20 months ago   448MBcentos        latest    5d0da3dc9764   24 months ago   231MB[root@centos ~]# docker save -o mysql_centos.tar mysql:5 centos[root@centos ~]# ll mysql_centos.tar-rw-------. 1 root root 692306432 9月   6 19:30 mysql_centos.tar

导入镜像 load

docker load 用于将一个 tar 文件导入并加载为一个或多个镜像。

bash
# 语法docker load -i "要导入的tar文件"# 实践[root@centos ~]# docker imagesREPOSITORY    TAG        IMAGE ID     CREATED    SIZE[root@centos ~]# docker load -i mysql_centos.tarad6b69b54919: Loading layer [==============================]fba7b131c5c3: Loading layer [==============================]......

镜像分层

当构建一个 Docker 镜像时,Docker 会将镜像分解为多个文件系统层,每个层都是只读的,并且包含了文件和目录的变更。这种分层的文件系统结构使得镜像的构建和复用变得非常高效。

read_only_image_layers

上面的示意图展示了一个由 3 个扩展镜像层和一个基础镜像层组成的 Docker 镜像。在基础镜像层之上的镜像层称为扩展镜像层。顾名思义,其是对基础镜像层功能的扩展。

在 Dockerfile 中,每条指令都是用于完成某项特定功能的,而每条指令都会生成一个扩展镜像层。

当创建一个新的 Docker 容器时,Docker 会在只读层(扩展镜像层)的基础上添加一个可写层,这个可写层会包含容器运行时所需的文件和目录变更。这样,多个容器就可以共享同一个基础镜像层和多个只读层。分层存储的优势在于镜像的复用和共享。如果有多个镜像使用了相同的基础镜像层,它们可以共享这个基础层,只需在其基础上添加自己的可写层。这样就可以大大减小镜像的体积,并提高镜像的构建和复用效率。

docker_shared_image_layers

在上面的示意图中,Docker 镜像的分层存储通过联合文件系统来实现。可写层是容器运行时的一部分,用于存储容器运行时的变更和数据。只读层包含了基础镜像的内容,它们是只读的,并且可以被多个容器共享。

需要注意的是,这里的分层并不是物理上的分层,而是逻辑上的分层。在底层实现上,Docker 使用了联合文件系统(UnionFS)来实现镜像的分层存储。联合文件系统是一种特殊的文件系统,它可以将多个不同的文件系统层合并为一个单一的文件系统。在 Docker 中,常用的联合文件系统有 AUFS、OverlayFS 和 DeviceMapper 等。

镜像摘要

Docker 镜像摘要是镜像内容的唯一标识符,它是通过对镜像二进制数据进行哈希运算生成的。摘要可以确保所引用的映像在整个生命周期中始终是相同的。如果镜像内容发生改变,即使名字和标签相同,摘要也会发生改变。

在 docker pull 镜像结束后会给出该拉取的镜像的摘要 digest。并且通过 docker images --digests 命令也可以查看到镜像的摘要信息。

bash
[root@centos ~]# docker pull hello-worldUsing default tag: latestlatest: Pulling from library/hello-world4f55086f7dd0: Already exists Digest: sha256:5dd0d3e6e255913fc30f90b9f2b1d359cc2cbdb48090cc4b65f1676e203243ccStatus: Downloaded newer image for hello-world:latestdocker.io/library/hello-world:latest

镜像摘要的作用

摘要的主要作用是区分相同<repository>:<tag>的不同镜像。

例如某个镜像在生产运行过程中发现存在一个 BUG。现对其进行了修复,并使用原标签将其 push 回了仓库,那么原镜像被覆盖。但生产环境中遗留了大量运行中的修复前镜像的容器。此时,通过镜像标签已经无法区分镜像是修复前的还是修复后的了,因为它们的标签是相同的。此时通过查看镜像的 digest 就可以区分出修改前后版本,因为内容发生了变化,digest 一定会变。为了确保再次拉取到的是修复后的镜像,可通过 digest 进行镜像拉取。其用法是:docker pull <repository>@<digest>

分发散列值

在 push 或 pull 镜像时,都会对镜像进行压缩以减少网络带宽和传输时长。但压缩会改变镜像内容,会导致经过网络传输后,镜像内容与其 digest 不相符。为了避免该问题,Docker 又为镜像配置了 Distribution Hash(分发散列值)。在镜像被压缩后立即计算分发散列值,然后使该值随压缩过的镜像一同进行发送。在接收方接收后,立即计算压缩镜像的分发散列值,再与携带的分发散列值对比。如果相同,则说明传输没有问题。

Comments

评论区将在滚动到这里时加载。