Docker 镜像是什么
• Docker image 本质上是一个 read-only 只读文件,可以理解为一个打包器,这个文件包含了文件系统、源码、库文件、依赖、工具等一些运行 application 所必须的文件。
• 我们可以把 Docker image 理解成一个模板,可以通过这个模板实例化出来很多容器,只有实际实例化时候,才具有一些运行态的概念。
• image 里面是一层层文件系统 UnionFS。联合文件系统,可以将几层目录挂载到一起,形成一个虚拟文件系统。
每一层文件系统我们叫做一层 layer,联合文件系统可以对每一层文件系统设置三种权限,只读(readonly)、读写(readwrite)和写出(whiteout-able),但是 docker 镜像中每一层文件系统都是只读的。
构建镜像的时候,从一个最基本的操作系统开始,每个构建的操作都相当于做一层的修改,增加了一层文件系统。一层层往上叠加,上层的修改会覆盖底层该位置的可见性,这也很容易理解,就像上层把底层遮住了一样。当你使用的时候,你只会看到一个完全的整体,你不知道里面有几层,也不清楚每一层所做的修改是什么。
镜像生活案例
镜像相当于我们 java 或者 C++ 中的类,相当于一个模板,可以很方便的构建出来不同的对象。

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


为什么需要镜像
在部署应用时,通过手工或写一些脚本的方式进行部署。这样部署面临问题就是云端和本地环境一致问题。用户为每个应用打包过程比较繁琐,需要配置和修改等操作,非常费劲。
Docker 镜像它是如何解决 PaaS 时代所面临的云端和本地一致性问题?很简单,Docker 镜像它就像一个压缩包文件,它是把一个镜像制作成一个完整的操作系统所有文件和对应的目录结构以及程序需要的其他依赖文件,这样的压缩包是跟你本地和测试环境用的操作系统一摸一样。这样 docker 就屏蔽了环境的差异,用户运行程序不需要针对配置进行修改。
此外 docker 最大的贡献就是定义了容器镜像的分层的存储格式,docker 镜像技术的基础是联合文件系统 (UnionFS),其文件系统是分层的。这样既可以充分利用共享层,又可以减少存储空间占用。比如不同镜像的操作系统这一层是一样的,那么 docker 存储一份,其他镜像操作系统这一层存储的只是引用。


docker 镜像提供了一种打包应用程序和预配置服务器环境的便捷方式,可以很方便的将其用于个人用途或与其他 Docker 用户公开共享。由于分层的设计,我们拉取时候就只拉取某一层,大大加快了部署的速度。
但同样有利有弊,docker 在打包一款程序也会将对应依赖项一起打包,这一定程度上增加了包的大小,此外由于分层的设计,我们需要某一个文件时就是一层一层的寻找,这也无疑降低了效率。
镜像命令详解
1. 镜像命令清单
| 命令 | 别名 | 功能 | 备注 |
|---|---|---|---|
| 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 | 删除不使用的镜像 |
2. docker images
• 功能:列出本地镜像。 • 语法
docker images [OPTIONS] [REPOSITORY[:TAG]]
• 别名:docker image ls, docker image list
• 关键参数
-a: 列出本地所有的镜像(含中间映像层,默认情况下,过滤掉中间映像层);--digests: 显示镜像的摘要信息;-f: 显示满足条件的镜像;--format: 指定返回值的模板文件;--no-trunc: 显示完整的镜像信息;-q: 只显示镜像 ID。
• 样例
# 列出本地全部镜像
docker images
# 列出本地镜像中 REPOSITORY 为 ubuntu 的镜像列表。
docker images ubuntu
3. docker tag
• 功能:标记本地镜像,将其归入某一仓库。 • 语法
docker tag SOURCE_IMAGE[:TAG] TARGET_IMAGE[:TAG]
• 别名:docker image tag
• 样例
docker tag ubuntu:22.04 myregistry.com/myubuntu:22.04
4. docker pull
参考镜像仓库一文命令。
5. docker push
参考镜像仓库一文命令。
6. docker rmi
• 功能:删除镜像。 • 语法
docker rmi [OPTIONS] IMAGE [IMAGE...]
• 别名:docker image rm, docker image remove
• 关键参数
-f: 强制删除镜像;--no-prune: 不移除该镜像的过程镜像,默认移除;
• 样例
通过 ID 删除

通过名称:TAG 删除

如果本地通过镜像生成了对应的容器,此时我们无法直接删除镜像,想要强制删除必须使用 -f

或者我们需要将本地对应的容器都删除掉,我们才可以删掉镜像。

7. docker save
• 功能:将指定镜像保存成 tar 归档文件。 • 语法
docker save [OPTIONS] IMAGE [IMAGE...]
• 别名:docker image save
• 关键参数
-o: 输出到的文件。
• 样例
可以一次 save 一个或者多个镜像为归档文件

8. docker load
• 功能:导入使用 docker save 命令导出的镜像。 • 语法
docker load [OPTIONS]
• 别名:docker image load
• 关键参数
--input,-i: 指定导入的文件,代替 STDIN。--quiet,-q: 精简输出信息。
• 样例

精简输出信息,没有进度条了。

