一、命令忘了怎么查
三个保底的命令,先记住:
docker version
docker info # 显示一些运行信息
docker 命令 --help
之后哪个命令不会用,就去官方文档查,命令和参数都在里面,把 Reference 展开就是 CLI reference:

https://docs.docker.com/reference
https://docs.docker.com/
二、镜像相关的命令总览
先把和镜像有关的命令列出来,后面逐个上手:
| 命令 | 说明 |
|---|---|
docker image build | 从 Dockerfile 构建镜像 |
docker image history | 查看镜像的构建历史 |
docker image import | 从 tar 包导入文件系统创建镜像 |
docker image inspect | 查看镜像详细信息 |
docker image load | 从 tar 归档或标准输入加载镜像 |
docker image ls(也就是 docker images) | 列出所有镜像 |
docker image prune | 删除未使用的镜像 |
docker image pull | 从仓库下载镜像 |
docker image push | 上传镜像到仓库 |
docker image rm | 删除一个或多个镜像 |
docker image save | 将镜像保存到 tar 归档文件 |
docker image tag | 给目标镜像打标签 |
三、看本地有哪些镜像
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest c3cbe1cc1aa5 25.9kB 9.49kB U
# 解释
IMAGE 镜像仓库源
ID 镜像ID
DISK USAGE 磁盘占用
CONTENT SIZE 内容大小
EXTRA 状态U,正在使用
它支持的选项:
| 选项 | 说明 |
|---|---|
-a, --all | 显示所有镜像(默认隐藏中间层和悬空镜像) |
--digests | 显示摘要信息 |
-f, --filter | 按条件过滤输出 |
--format | 使用自定义模板格式化输出 |
--no-trunc | 不截断输出 |
-q, --quiet | 只显示镜像 ID |
--tree | 实验性功能,以树形结构列出多平台镜像 |
--format 支持这几种写法:
table或'table TEMPLATE':使用 Go 模板以表格格式输出json:以 JSON 格式输出'TEMPLATE':使用给定的 Go 模板直接输出
平时最常用的就是 -q 和 -a,配合起来只拿 ID:
root@VM-0-9-ubuntu:~# docker images -aq
c3cbe1cc1aa5
四、搜索镜像
docker 镜像都放在 docker hub,相当于一个镜像商店,可以在官网搜,也可以在 linux 里搜。
docker search 镜像名
(我这边网络问题没法演示,先把参数记下来。)
| 选项 | 说明 |
|---|---|
-f, --filter | 按条件过滤搜索结果 |
--format | 使用 Go 模板美化输出格式 |
--limit | 限制最大搜索结果数量 |
--no-trunc | 不截断输出内容 |
可以用 -f 过滤出收藏多的,比如大于 3000 的:
docker search -f stars=3000 mysql
五、拉取镜像
docker pull 是唯一会走镜像加速的命令,其他命令不加速,这点记一下。
root@VM-0-9-ubuntu:~# docker pull --help
Usage: docker pull [OPTIONS] NAME[:TAG|@DIGEST]
Download an image from a registry
Aliases:
docker image pull, docker pull
Options:
-a, --all-tags Download all tagged images in the repository
--platform string Set platform if server is multi-platform capable
-q, --quiet Suppress verbose output
| 选项 | 全称 | 作用 |
|---|---|---|
-a | --all-tags | 下载仓库里所有带标签的镜像(不常用,会下很多) |
--platform | — | 指定平台架构(如 linux/amd64、linux/arm64) |
-q | --quiet | 安静模式,减少输出信息 |
拉的时候能看到下载信息,一层一层往下走:
root@VM-0-9-ubuntu:~# docker pull mysql
Using default tag: latest # 不写tag默认最新,版本必须是仓库存在的
latest: Pulling from library/mysql
71fecf9a0313: Pull complete # 分层下载,镜像核心,联合文件系统
35c80c3f0cad: Pull complete
30627cea5424: Pull complete
718475825f6a: Pull complete
0fab344c2070: Pull complete
7ee3c7ac3aeb: Pull complete
7a08e28acd68: Pull complete
1fc0feac79ef: Pull complete
234be8523cd7: Pull complete
3bfe3c84c770: Pull complete
58ddc8cbf912: Download complete
ebf48244f5b5: Download complete
# 签名
Digest: sha256:cbade841779f1661300e705721f9d2ff159865cc7a8a291affbff43ac6ec7f1d
Status: Downloaded newer image for mysql:latest
docker.io/library/mysql:latest # 真实地址
# docker pull mysql 等价于 docker pull docker.io/library/mysql:latest
root@VM-0-9-ubuntu:~# docker pull mysql:5.7
5.7: Pulling from library/mysql
df9a4d85569b: Pull complete
20e4dcae4c69: Pull complete
1c56c3d4ce74: Pull complete
e9f03a1c24ce: Pull complete
68c3898c2015: Pull complete
6b95a940e7b6: Pull complete
90986bb8de6e: Pull complete
ae71319cb779: Pull complete
ffc89e9dfd88: Pull complete
43d05e938198: Pull complete
064b2d298fba: Pull complete
96889c47a44a: Download complete
9eb6a52b8441: Download complete
Digest: sha256:4bc6bc963e6d8443453676cae56536f4b8156d78bae03c0145cbe47c2aad73bb
Status: Downloaded newer image for mysql:5.7
docker.io/library/mysql:5.7
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest c3cbe1cc1aa5 25.9kB 9.49kB U
mysql:5.7 4bc6bc963e6d 700MB 149MB
mysql:latest cbade841779f 1.28GB 288MB
关于镜像分层缓存:docker pull mysql:latest 拉下来的其实是 MySQL 8.0,docker pull mysql:5.7 是 5.7 版本。虽然都叫 MySQL,但底层基础层(比如 71fecf9a0313 和 df9a4d85569b)来自不同的构建,镜像 ID 也不一样,所以 Docker 不会把它们当成"已存在"的层,缓存共用不上。

