Docker使用【镜像】
Docker镜像
- 1. Docker镜像是什么
- 2. 镜像分层案例
- 3. 为什么需要镜像
- 4. 镜像命令详解
- 4.1 镜像命令清单
- 4.2 docker rmi
- 4.3 docker save
- 4.4 docker load
- 4.5 docker history
- 4.6 docker image prune
- 5. 镜像综合实战:镜像存储的压缩与共享
1. Docker镜像是什么
Docker image 本质上是一个 read-only 只读文件, 这个文件包含了文件系统、
源码、库文件、依赖、工具等一些运行 application 所必须的文件。
我们可以把 Docker image 理解成一个模板, 可以通过这个模板实例化出来很多
容器。
image 里面是一层层文件系统 Union FS。联合文件系统,可以将几层目录挂载到
一起,形成一个虚拟文件系统。
每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三
种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的。
构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层
的修改,增加了一层文件系统。一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样。当你使用的时候,你只会看到一个完全的整体,你不知道里面有几层,也不清楚每一层所做的修改是什么。
2. 镜像分层案例
1. 实际案例
- 对于图中的Java镜像和C++镜像,他们共用一个操作系统内核。然后在此基础上,每个镜像都有自己的实例化操作系统。
- 再往上层看,Java镜像是JDK,最上层就是app.jar;对于C++,再上层就是app.exe可执行程序,也是最上层。
- 这是底层角度,如果我们从使用者的角度来看,只能从上往下看,上层会将下层挡住,不可见。

2. 生活案例
- 我们以日常的地板为例,开发商的房子提供给用户的时候一般是做好了地暖,而这些地暖其实是一层一层添加的,最底层的钢筋水泥层,然后添加保温层,采暖管,再铺设水泥层,到最后交付的时候家家户户都是水泥面,这一层一般是不可修改的,最上层用户一般会再铺设商木地板或者地板砖每家每户的选择不一样,相当于我们镜像的容器层。

3. 为什么需要镜像
在部署应用时,通过手工或写一些脚本的方式进行部署。这样部署面临问题就是云端和本地环境一致问题。用户为每个应用打包过程比较繁琐,需要配置和修改等操作,非常费劲。
然而,Docker 镜像就是为了解决这个小小的打包功能,突然一夜之间成名。那么,你可能说 Docker 镜像就是个压缩包,是的,你猜对了,它就像一个压缩包文件。它是如何解决 Paas 时代所面临的云端和本地一致性问题?很简单,它是把一个镜像制作成一个完整的操作系统所有文件和对应的目录结构,这样的压缩包是跟你本地和测试环境用的操作系统一摸一样。
docker 最大的贡献就是定义了容器镜像的分层的存储格式,docker 镜像技术的基础是联合文件系统(UnionFS),其文件系统是分层的。这样既可以充分利用共享层,又可以减少存储空间占用。
docker 镜像提供了一种打包应用程序和预配置服务器环境的便捷方式,可以很方便的将其用于个人用途或与其他 Docker 用户公开共享。
4. 镜像命令详解
有一些命令之前已经学过了:Docker使用【Registry镜像仓库】,这里就不再赘述。
4.1 镜像命令清单
import是容器章节export会用的命令,build是dockerfile章节会使用的命令,届时再详细讲解。
| 命令 | 别名 | 功能 | 备注 |
|---|---|---|---|
| docker images | docker image ls/docker image list | 列出本地镜像 | 必须掌握 |
| docker tag | docker image tag | 给镜像打标签,可用于推送镜像仓库 | 必须掌握 |
| docker pull | docker image pull | 从镜像仓库拉取镜像 | 和镜像仓库命令相同,也可以归类为镜像操作命令,必须掌握,参考镜像命令此处不赘述 |
| docker push | docker image push | 推送镜像到仓库 | 和镜像仓库命令相同,也可以归类为镜像操作命令必须掌握,参考镜像命令此处不赘述 |
| docker rmi | docker image rm/ docker image remove | 删除本地镜像 | 必须掌握 |
| docker build | docker image build | 通过 dockerfile 制作镜像 | 必须掌握 |
| docker save | docker image save | 将指定镜像保存成 tar 归档文件 | 必须掌握 |
| docker load | docker image load | 导入使用 docker save 命令导出的镜像 | 必须掌握 |
| docker image inspect | 查看镜像详细信息 | ||
| docker history | docker image history | 查看镜像历史 | |
| docker import | docker image import | 从归档文件 docker export 中创建镜像。 | |
| docker image prune | 删除不使用的镜像 |
4.2 docker rmi
1. 功能
- 删除镜像。
2. 语法
docker rmi [OPTIONS] IMAGE [IMAGE...]
3. 别名
docker image rm, docker image remove
4. 关键参数
-f:强制删除;--no-prune:不移除该镜像的过程镜像,默认移除(学完dockerfile后才能真正理解);
5. 样例
- 比如我们要删除
hello-world镜像:

- 首先要检查该镜像有没有引用,有的话全部删除:
- 可以看到,该镜像有三个引用,提前使用下容器命令
docker rm + id,删除掉所有引用该镜像的容器。如果不删除引用,则无法删除该镜像。
- 可以看到,该镜像有三个引用,提前使用下容器命令

- 再次查看镜像,删除成功:

4.3 docker save
1. 功能
- 将指定镜像保存成 tar 归档文件(就像zip压缩)。
2. 语法
docker save [OPTIONS] IMAGE [IMAGE...]
3. 别名
docker image save
4. 关键参数
-o:输出到的文件。
5. 样例

4.4 docker load
1. 功能
- 导入使用 docker save 命令导出的镜像。
2. 语法
docker load [OPTIONS]
3. 别名
docker image load
4. 关键参数
--input , -i:指定导入的文件,代替 STDIN。--quiet , -q:精简输出信息。
5. 样例
- 先把之前
save的busybox镜像删了:

- 然后
load之前的tar包:

4.5 docker history
1. 功能
- 显示镜像历史,构建过程中每一层的详细信息。
2. 语法
docker history [OPTIONS] IMAGE
3. 别名
docker image history
4. 关键参数
-H , --human:大小和日期采用人容易读的格式展现。--no-trunc:显示全部信息,不要隔断;-q, --quiet:只显示镜像 id 信息;
5. 样例
- 这个镜像比较简单,只有两层:

4.6 docker image prune
1. 功能
- 删除不使用的镜像。
不使用的镜像有两类:a. 没有容器引用的镜像 b. 虚悬镜像,就是
REPOSITORY和TAG均为<null>的镜像。
2. 语法
docker image prune [OPTIONS]
3. 关键参数
-a , --all:删除全部没有容器引用的镜像;--filter filter:指定过滤条件;-f, --force:强制删除;
4. 样例
- 删除虚悬镜像:

简单来说,虚悬镜像就是 Docker 世界的“垃圾文件”,定期清理它们可以保持你的开发环境整洁和高效。
5. 镜像综合实战:镜像存储的压缩与共享
1. 在Docker Hub找一个nginx1.24.0镜像,拉下来
- 可以看到服务端只有50多M:

- 拉到本地,查看,发现足足有142M,说明服务端在存储镜像时,进行了一定的压缩:

2. 给拉下来的nginx镜像,打上多个tag,向远端仓库推送多份
- 其实到这一步就初见端倪了,这些镜像只是tag不同,而id是同一个:

- 向远端仓库推送,发现推送v2和v3时,显示层已经存在;并且v1版本推送时,发现是
mount上去的,因为如果 docker hub 发现已经有了该镜像是mount的,不是从本地推上去的:

- 可以看到,三个版本都存在仓库中了,但是实际上他们只是
tag不同,真正占空间的只有一份:

