Docker(三)镜像

Docker(三)镜像

第一节 Docker镜像

1.1 简介

  如果读者之前曾经是VM管理员,则可以把Docker镜像理解为VM模板,VM模板就像停止运行的VM,而Docker镜像就像停止运行的容器; 如果读者是一名研发人员,可以将镜像理解为(Class)。

  需要先从镜像仓库服务中拉取镜像。常见的镜像仓库服务是Docker Hub,但是也存在其他镜像仓库服务。拉取操作会将镜像下载到本地Docker主机,可以使用该镜像启动一个或者多个容器。

  镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包。因为容器的设计初衷就是快速和小巧,所以镜像通常都比较小。


1.2 详解

  前面多次提到镜像就像停止运行的容器(类)。实际上,我们可以停止某个容器的运行,并从中创建新的镜像。所以镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构。

1.2.1 镜像和容器

  通常使用docker container run和docker service create命令从某个镜像启动一个或多个容器。一旦容器从镜像启动后,二者之间就变成了互相依赖的关系,并且在镜像上启动的容器全部停止之前,镜像是无法被删除的。尝试删除镜像而不停止或销毁使用它的容器,会导致下面的错误。

1
2
3
4
5
$ docker image rm 
Error response from daemon: conflict: unable to remove repository referenc
e \
"" (must force) - container is using its referenc\
ed image

1.2.2 镜像通常比较小

  容器目的就是运行应用或者服务,这意味着容器的镜像中必须包含应用/服务运行所必需的操作系统和应用文件。但是,容器又追求快速和小巧,这意味着构建镜像的时候通常需要裁剪掉不必要的部分,保持较小的体积。例如,Docker镜像通常不会包含6个不同的Shell让用户选择——通常Docker镜像中只有一个精简的Shell,甚至没有Shell。镜像中还不包含内核——容器都是共享所在Docker主机的内核。所以有时会说容器仅包含必要的操作系统(通常只有操作系统文件和文件系统对象)。Hyper-V容器运行在专用的轻量级VM上,同时利用VM内部的操作系统内核。

  Windows镜像要比Linux镜像大一些,这与Windows OS工作原理相关。比如,未压缩的最新Microsoft .NET镜像 (microsoft/dotnet:latest)超过1.7GB。Windows Server 2016 Nano Server镜像(microsoft/nanoserver:latest)在拉取并解压后,其体积略大于1GB。

1.2.3 拉取镜像

  Docker主机安装之后,本地并没有镜像。Linux Docker主机本地镜像仓库通常位于/var/lib/docker/<storage-driver>,Windows Docker主机则是C:\ProgramData\docker\windowsfilter。可以使用以下命令检查Docker主机的本地仓库中是否包含镜像。

1
2
$ docker image ls 
REPOSITORY TAG IMAGE ID CREATED SIZE

  将镜像取到Docker主机本地的操作是拉取。通过下面的命令可以将镜像拉取到本地,并观察其大小。

1
2
3
$ docker image pull ubuntu:latest
$ docker image pull alpine:latest
$ docker image ls

1.2.4 镜像仓库服务

  Docker镜像存储在镜像仓库服务(Image Registry)当中。Docker客户端的镜像仓库服务是可配置的,默认使用Docker Hub。镜像仓库服务包含多个镜像仓库(Image Repository)。同样,一个镜像仓库中可以包含多个镜像。图6.2展示了包含3个镜像仓库的镜像仓库服务,其中每个镜像仓库都包含一个或多个镜像。

包含3个镜像仓库的镜像仓库服务

  顾名思义,官方仓库中的镜像是由Docker公司审查的。这意味着其中的镜像会及时更新,由高质量的代码构成,这些代码是安全的,有完善的文档和最佳实践。非官方仓库更像江湖侠客,其中的镜像不一定具备官方仓库的优点,但这并不意味着所有非官方仓库都是不好的!非官方仓库中也有一些很优秀的镜像。用户需要做的是在信任非官方仓库镜像代码之前保持谨慎。

