Docker镜像概念
作为一名研发人员,则可以将镜像理解为类(Class)。是一个应用程序。
首先需要先从镜像仓库服务中拉取镜像。常见的镜像仓库服务是 Docker Hub,但是也存在其他镜像仓库服务。
拉取操作会将镜像下载到本地 Docker 主机,可以使用该镜像启动一个或者多个容器。
镜像由多个层组成,每层叠加之后,从外部看来就如一个独立的对象。镜像内部是一个精简的操作系统(OS),同时还包含应用运行所必须的文件和依赖包。
因为容器的设计初衷就是快速和小巧,所以镜像通常都比较小。
前面多次提到镜像就像停止运行的容器(类)。实际上,可以停止某个容器的运行,并从中创建新的镜像。
在该前提下,镜像可以理解为一种构建时(build-time)结构,而容器可以理解为一种运行时(run-time)结构,如下图所示。
Docker Hub地址
docker hub类似maven远程仓库地址
https://hub.docker.com/
pull命令
1)下载镜像的命令。镜像从远程镜像仓库服务的仓库中下载。默认情况下,镜像会从 Docker Hub 的仓库中拉取。
2)通过下载过程,可以看到,一个镜像一般是由多个层组成,类似 f7e2b70d04ae 这样的串表示层的唯一 ID。实际上完整的 ID 包括了 256 个 bit, 64 个十六进制字符组成的,只不过docker由于命令行的限制并没有显示全,如下图所示,下载的一个tomcat镜像就是分成了六层,每层都有自己的ID。
问题一:大家可能会想到,如果多个不同的镜像中,同时包含了同一个层,这样重复下载,岂不是导致了存储空间的浪费么?
实际上,Docker 并不会这么傻会去下载重复的层,Docker 在下载之前,会去检测本地是否会有同样 ID的层,如果本地已经存在了,就直接使用本地的就好了。
问题二:另一个问题,不同仓库中,可能也会存在镜像重名的情况发生,这种情况咋办?
从严格意义上讲,我们在使用 pull命令时,还需要在镜像前面指定仓库地址(Registry),如果不指定,则Docker会使用您默认配置的仓库地址。例如上面,由于我配置的是国内docker.io的仓库地址,我在pull 的时候,docker会默认为我加上 docker.io/library 的前缀。
例如:当我执行docker pull tomcat:9.0.20-jre8命令时,实际上相当于 docker pull
docker.io/tomcat:9.0.20-jre8,如果您未自定义配置仓库,则默认在下载的时候,会在镜像前面加上DockerHub 的地址。Docker 通过前缀地址的不同,来保证不同仓库中,重名镜像的唯一性。
https://hub.docker.com/_/tomcat
# apline和slim都是docker的一种压缩技术,做出来的docker镜像大小比原始的要小
docker pull tomcat:9.0.20-jre8
docker pull tomcat:9.0.20-jre8-slim
docker pull tomcat:9.0.20-jre8-alpine
https://hub.docker.com/_/centos
docker pull centos:7.8.2003
https://hub.docker.com/_/ubuntu
docker pull ubuntu:20.04
https://hub.docker.com/_/debian
docker pull debian:10.6
docker pull debian:10.6-slim
https://hub.docker.com/_/alpine
docker pull alpine:3.12.1
这里要注意同一种镜像在采用了slim或者apline压缩技术后镜像大小会变小,如下图:
apline也是一种操作系统内核,他的镜像版本通常是最小的。关于到底采用哪种操作系统作为我们的基础镜像,其实是没有定论的,即使采用apline做基础镜像比采用centos做基础镜像做出来的镜像包体积小很多,但是还是有很多公司会统一要求用centos作基础镜像,也有的公司要求用debian作为基础的操作系统制作镜像,这里我们一般建议公司内统一用一种基础操作系统来制作镜像即可。
这是因为我们如果用同一个基础操作系统,在下载某个镜像的时候经常会发现这个镜像的某个层文件是已经存在的不用下载了,这样我们的镜像又会小一些。方便上传下载,占用的磁盘也小一些。
常用参数
-a, --all-tags=true|false : 是否获取仓库中所有镜像,默认为否;
--disable-content-trust : 跳过镜像内容的校验,默认为 true;
images命令
通过使用如下两个命令,列出本机已有的镜像:
# 这两个命令起到的作用是一样额
docker images
docker image ls
各个选项说明:
1)REPOSITORY:表示镜像的仓库源
2)TAG:镜像的标签
3)IMAGE ID:镜像ID
4)CREATED:镜像创建时间
5)SIZE:镜像大小
例如下图:
save命令
这个命令是用来保存我们的镜像的,防止说我们之前下的镜像系统恢复快照过后又没了,需要重新下载镜像带来的麻烦。
一个镜像
#创建一个data目录用于存放保存的镜像
mkdir -p /data
cd /data
# 将tomcat的9.0.20-jre8-alpine镜像输出到tomcat9.tar文件
docker save tomcat:9.0.20-jre8-alpine -o tomcat9.tar
# 将tomcat的9.0.20-jre8-slim镜像输出到tomcat9.slim.tar文件
docker save tomcat:9.0.20-jre8-slim > tomcat9.slim.tar
当然也可以同时备份多个镜像,中间使用空格隔开就可以了,具体如下:
docker save tomcat:9.0.20-jre8-alpine tomcat:9.0.20-jre8-slim tomcat:9.0.20-jre8 -o tmocat9all.tar
常用参数
-o :输出到的文件
多个镜像
推荐开发岗的人员使用idea开发工具中的列编辑模式制作docker save命令,编辑后可以生成如下命令
# 创建一个目录用于保存文件
mkdir -p /data
cd /data
# 多个镜像可以加上换行符
docker save \
ubuntu:20.04 \
alpine:3.12.1 \
debian:10.6-slim \
centos:7.8.2003 \
-o linux.tar
docker save \
tomcat:9.0.20-jre8-alpine \
tomcat:9.0.20-jre8-slim \
tomcat:9.0.20-jre8 \
-o tomcat9.0.20.tar
load命令
load命令用于将压缩包导成镜像,他和save命令是对应的。这里我们做演示实验可以先删掉我们已经保存的一个tomcat9的alpine版本镜像,删除后如下图所示:
然后我们可以通过load我们之前保存好的镜像备份将这个镜像恢复出来,使用命令docker load -i tomcat9-alpine.tar,效果如下图所示:
这里看到我们从备份文件里面成功的恢复出来了该镜像。
mkdir -p /data
cd /data
# 恢复linux.tar里面的镜像
docker load -i linux.tar
# 恢复tomcat9.0.20.tar文件里面的镜像
docker load < tomcat9.0.20.tar
常用参数
--input , -i : 指定导入的文件。
--quiet , -q : 精简输出信息。
search命令
不推荐使用search命令查找镜像,不够直观。这里还是看一下他的用法,你可以不用,但是不能不会用。通常的我们推荐去docker网页上去查找,这里的有完整的描述信息说明文档等。
# 这样查不直观,推荐直接在https://hub.docker.com/上面去看文档描述信息
docker search tomcat
常用参数
-f, --filter filter : 过滤输出的内容;
--limit int :指定搜索内容展示个数;
--no-index : 不截断输出内容;
--no-trunc :不截断输出内容;
inspect命令
如果我们要查看我们机器上已经存在的这些镜像信息可以使用该命令。
1)通过 docker inspect 命令,我们可以获取镜像的详细信息,其中,包括创建者,各层的数字摘要等。
2)docker inspect 返回的是 JSON格式的信息,如果您想获取其中指定的一项内容,可以通过 -f 来指定,如获取镜像大小。
# 查看tomcat的9.0.20-jre8-alpine版本的镜像详细信息
docker inspect tomcat:9.0.20-jre8-alpine
#获取tomcat:9.0.20-jre8-alpine镜像的size信息
docker inspect -f {{".Size"}} tomcat:9.0.20-jre8-alpine
使用该命令会输出一个JSON文件,使用效果如下图:
指定查看镜像Size的话效果如下图:
history命令
从前面的命令中,我们了解到,一个镜像是由多个层组成的,那么,我们要如何知道各个层的具体内容呢?通过 docker history命令,可以列出各个层的创建信息,当然这里各层信息的展示效果是不太理想和明显的,我们只需要了解这个命令就可以了。
例如:查看 tomcat:9.0.20-jre8-alpine的各层信息
docker history tomcat:9.0.20-jre8-alpine
tag命令
标记本地镜像,将其归入某一仓库,也就相当于改了镜像的名称。
这里我们先简单熟悉一下tag命令,后边的再详细进行讲解。
# 将tomcat标签为9.0.20-jre8-alpine的镜像改名为david/tomcat标签为9
docker tag tomcat:9.0.20-jre8-alpine david/tomcat:9
rmi命令
通过如下两个都可以删除镜像:
docker rmi tomcat:9.0.20-jre8-alpine
docker image rm tomcat:9.0.20-jre8-alpine
常用参数
-f, -force : 强制删除镜像,即便有容器引用该镜像;
-no-prune : 不要删除未带标签的父镜像;
通过ID删除镜像
除了通过标签名称来删除镜像,我们还可以通过制定镜像 ID, 来删除镜像。一旦制定了通过 ID 来删除镜像,它会先尝试删除所有指向该镜像的标签,然后在删除镜像本身。
docker rmi ee7cbd482337
第一次试验
# 根据tomcat:9.0.20-jre8-alpine镜像重新打一个新的tag
docker tag tomcat:9.0.20-jre8-alpine lagou/tomcat:9
# 通过images命令查看镜像
docker images
# 通过image的ID删除镜像
docker rmi 387f9d021d3a
# 错误信息如下:
Error response from daemon: conflict: unable to delete 387f9d021d3a (must be forced)
- image is referenced in multiple repositories
第二次试验
# 根据tomcat:9.0.20-jre8-alpine镜像重新打两个个新的tag
docker tag tomcat:9.0.20-jre8-alpine lagou/tomcat:9
docker tag tomcat:9.0.20-jre8-alpine lagou/tomcat:9.1
# 根据image名称删除tomcat:9.0.20-jre8-alpine
docker rmi tomcat:9.0.20-jre8-alpine
# 通过image的ID删除镜像
docker rmi 387f9d021d3a
#错误信息如下:
Error response from daemon: conflict: unable to delete 387f9d021d3a (must be forced)
- image is referenced in multiple repositories
总结
1)推荐通过image的名称删除镜像
2)image的ID在终端长度未完全显示,ID值会出现重复
删除镜像的限制
删除镜像很简单,但也不是我们何时何地都能删除的,它存在一些限制条件。当通过该镜像创建的容器未被销毁时,镜像是无法被删除的。为了验证这一点,我们来做个试验。
docker run -itd --name tomcat9 tomcat:9.0.20-jre8-alpine
可以看到提示信息,无法删除该镜像,因为有容器正在引用他!同时,这段信息还告诉我们,除非通过添加 -f 子命令,也就是强制删除,才能移除掉该镜像!
但是,我们一般不推荐这样暴力的做法,正确的做法应该是:
1)先删除引用这个镜像的容器;
2)再删除这个镜像;
比如下面的删除镜像的错误:
我们可以通过下面的命令查一下这个镜像的依赖:
docker image inspect --format='{{.RepoTags}} {{.Id}} {{.Parent}}' $(docker image ls -q --filter since=5ff2c1549f53)
然后把依赖的删除掉。
清理镜像
我们在使用 Docker 一段时间后,系统一般都会残存一些临时的、没有被使用的镜像文件,可以通过以下命令进行清理。执行完命令后,还是告诉我们释放了多少存储空间!
docker image prune
常用参数
-a, --all : 删除所有没有用的镜像,而不仅仅是临时文件;
-f, --force :强制删除镜像文件,无需弹出提示确认;
docke