这张图里红框标出来的 Already exists 就是不需要重复下载、可以直接共用的缓存层。
六、镜像为什么是一层层的
前面 pull 的时候看到的 Pull complete、Already exists,还有"两个 mysql 版本共用不上缓存"这件事,根子都在分层上。
镜像不是一个整块的文件,而是一层一层叠出来的。FROM debian 是第一层,再来一句 RUN apt-get install emacs 就多一层,再 RUN apt-get install apache2 又一层 —— 每一层都盖在内核和已有的镜像之上:

整个镜像最底下那层是 bootfs:

bootfs 和典型的 Linux/Unix 系统一样,装的是 bootloader 和 kernel;boot 加载完成、内核进了内存之后,bootfs 就卸载了。它上面才是 rootfs:

rootfs 就是 Ubuntu、CentOS 这些发行版的文件系统。容器其实就是一个小号的虚拟机环境,只不过它和宿主机共用同一个内核。
再往上就是一层层的镜像层了。拿一个常见的例子:第 1 层是 Ubuntu 16.04,第 2 层装 Python,第 3 层打安全补丁 —— 这三层合起来才是那个"镜像",单独拿出任何一层都不是:

层与层之间是叠加,不是替换。第 1 层里有文件 1、2、3,第 2 层里有文件 4、5、6,那么这个镜像里就是 6 个文件:

这也解释了不同的镜像为什么能共用底下的层。app1.0 在 centos、mysql 这些底层之上加了自己的文件,app2.0 只是在 app1.0 的基础上又多了一个文件 7,下面的层是共用的,所以 2.0 只多占一个文件的空间:

最后是镜像和容器的关系:镜像的每一层都是只读的,容器跑起来的时候 docker 会在最上面再盖一个可写的容器层,你在容器里做的所有操作都写在这一层:

所以 docker commit 能把容器那层的改动提交成一个新镜像;而容器一删,这层可写层也跟着没了 —— 这也是后面要讲数据卷的原因。
七、删除镜像
docker rmi -f 镜像ID # 该镜像全删
root@VM-0-9-ubuntu:~# docker rmi -f 4bc6bc963e6d
Untagged: mysql:5.7
Deleted: sha256:4bc6bc963e6d8443453676cae56536f4b8156d78bae03c0145cbe47c2aad73bb
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest c3cbe1cc1aa5 25.9kB 9.49kB U
mysql:latest cbade841779f 1.28GB 288MB
# 批量删除全部的,传入所有镜像的id,这里习惯上用了反引号
# $() 是命令替换,它会执行括号里的命令,然后把输出结果作为外层命令的参数
docker rmi -f $(docker images -aq)
root@VM-0-9-ubuntu:~# docker rmi -f `docker images -aq`
Untagged: mysql:latest
Deleted: sha256:cbade841779f1661300e705721f9d2ff159865cc7a8a291affbff43ac6ec7f1d
Untagged: hello-world:latest
Deleted: sha256:c3cbe1cc1aa588a64951ac6286e0df7b27fe2e6324b1001c619bb358770c0178
root@VM-0-9-ubuntu:~# docker images
i Info → U In Use
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
root@VM-0-9-ubuntu:~#
$(...) 和反引号是一个意思,都是命令替换,实际敲的时候用 $(...) 更清楚,反引号容易看错。
八、镜像的导出、导入和 commit
这几个命令基础部分没细讲,先把名字和用途对上,后面 Dockerfile 那几页会展开:
docker save把镜像存成 tar 归档,docker load再把 tar 读回来变成镜像docker export把容器导出成 tar,docker import用它做一个文件系统镜像docker commit把容器当前的改动提交成一个新镜像docker history看镜像是一层层怎么构建出来的docker tag给镜像打标签,docker push推到仓库
镜像的东西就这些,容器怎么跑起来在下一页。