1.2.5 镜像命名和标签

  只需要给出镜像的名字和标签,就能在官方仓库中定位一个镜像(采用“:”分隔)。从官方仓库拉取镜像时,docker image pull命令的格式如下。

1
docker image pull <repository>:<tag>

  在之前的Linux示例中,通过下面的两条命令完成Alpine和Ubuntu镜像的拉取。这两条命令从alpine和ubuntu仓库拉取了标有“latest”标签的镜像。

1
docker image pull alpine:latest docker image pull ubuntu:latest

  首先,如果没有在仓库名称后指定具体的镜像标签,则Docker会假设用户希望拉取标签为latest的镜像。

  其次,标签为latest的镜像不保证这是仓库中最新的镜像。例如,Alpine仓库中最新的镜像通常标签是edge。通常来讲,使用latest标签时需要谨慎!

  从非官方仓库拉取镜像也是类似的,用户只需要在仓库名称面前加上Docker Hub的用户名或者组织名称。下面的示例展示了如何从tudemo仓库中拉取v2这个镜像,其中镜像的拥有者是Docker Hub账户nigelpoulton,一个不应该被信任的账户。

1
2
$ docker image pull nigelpoulton/tu-demo:v2 
//该命令会从以书作者的Docker Hub账号为命名空间的tu-demo库中下载标签为v2的镜像

1.2.6 为镜像打多个标签

  一个镜像可以根据用户需要设置多个标签。这是因为标签是存放在镜像元数据中的任意数字或字符串。

  在docker image pull命令中指定-a参数来拉取仓库中的全部镜像。接下来可以通过运行docker image ls查看已经拉取的镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
$ docker image pull -a nigelpoulton/tu-demo

latest: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Pull complete
a3ed95caeb02: Pull complete
<Snip>
Digest: sha256:42e34e546cee61adb1...3a0c5b53f324a9e1c1aae451e9
v1: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists
<Snip>
Digest: sha256:9ccc0c67e5c5eaae4b...624c1d5c80f2c9623cbcc9b59a
v2: Pulling from nigelpoulton/tu-demo
237d5fcd25cf: Already exists
a3ed95caeb02: Already exists
<Snip>
Digest: sha256:d3c0d8c9d5719d31b7...9fef58a7e038cf0ef2ba5eb74c
Status: Downloaded newer image for nigelpoulton/tu-demo

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE
nigelpoulton/tu-demo v2 6ac21e..bead 1 yr ago 211.6 MB
nigelpoulton/tu-demo latest 9b915a..1e29 1 yr ago 211.6 MB
nigelpoulton/tu-demo v1 9b915a..1e29 1 yr ago 211.6 MB

  刚才发生了如下几件事情:首先,该命令从nigelpoulton/tu-demo仓库拉取了3个镜像:latest、v1以及v2。其次,注意看docker image ls命令输出中的IMAGE ID这一列。可以发现只有两个不同的Image ID。这是因为实际只下载了两个镜像,其中一个镜像拥有两个标签。

  这个示例也完美证明了前文中关于latest标签使用的警告。在本例中,latest标签指向了v1标签的镜像。这意味着latest实际指向了两个镜像中较早的那个版本,而不是最新的版本!latest是一个非强制标签,不保证指向仓库中最新的镜像!

1.2.7 过滤docker image ls的输出内容

 
  Docker提供–filter参数来过滤docker image ls命令返回的镜像列表内容。

  下面的示例只会返回悬虚(dangling)镜像。

