镜像(Image)可以理解为是一个只读的文件包,其中包含了虚拟环境运行最原始文件系统的内容。但是 Docker 的镜像与虚拟机中的镜像还是有一定区别的。Docker 通过实现 AUFS 了一种增量式的镜像结构,这样做的好处是:每次对镜像内容的修改,Docker 都会将这些修改铸造成一个镜像层,而一个镜像其实就是由其下层所有的镜像层所组成的。当然,每一个镜像层单独拿出来,与它之下的镜像层都可以组成一个镜像。由于这种结构,Docker 的镜像实质上是无法被修改的,因为所有对镜像的修改只会产生新的镜像,而不是更新原有的镜像。
与其他虚拟机的镜像管理不同,Docker 将镜像管理纳入到了自身设计之中,也就是说,所有的 Docker 镜像都是按照 Docker 所设定的逻辑打包的,也是受到 Docker Engine 所控制的。
普通的虚拟机镜像,是由发布者用自己的方式打包成镜像文件,而使用则是从网络上下载后回复到虚拟机里面;而 Docker 的镜像必须通过 Docker 来打包,也必须通过 Docker 下载或导入后使用,不能单独直接恢复成容器中的文件系统。
虽然 Docker 镜像的这种打包方式失去了很多灵活性,但是其固定的格式可以在不同的服务器间轻松的传递 Docker 镜像,配合 Docker 自身对镜像的管理功能,在不同的机器中传递和共享 Docker 变得非常方便。
对于每一个记录文件系统修改的镜像层来说,Docker 都会根据它们的信息生成了一个 Hash 码,这是一个 64 长度的字符串,足以保证全球唯一性,这种编码的形式在 Docker 很多地方都有体现。
由于镜像层都有唯一的编码,那么就能够区分不同的镜像层并能保证它们的内容与编码是一致的,这带来了另一个好处,就是可以在镜像之间共享镜像层。
比如说:Docker 官方提供的镜像 elasticsearch 镜像和 jenkins 镜像都是在 openjdk 镜像之上修改而得,那么在实际使用的时候,这两个镜像是可以共用 openjdk 镜像内部的镜像层的。这带来好处就是让镜像可以共用一些存储空间,达到 1 + 1 < 2 的效果,使得在同一台机器里存放众多镜像提供了可能。
镜像是由 Docker 进行管理的,所以它的存储位置和存储方式等并不需要过多的关心,只需要利用 Docker 所提供的一些接口或命令对它们进行控制即可。
如果要查看当前连接的 docker daemon 中存放和管理了哪些镜像,可以使用命令 docker images
来查看:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rabbitmq 3-management d6558098d04c 2 months ago 177MB
openzipkin/zipkin latest b4a4e6e796ee 2 months ago 253MB
wurstmeister/kafka latest 988f4a6ca13c 4 months ago 421MB
kibana 7.1.0 714b175e84e8 6 months ago 745MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
wurstmeister/zookeeper latest 3f43f72cb283 10 months ago 510MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
docker images
命令返回的结果中,可以看到镜像ID(IMAGE ID)、构建时间(CREATED)、占用空间(SIZE)等数据。
注意:结果中镜像ID的长度只有12个字符,这和前面说的 64 个字符貌似不一致。其实为了避免屏幕的空间都被太长的镜像 ID 占满,所以 Docker 只显示了镜像 ID 的前 12 个字符,大部分情况下,镜像 ID 的前 12 个字符已经能够让在单一主机中识别出不同的镜像了。
目前不能通过命令行获取镜像在远程仓库中的版本,如果需要获取镜像版本,需要到 docker hub : https://hub.docker.com/ 中查看:
镜像层的 ID 既可以识别每个镜像层,也可以用来直接识别镜像(因为根据最上层镜像能够找出所有依赖的下层镜像,所以最上层进行的镜像层 ID 就能表示镜像的 ID),但是使用这种无意义的超长哈希码显然是违背人性的,所以这里还要介绍镜像的命名,通过镜像名能够更容易的识别镜像。
在 docker images 命令打印出的内容中,有两个与镜像命名有关的数据:REPOSITORY 和 TAG,这两者其实就组成了 docker 对镜像的命名规则。
比如对于前面的 kafka image:
REPOSITORY TAG IMAGE ID CREATED SIZE
wurstmeister/kafka latest 988f4a6ca13c 4 months ago 421MB
这个镜像的命名可以分成三个部分:username、repository 和 tag。
对于 username 来说,在命令 docker images
的返回结果中,有的镜像有 username 这个部分,而有的镜像是没有的。没有 username 这个部分的镜像,表示镜像是由 Docker 官方所维护和提供的,所以就不单独标记用户了。
而 repository 部分通常采用的是软件名,但是镜像还是镜像,镜像名还是镜像名,其与软件命名其实是独立的。
Docker 中还有一个约定,当在操作中没有具体给出镜像的 tag 时,Docker 会采用 latest
作为缺省 tag。这也就带来了一个共识,也就是绝大多数镜像提供者在提供镜像时,会在 latest 对应的镜像中包含软件最新的版本。这带来了一项小便利,在不需要了解应用程序迭代周期的情况下,可以利用 latest 镜像保持软件最新版本的使用。
在一些编程语言中,都会有统一的依赖包管理,如 java 的 maven,node.js 的 npm等,这些管理工具后面,都至少有一个依赖仓库。
docker 也有镜像仓库,其最大的作用是实现了 Docker 镜像的分发。借助镜像仓库,可以得到一个镜像的中转站,将开发环境上所使用的镜像推送至镜像仓库,并在测试或生产环境上拉取到它们,而这个过程仅需要几个命令,甚至自动化完成。
Docker 官方建立了中央镜像仓库 : Docker Hub ,Docker Hub 除了普通镜像仓库的功能外,它内部还有更加细致的权限管理,支持构建钩子和自动构建,还有一套 Web 操作页面。
可以在界面输入命令行搜索镜像,也可以在命令行输入 : docker search 镜像名
搜索镜像。
$ docker search nginx
NAME DESCRIPTION STARS OFFICIAL AUTOMATED
nginx Official build of Nginx. 12280 [OK]
jwilder/nginx-proxy Automated Nginx reverse proxy for docker con… 1696 [OK]
richarvey/nginx-php-fpm Container running Nginx + PHP-FPM capable of… 747 [OK]
linuxserver/nginx An Nginx container, brought to you by LinuxS… 82
bitnami/nginx Bitnami nginx Docker Image 73 [OK]
tiangolo/nginx-rtmp Docker image with Nginx using the nginx-rtmp… 60 [OK]
nginxdemos/hello NGINX webserver that serves a simple page co… 33 [OK]
jc21/nginx-proxy-manager Docker container for managing Nginx proxy ho… 31
jlesage/nginx-proxy-manager Docker container for Nginx Proxy Manager 29 [OK]
nginx/nginx-ingress NGINX Ingress Controller for Kubernetes 22
privatebin/nginx-fpm-alpine PrivateBin running on an Nginx, php-fpm & Al… 19 [OK]
schmunk42/nginx-redirect A very simple container to redirect HTTP tra… 17 [OK]
blacklabelops/nginx Dockerized Nginx Reverse Proxy Server. 12 [OK]
centos/nginx-18-centos7 Platform for running nginx 1.8 or building n… 12
nginxinc/nginx-unprivileged Unprivileged NGINX Dockerfiles 11
centos/nginx-112-centos7 Platform for running nginx 1.12 or building … 10
nginx/nginx-prometheus-exporter NGINX Prometheus Exporter 9
webdevops/nginx Nginx container 8 [OK]
sophos/nginx-vts-exporter Simple server that scrapes Nginx vts stats a… 5 [OK]
1science/nginx Nginx Docker images that include Consul Temp… 5 [OK]
mailu/nginx Mailu nginx frontend 5 [OK]
pebbletech/nginx-proxy nginx-proxy sets up a container running ngin… 2 [OK]
ansibleplaybookbundle/nginx-apb An APB to deploy NGINX 1 [OK]
wodby/nginx Generic nginx 0 [OK]
centos/nginx-110-centos7 Platform for running nginx 1.10 or building … 0
其中,OFFICIAL 代表镜像为 Docker 官方提供和维护,相对来说稳定性和安全性较高。STARS 代表镜像的关注人数,这类似 GitHub 的 Stars,可以理解为热度。
可以使用 docker pull
命令拉取镜像,命令的参数就是前面的镜像仓库名。
sudo docker pull mongo
Using default tag: latest
latest: Pulling from library/mongo
7ddbc47eeb70: Pull complete
c1bbdc448b72: Pull complete
8c3b70e39044: Pull complete
45d437916d57: Pull complete
e119fb0e0a55: Pull complete
91f0b9bae1ea: Pull complete
53e7c2967f11: Pull complete
69a945568374: Pull complete
93333bc225a7: Pull complete
b9c10bd6c9bd: Pull complete
7f4e3538e99c: Downloading [==================================> ] 72.45MB/111.8MB
1164b51d180a: Download complete
a715a7d71f27: Download complete
在控制台中,可以看到镜像拉取的进度。下载进度会分为几行,其实每一行代表的就是一个镜像层。Docker 首先会拉取镜像所基于的所有镜像层,之后再单独拉取每一个镜像层并组合成这个镜像。如果在本地已经存在相同的镜像层(共享于其他的镜像),Docker 就直接略过这个镜像层的拉取而直接采用本地的内容。
在获取镜像时没有提供镜像标签,Docker 会默认使用 latest 这个标签,使用完整的镜像命名来拉取镜像如下:
$ sudo docker pull openzipkin/zipkin:2.19
2.19: Pulling from openzipkin/zipkin
9ff2acc3204b: Pull complete
69e2f037cdb3: Pull complete
0ab175cd7cdc: Pull complete
3e010093287c: Pull complete
4a63134ba470: Pull complete
8f250d77eb0d: Pull complete
05b9d3576e9f: Pull complete
ef0fec9b6120: Pull complete
07f5eb79ad62: Pull complete
ee88f81d121c: Pull complete
b8887dc36c2b: Pull complete
97a2c104c0b4: Pull complete
Digest: sha256:87fe01472af81fb7e25d2a79eddda7b50bc450b7116b5fabafb4e6f6c66c802f
Status: Downloaded newer image for openzipkin/zipkin:2.19
docker.io/openzipkin/zipkin:2.19
镜像拉取完成后,可以通过命令 docker images
来查看已经拉取的镜像列表。
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rabbitmq 3-management d6558098d04c 2 months ago 177MB
openzipkin/zipkin latest b4a4e6e796ee 2 months ago 253MB
wurstmeister/kafka latest 988f4a6ca13c 4 months ago 421MB
kibana 7.1.0 714b175e84e8 6 months ago 745MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
wurstmeister/zookeeper latest 3f43f72cb283 10 months ago 510MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
可以通过命令 docker inspect
查看已拉取镜像详细信息,比如:
docker inspect openzipkin/zipkin:2.19
docker inspect
的参数除了容器的名称,还可以是镜像id或者容器id。
通过镜像名或者镜像ID传递到 docker inspect
或者其他类似的命令(需要指定Docker对象的命令)里,Docker 都会根据传入的内容去寻找与之匹配的内容,只要传入的内容能够找出唯一的镜像,Docker 就会对这个镜像执行给定的操作。如果找不到唯一的镜像,那么操作不会进行,Docker 也会显示错误。
也就是说,只要传入能够唯一识别镜像或容器的信息,即使它短到只有1个字符,Docker 都是可以处理的。
如下:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
rabbitmq latest 72469b528c2d 10 days ago 150MB
openzipkin/zipkin 2.19 12ee1ce53834 13 days ago 157MB
rabbitmq 3-management d6558098d04c 2 months ago 177MB
openzipkin/zipkin latest b4a4e6e796ee 2 months ago 253MB
wurstmeister/kafka latest 988f4a6ca13c 4 months ago 421MB
kibana 7.1.0 714b175e84e8 6 months ago 745MB
elasticsearch 7.1.0 12ad640a1ec0 6 months ago 894MB
wurstmeister/zookeeper latest 3f43f72cb283 10 months ago 510MB
hello-world latest fce289e99eb9 11 months ago 1.84kB
# IMAGE ID 前缀为 7 的有两个, 查询 7 会返回错误
$ docker inspect 7
[]
Error response from daemon: Multiple IDs found with provided prefix: 7
# 3 开头的 id 只有一个,运行如下
docker inspect 3
[
{
"Id": "sha256:3f43f72cb2832e7a5fbed7f7dbcd0c43004357974d8f32555d101bd53e81e74f",
"RepoTags": [
"wurstmeister/zookeeper:latest"
],
"RepoDigests": [
"wurstmeister/zoo
......................
如图:
可以使用命令 docker rmi
移除本地的镜像,参数是镜像名或者镜像id。
$ sudo docker rmi rabbitmq
Untagged: rabbitmq:latest
Untagged: rabbitmq@sha256:3c0ebabfb9e8b53b18d4ee060019718f47df17dc4a333f1ae1715963216216bd
Deleted: sha256:72469b528c2d9030a1bc3b856c74bda2ba20102243959f5d56fdd90f1feb567a
Deleted: sha256:31961c9940cf1337da82b685c03851d2e9f1c61354be86a3405eddc14142a6d7
Deleted: sha256:3395fce986f2b2181272d43e8d41392540d9d79ad568563b6abec52567b48626
Deleted: sha256:8e3f24605824056f5eca2737711fa84b13ca03e0ef63166c8f7a460b221bdc2a
Deleted: sha256:77c0c1c577c10652620a84a00c287cbc285a847af7e98cda5c8be1405a6d70aa
Deleted: sha256:5d40e9049495908930f2c42beaef612c3fbdccaf232b64c86e57fc0d3c36cbaa
Deleted: sha256:5948e2c971ab5c3c297f781986fcfbbf0a2175d6900c6ec40380fbb08fbcbed5
Deleted: sha256:4fc26b0b0c6903db3b4fe96856034a1bd9411ed963a96c1bc8f03f18ee92ac2a
Deleted: sha256:b53837dafdd21f67e607ae642ce49d326b0c30b39734b6710c682a50a9f932bf
Deleted: sha256:565879c6effe6a013e0b2e492f182b40049f1c083fc582ef61e49a98dca23f7e
Deleted: sha256:cc967c529ced563b7746b663d98248bc571afdb3c012019d7f54d6c092793b8b
删除镜像其实就是删除镜像内的镜像层,在删除镜像命令打印的结果里,可以看到被删除的镜像层以及它们的ID。如果存在两个镜像共用一个镜像层的情况,Docker 是不会删除被共享的那部分镜像层,只有当镜像层只被当前被删除的镜像所引用时,Docker 才会将它们从硬盘空间中移除。
docker rmi
命令也支持同时删除多个镜像,只需要通过空格传递多个镜像 ID 或镜像名即可。
$ sudo docker rmi -f kibana:7.1.0 elasticsearch:7.1.0
Untagged: kibana:7.1.0
Untagged: kibana@sha256:7a60259ea48715842d88e262cbf58ccc9f847997faf6babda55338a562bcee61
Deleted: sha256:714b175e84e8fa91ceed8b802980efb4017fa75359599cd2b63c87bbc26efe77
Untagged: elasticsearch:7.1.0
Untagged: elasticsearch@sha256:f449aeab752587709b440a9cb9b35ed93bfabdab75fb8ae9e0b330aa0e584a51
Deleted: sha256:12ad640a1ec0484ee7eac455e6b924fb01a1fc88ca01d5a6d90cfa7554ab4568
Error response from daemon: conflict: unable to remove repository reference "xxxxxxx" (must force) - container 766113c852d4 is using its referenced image fce289e99eb9
由于 container 依赖该镜像,所以无法删除。处理办法:
1、删除引用容器
使用 sudo docker stop xxx
停止容器,然后使用 sudo docker rm xxx
删除容器,最后使用 sudo docker rmi 镜像名或镜像id
删除镜像即可,如下:
上面可以使用 docker stop $(docker ps -a -q)
停止所有的container,使用 docker rm $(docker ps -a -q)
删除所有container。
2、强制删除
在命令中加 -f
参数强制删除镜像:sudo docker rmi -f xxx