9. docker image inspect
• 功能:查看镜像详细信息 • 语法
docker image inspect [OPTIONS] IMAGE [IMAGE...]
• 注意事项:
- docker inspect 会自动检查是镜像还是容器然后显示相关信息
• 样例
# 查看镜像详细信息
docker image inspect nginx:1.23.3
10. docker history
• 功能:显示镜像历史,即镜像内每一层详细的创建信息。 • 语法
docker history [OPTIONS] IMAGE
• 别名:docker image history
• 关键参数
-H,--human: 大小和日期采用人容易读的格式展现,默认开启--no-trunc: 显示全部信息,不要隔断;-q,--quiet: 只显示镜像 id 信息;
• 样例


11. docker import
• 功能:从归档文件中创建镜像。 • 语法
docker import [OPTIONS] file|URL|- [REPOSITORY[:TAG]]
• 别名:docker image import
• 关键参数
-c: 应用 docker 指令创建镜像;-m: 提交时的说明文字;
• 样例
docker import my_ubuntu_v3.tar maxhou/ubuntu:v4
12. docker image prune
• 功能:删除不使用的镜像(所谓不使用的镜像分为两种,一种是没有容器使用的镜像,一种是 dangling 镜像)。 • 语法
docker image prune [OPTIONS]
• 关键参数
-a,--all: 删除全部不使用的镜像;--filter filter: 指定过滤条件;-f,--force: 不提示是否删除;
• 样例
docker image prune

13. docker build
• 功能:docker build 命令用于使用 Dockerfile 创建镜像。 • 语法
docker build [OPTIONS] PATH | URL | -
• 关键参数
--build-arg=[]: 设置镜像创建时的变量;-f: 指定要使用的 Dockerfile 路径;--label=[]: 设置镜像使用的元数据;--no-cache: 创建镜像的过程不使用缓存;--pull: 尝试去更新镜像的新版本;--quiet,-q: 安静模式,成功后只输出镜像 ID;--tag,-t: 镜像的名字及标签,通常 name:tag 或者 name 格式;可以在一次构建中为一个镜像设置多个标签。--network: 默认 default。在构建期间设置 RUN 指令的网络模式
• 样例
docker build -t mynginx:v1 .
镜像操作案例
查找镜像

下载镜像

查看镜像及列表存储位置
遍历查看镜像

查看镜像仓库在本地的存储信息
- 进入
/data/var/lib/docker/image/目录,注意存储位置这里的是修改后的/data

- 查看
overlay2/repositories.json文件,该文件记录已拉取镜像文件的信息

- 查看本地镜像,发现和 repositories.json 文件记录的信息相同
镜像过滤
- 根据仓库名列出镜像
docker image ls ubuntu
- 列出特定的某个镜像,也就是说指定仓库名和标签
docker image ls ubuntu:18.04
- docker image ls 还支持强大的过滤器参数
--filter,或者简写-f。之前我们已经看到了使用过滤器来列出虚悬镜像的用法,它还有更多的用法。查看某个位置之前的镜像 before,查看某个位置之后的镜像 since

查看镜像详情

查看镜像分层
Docker history 可以查看分层

docker image inspect 可以查看详细的分层

一些镜像下载的时候也可以看到是一层一层下载的

打标签与推送镜像前需要在提供镜像仓库服务的网站创建对应仓库
打标签
docker tag busybox:1.36.0 ccr.ccs.tencentyun.com/maxhou6/busyboxbymaxhou:v3.0
推送镜像
docker pull ccr.ccs.tencentyun.com/maxhou6/busyboxbymaxhou:v3.0
运行容器

如果本地不存在对应镜像,会从远程仓库拉取并运行

镜像删除
镜像的删除:可以根据 id 和名字删除,对于使用的镜像需要先清理容器再删除镜像
如果本地存在多个某一镜像打上 tag 得到的镜像(这些镜像 ID 相同,实际上就是同一个镜像),我们删除这些镜像,只是删除对应的 tag,只会显示 untagged 信息,不会因为本地存在对应容器而阻止

当本地其他 tag 都删除,只剩下最后一个镜像时,我们这时候要删除,就必须先将使用该镜像的容器都删除掉,才可以 rmi 删除该镜像

镜像综合实战
实战一、离线迁移镜像
注:对于一些保密性质较为严格的场所,我们是无法联网,无法连接远程仓库的,所以我们就需要离线迁移镜像手段。
- 服务器 1 上镜像保存为 tar 文件,如操作系统为 ubuntu

- scp 或者只用使用可视化工具拷贝镜像到第二台服务器上
scp 根据 ssh 协议将当前目录下的某个文件拷贝到对端某个用户的某个路径下
scp 文件名 用户名@对端 IP:拷贝的路径

- 从 tar 中恢复镜像

- 执行 docker run 检查镜像是否可以正常运行

实战二、镜像存储的压缩与共享
- 拉取 nginx 镜像,如果本地没有,镜像是从仓库拉取,如果有会提示镜像已经存在,并且是最新的。

- Docker images 查看本地镜像,可以看到该镜像为 142Mb

- 从上面看到 nginx 为 1.21.1 的大小是 140 多 MB,但是我们从 docker hub 上查看可以看到镜像是 50 多 MB,说明发生了压缩,因为仓库到本地需要走网络,所以文件越小越好。
所以镜像在远端是进行压缩的,拉取到本地则会进行解压

- 把一个镜像打多个 tag,然后同时推送仓库,可以看到是说层已经存在,那么就不再 push 了,不会重复存储同一份数据

- 添加一个新的镜像到我们的仓库的时候,如果 docker hub 能在仓库中找到,会表示是 mount 的,同样不是从本地推上去的。
所以远端只会存储一份元数据,不会重复存储,除了元数据其他的只是起的别名。