1
2
3
$ docker image ls --filter dangling=true 
REPOSITORY TAG IMAGE ID CREATED SIZE
<none> <none> 4fd34165afe0 7 days ago 14.5MB

  那些没有标签的镜像被称为悬虚镜像,在列表中展示为<none>: <none>。通常出现这种情况,是因为构建了一个新镜像,然后为该镜像打了一个已经存在的标签。当此情况出现,Docker会构建新的镜像,然后发现已经有镜像包含相同的标签,接着Docker会移除旧镜像上面的标签,将该标签标在新的镜像之上。

  例如,首先基于alpine:3.4构建一个新的镜像,并打上dodge:challenger标签。然后更新Dockerfile, 将alpine:3.4替换为alpine:3.5,并且再次执行docker image build命令。该命令会构建一个新的镜像,并且标签为dodge:challenger,同时移除了旧镜像上面对应的标签,旧镜像就变成了悬虚镜像。

  可以通过docker image prune命令移除全部的悬虚镜像。如果添加了-a参数,Docker会额外移除没有被使用的镜像(那些没有被任何容器使用的镜像)。

Docker目前支持如下的过滤器:

  • dangling:可以指定true或者false,仅返回悬虚镜像(true),或者非悬虚镜像(false)。
  • before:需要镜像名称或者ID作为参数,返回在之前被创建的全部镜像。
  • since:与before类似,不过返回的是指定镜像之后创建的全部镜 像。
  • label:根据标注(label)的名称或者值,对镜像进行过滤。docker image ls命令输出中不显示标注内容。

  其他的过滤方式可以使用reference。下面就是使用reference完成过滤并且仅显示标签为latest的示例。

1
2
3
4
$ docker image ls --filter=reference="*:latest" 
REPOSITORY TAG IMAGE ID CREATED SIZE
alpine latest 3fd9065eaf02 8 days ago 4.15MB
test latest 8426e7efb777 3 days ago 122MB

  也可以使用–format参数来通过Go模板对输出内容进行格式化。例如,下面的指令将只返回Docker主机上镜像的大小属性。

1
2
3
$ docker image ls --format "{{.Size}}" 
99.3MB
111MB

  使用下面命令返回全部镜像,但是只显示仓库、标签和大小信息。

1
2
3
$ docker image ls --format "{{.Repository}}: {{.Tag}}: {{.Size}}" 
dodge: challenger: 99.3MB
ubuntu: latest: 111MB

  如果需要更复杂的过滤,可以使用OS或者Shell自带的工具,比如Grep或者AWK。

1.2.8 通过CLI方式搜索Docker Hub

  docker search命令允许通过CLI的方式搜索Docker Hub。可以通过“NAME”字段的内容进行匹配,并且基于返回内容中任意列的值进 行过滤。

  简单模式下,该命令会搜索所有“NAME”字段中包含特定字符串的仓库。

1
2
3
4
5
6
7
$ docker search nigelpoulton 
NAME DESCRIPTION STARS AUTOMATED
nigelpoulton/pluralsight.. Web app used in... 8 [OK]
nigelpoulton/tu-demo 7
nigelpoulton/k8sbook Kubernetes Book web app 1
nigelpoulton/web-fe1 Web front end example 0
nigelpoulton/hello-cloud Quick hello-world image 0

  可以使用–filter “is-official=true”,使命令返回内容只显示官方镜像。通过”is-automated=true”只显示自动创建的仓库。

1
2
$ docker search alpine --filter "is-official=true"
$ docker search alpine --filter "is-automated=true"

  默认情况下,Docker只返回25行结果。但是可以指定–limit参数来增加返回内容行数,最多为100行。

1.2.9 镜像和分层

  Docker镜像由一些松耦合的只读镜像层组成。如图6.3所示。

Docker镜像

  Docker负责堆叠这些镜像层,并且将它们表示为单个统一的对象。有多种方式可以查看和检查构成某个镜像的分层,在前面已经展示了其中一种。回顾一下docker image pull ubuntu:latest命令的输出内容。

1
2
3
4
5
6
7
8
9
$ docker image pull ubuntu:latest 
latest: Pulling from library/ubuntu
952132ac251a: Pull complete
82659f8f1b76: Pull complete
c19118ca682d: Pull complete
8296858250fe: Pull complete
24e0251a0e2c: Pull complete
Digest: sha256:f4691c96e6bbaa99d...28ae95a60369c506dd6e6f6ab
Status: Downloaded newer image for ubuntu:latest

  以Pull complete结尾的每一行都代表了镜像中某个被拉取的镜像层。可以看到,这个镜像包含5个镜像层。图6.4以图片形式将镜像层ID作为标识展示了这些分层。

镜像层

  另一种查看镜像分层的方式是通过docker image inspect命令。缩减之后的输出也显示该镜像包含5个镜像层。只不过这次的输出 内容中使用了镜像的SHA256散列值来标识镜像层。不过,两中命令都显示了镜像包含5个镜像层。

  所有的Docker镜像都起始于一个基础镜像层,当进行修改或增加新的内容时,就会在当前镜像层之上,创建新的镜像层。

  举一个简单的例子,假如基于Ubuntu Linux 16.04创建一个新的镜像,这就是新镜像的第一层;如果在该镜像中添加Python包,就会在基础镜像层之上创建第二个镜像层;如果继续添加一个安全补丁,就会创建第三个镜像层。该镜像当前已经包含3个镜像层,如图6.5所示(这只是一个用于演示的很简单的例子)。

基于Ubuntu Linux 16.04创建镜像

  在添加额外的镜像层的同时,镜像始终保持是当前所有镜像的组合。图6.6中举了一个简单的例子,每个镜像层包含3个文件,而镜像包含了来自两个镜像层的6个文件。

添加额外的镜像层后的镜像

  图6.7中展示了一个稍微复杂的三层镜像,在外部看来整个镜像只有6个文件,这是因为最上层中的文件7是文件5的一个更新版本。这种情况下,上层镜像层中的文件覆盖了底层镜像层中的文件。这样就使得 文件的更新版本作为一个新镜像层添加到镜像当中。

三层镜像

  Docker通过存储引擎(新版本采用快照机制)的方式来实现镜像层堆栈,并保证多镜像层对外展示为统一的文件系统。Linux上可用的存储引擎有AUFS、Overlay2、Device Mapper、Btrfs以及ZFS。每种存储引擎都基于Linux中对应的文件系统或者块设备技术,并且每种存储引擎都有其独有的性能特点。

图6.8展示了从系统角度看三层镜像,与系统显示相同的三层镜像。所有镜像层堆叠并合并,对外提供统一的视图。

从系统角度看三层镜像

1.2.10 共享镜像层

  多个镜像之间可以并且确实会共享镜像层。这样可以有效节省空间并提升性能。再回顾一下之前用于拉取nigelpoulton/tu-demo仓库下全部包含标签的docker image pull命令(包含-a参数)。

  注意那些以Already exists结尾的行。由这几行可见,Docker很聪明,可以识别出要拉取的镜像中,哪几层已经在本地存在。在本例中,Docker首先尝试拉取标签为latest的镜像。然后,当拉取标签为v1和v2的镜像时,Docker注意到组成这两个镜像的镜像层,有一部分已经存在了。出现这种情况的原因是前面3个镜像相似度很高,所以共享了很多镜像层。

  Docker在Linux上支持很多存储引擎(Snapshotter)。每个存储引擎都有自己的镜像分层、镜像层共享以及写时复制(CoW)技术的具体实现。但是其最终效果和用户体验是完全一致的。

1.2.11 根据摘要拉取镜像

  到目前为止介绍了如何通过标签来拉取镜像,但问题是标签是可变的!这意味着可能偶尔出现给镜像打错标签的情况,有时甚至会给新镜像打一个已经存在的标签。

  假设镜像golftrack:1.5存在一个已知的Bug。因此可以拉取该镜像后修复它,并使用相同的标签将更新的镜像重新推送回仓库。

  镜像golftrack:1.5存在Bug,这个镜像已经应用于生产环境。如果创建一个新版本的镜像,并修复了这个Bug。那么问题来了,构建新镜像并将其推送回仓库时使用了与问题镜像相同的标签!原镜像被覆盖,但在生产环境中遗留了大量运行中的容器,没有什么好办法区分正在使用的镜像版本是修复前还是修复后的,因为两个镜像的标签是相同的!
是时候轮到镜像摘要(Image Digest)出马了。

  Docker 1.10中引入了新的内容寻址存储模型。作为模型的一部分,每一个镜像现在都有一个基于其内容的密码散列值(后文用摘要代指这个散列值)。因为摘要是镜像内容的一个散列值,所以镜像内容的变更一定会导致散列值的改变。这意味着摘要是不可变的。这种方式可以解决前面讨论的问题。

  每次拉取镜像,摘要都会作为docker image pull命令返回代码的一部分。只需要在docker image ls命令之后添加–digests参数即可在本地查看镜像摘要。

1
2
3
4
5
6
7
8
9
10
$ docker image pull alpine 
Using default tag: latest
latest: Pulling from library/alpine
e110a4a17941: Pull complete
Digest: sha256:3dcdb92d7432d56604d...6d99b889d0626de158f73a
Status: Downloaded newer image for alpine:latest

$ docker image ls --digests alpine
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
alpine latest sha256:3dcd...f73a 4e38e38c8ce0 10 weeks ago 4.8 MB

  从上面的代码片段中可知,Alpine镜像的签名值:sha256:3dcdb92d7432d56604d… 6d99b889d0626de158f73a。

  已知镜像的摘要,可以使用摘要值再次拉取这个镜像,确保准确拉取想要的镜像。截止当前没有原生Docker命令支持从远端镜像仓库服务(如Docker Hub)中获取镜像签名了。这意味着只能先通过标签方式拉取镜像到本地,然后自己维护镜像的摘要列表。

  下面的例子首先在Docker主机上删除alpine:latest镜像,然后显示如何通过摘要(而不是标签)来再次拉取该镜像。

1
2
3
4
5
6
7
8
9
10
11
$ docker image rm alpine:latest 
Untagged: alpine:latest
Untagged: alpine@sha256:c0537...7c0a7726c88e2bb7584dc96
Deleted: sha256:02674b9cb179d...abff0c2bf5ceca5bad72cd9
Deleted: sha256:e154057080f40...3823bab1be5b86926c6f860

$ docker image pull alpine@sha256:c0537...7c0a7726c88e2bb7584dc96
sha256:c0537...7726c88e2bb7584dc96: Pulling from library/alpine
cfc728c1c558: Pull complete
Digest: sha256:c0537ff6a5218...7c0a7726c88e2bb7584dc96
Status: Downloaded newer image for alpine@sha256:c0537...bb7584dc96

1.2.12 镜像散列值(摘要)

  从Docker 1.10版本开始,镜像就是一系列松耦合的独立层的集合。镜像本身就是一个配置对象,其中包含了镜像层的列表以及一些元数据信息。镜像层才是实际数据存储的地方(比如文件等,镜像层之间是完全独立的,并没有从属于某个镜像集合的概念)。

  镜像的唯一标识是一个加密ID,即配置对象本身的散列值。每个镜像层也由一个加密ID区分,其值为镜像层本身内容的散列值。这意味着修改镜像的内容或其中任意的镜像层,都会导致加密散列值的变化。所以,镜像和其镜像层都是不可变的,任何改动都能很轻松地被辨别。这就是所谓的内容散列(Content Hash)。

  在推送和拉取镜像的时候,都会对镜像层进行压缩来节省网络带宽以及仓库二进制存储空间。但是压缩会改变镜像内容,这意味着镜像的内容散列值在推送或者拉取操作之后,会与镜像内容不相符!这显然是个问题。例如,在推送镜像层到Docker Hub的时候,Docker Hub会尝试确认接收到的镜像没有在传输过程中被篡改。为了完成校验,Docker Hub会根据镜像层重新计算散列值,并与原散列值进行比较。因为镜像在传输过程中被压缩(发生了改变),所以散列值的校验也会失败。为避免该问题,每个镜像层同时会包含一个分发散列值 (Distribution Hash)。这是一个压缩版镜像的散列值,当从镜像仓库服务拉取或者推送镜像的时候,其中就包含了分发散列值,该散列值会用于校验拉取的镜像是否被篡改过

  这个内容寻址存储模型极大地提升了镜像的安全性,因为在拉取和推送操作后提供了一种方式来确保镜像和镜像层数据是一致的。该模型也解决了随机生成镜像和镜像层ID这种方式可能导致的ID冲突问题。

1.2.13 多层架构的镜像

  Docker最值得称赞的一点就是使用方便。例如,运行一个应用就像拉取镜像并运行容器这么简单。无须担心安装、依赖或者配置的问题。但是,随着Docker的发展,事情开始变得复杂——尤其是在添加了新平台和架构之后,例如Windows、ARM以及s390x。在拉取镜像并运行之前,需要考虑镜像是否与当前运行环境的架构匹配,这破坏了Docker的流畅体验。

  多架构镜像(Multi-architecture Image)的出现解决了这个问题!

  Docker(镜像和镜像仓库服务)规范目前支持多架构镜像。这意味着某个镜像仓库标签(repository:tag)下的镜像可以同时支持64位 Linux、PowerPC Linux、64位Windows和ARM等多种架构。简单地说,就是一个镜像标签之下可以支持多个平台和架构。

  为了实现这个特性,镜像仓库服务API支持两种重要的结构: Manifest列表(新)和Manifest。Manifest列表是指某个镜像标签支持的架构列表。其支持的每种架构,都有自己的Mainfest定义,其中列举了该镜像的构成。

  图6.9使用Golang官方镜像作为示例。图左侧是Manifest列表,其中包含了该镜像支持的每种架构。Manifest列表的每一项都有一个箭头,指向具体的Manifest,其中包含了镜像配置和镜像层数据。

Golang官方镜像

  在具体操作之前,先来了解一下原理:假设要在Raspberry Pi(基于ARM架构的Linux)上运行Docker。在拉取镜像的时候,Docker客户端会调用Docker Hub镜像仓库服务相应的API完成拉取。如果该镜像有Mainfest列表,并且存在Linux on ARM这一项,则Docker Client就会找到ARM架构对应的Mainfest并解析出组成 该镜像的镜像层加密ID。然后从Docker Hub二进制存储中拉取每个镜像层。

  下面的示例就展示了多架构镜像是如何在拉取官方Golang镜像时工作的,并且通过一个简单的命令展示了Go的版本和所在主机的CPU架构。需要注意的是,两个例子都使用相同的命令 docker container run。不需要告知Docker具体的镜像版本是64位Linux还是64位Windows。示例中只运行了普通的命令,选择当前平台和架构所需的正确镜像版本是有由Docker完成的。

1
2
3
4
5
6
7
8
9
10
$ docker container run --rm golang go version

Unable to find image 'golang:latest' locally
latest: Pulling from library/golang
723254a2c089: Pull complete
<Snip>
39cd5f38ffb8: Pull complete
Digest: sha256:947826b5b6bc4...
Status: Downloaded newer image for golang:latest
go version go1.9.2 linux/amd64

  前面的操作包括从Docker Hub拉取Golang镜像,以容器方式启动,执行go version命令,并且输出Go的版本和主机OS / CPU架构信息。最后一行展示了go version命令的输出内容。

  全面支持各种架构的工作仍在推进当中。创建支持多架构的镜像需要镜像的发布者做更多的工作。同时,某些软件也并非跨平台的。在这个前提下,Manifest列表是可选的——在没有Manifest列表的情况下,镜像仓库服务会返回普通的Manifest。

1.2.14 删除镜像

  当不再需要某个镜像的时候,可以通过docker image rm命令从Docker主机删除该镜像。其中,rm是remove的缩写。

  删除操作会在当前主机上删除该镜像以及相关的镜像层。这意味着无法通过docker image ls命令看到删除后的镜像,并且对应的包含镜像层数据的目录会被删除。但是,如果某个镜像层被多个镜像共享,那只有当全部依赖该镜像层的镜像都被删除后,该镜像层才会被删除。如果被删除的镜像上存在运行状态的容器,那么删除操作不会被允许。再次执行删除镜像命令之前,需要停止并删除该镜像相关的全部容器。

  下面通过镜像ID来删除镜像。

1
2
3
4
$ docker image rm 02674b9cb179 
Untagged: alpine@sha256:c0537ff6a5218...c0a7726c88e2bb7584dc96
Deleted: sha256:02674b9cb179d57...31ba0abff0c2bf5ceca5bad72cd9
Deleted: sha256:e154057080f4063...2a0d13823bab1be5b86926c6f860

  一种删除某Docker主机上全部镜像的快捷方式是在docker image rm命令中传入当前系统的全部镜像ID,可以通过docker image ls获取全部镜像ID(使用-q参数)。如果是在Windows环境中,那么只有在PowerShell终端中执行才会 生效。在CMD中执行并不会生效。

1
$ docker image rm $(docker image ls -q) -f

  为了理解具体工作原理,首先下载一组镜像,然后通过运行docker image ls -q。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ docker image pull alpine 
Using default tag: latest
latest: Pulling from library/alpine
e110a4a17941: Pull complete
Digest: sha256:3dcdb92d7432d5...3626d99b889d0626de158f73a
Status: Downloaded newer image for alpine:latest

$ docker image pull ubuntu
Using default tag: latest
latest: Pulling from library/ubuntu
952132ac251a: Pull complete
82659f8f1b76: Pull complete
c19118ca682d: Pull complete
8296858250fe: Pull complete
24e0251a0e2c: Pull complete
Digest: sha256:f4691c96e6bba...128ae95a60369c506dd6e6f6ab
Status: Downloaded newer image for ubuntu:latest

$ docker image ls -q
bd3d4369aebc
4e38e38c8ce0

  可以看到docker image ls -q命令只返回了系统中本地拉取的全部镜像的ID列表。将这个列表作为参数传给docker image rm会删除本地系统中的全部镜像。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
$ docker image rm $(docker image ls -q) -f 
Untagged: ubuntu:latest
Untagged: ubuntu@sha256:f4691c9...2128ae95a60369c506dd6e6f6ab
Deleted: sha256:bd3d4369aebc494...fa2645f5699037d7d8c6b415a10
Deleted: sha256:cd10a3b73e247dd...c3a71fcf5b6c2bb28d4f2e5360b
Deleted: sha256:4d4de39110cd250...28bfe816393d0f2e0dae82c363a
Deleted: sha256:6a89826eba8d895...cb0d7dba1ef62409f037c6e608b
Deleted: sha256:33efada9158c32d...195aa12859239d35e7fe9566056
Deleted: sha256:c8a75145fcc4e1a...4129005e461a43875a094b93412
Untagged: alpine:latest
Untagged: alpine@sha256:3dcdb92...313626d99b889d0626de158f73a
Deleted: sha256:4e38e38c8ce0b8d...6225e13b0bfe8cfa2321aec4bba
Deleted: sha256:4fe15f8d0ae69e1...eeeeebb265cd2e328e15c6a869f

$ docker image ls
REPOSITORY TAG IMAGE ID CREATED SIZE

1.3 命令

  操作Docker镜像常用到的命令。

  • docker image pull 是下载镜像的命令。镜像从远程镜像仓库服务的仓库中下载。默认情况下,镜像会从Docker Hub的仓库中拉取。docker image pull alpine:latest命令会从Docker Hub的alpine仓库中拉取标签为latest的镜像。
  • docker image ls 列出了本地Docker主机上存储的镜像。可以通过–digests参数来查看镜像的SHA256签名。
  • docker image inspect 命令非常有用!该命令完美展示了镜像的细节,包括镜像层数据和元数据。
  • docker image rm 用于删除镜像。docker image rm alpine:latest命令的含义是删除alpine:latest镜像。当镜像存在关联的容器,并且容器处于运行(Up)或者停止(Exited)状态时,不允许删除该镜像。

参考博客和文章书籍等:

《深入浅出Docker》

因博客主等未标明不可引用,若部分内容涉及侵权请及时告知,我会尽快修改和删除相关内容