目录
Docker 镜像教程:pull、images、tag、rmi 与分层结构
镜像(image)是创建容器的模板。上一节的 docker run nginx:1.30 背后,Docker 先下载了 nginx:1.30 这个镜像。本节说明镜像如何命名、下载、查看和删除,以及它“一层一层”的结构。
镜像名称的组成
一个完整的镜像名称如下:
docker.io/library/nginx:1.30-alpine
└───┬───┘ └──┬──┘ └─┬─┘ └────┬────┘
registry 命名空间 名称 tag
| 部分 | 说明 | 省略时的默认值 |
|---|---|---|
| registry | 存放镜像的服务器 | docker.io(Docker Hub) |
| 命名空间 | 用户或组织名称 | 官方镜像是 library |
| 名称(repository) | 镜像名称 | 不可省略 |
| tag | 版本标签 | latest |
所以下面三种写法指的是同一个镜像:
docker pull nginx
docker pull nginx:latest
docker pull docker.io/library/nginx:latest
其他 registry 的镜像需要写出完整地址,例如 GitHub 的 ghcr.io/owner/app:1.0、Google 的 gcr.io/distroless/static-debian13。
常见的 tag 命名
官方镜像通常同时提供多种变体:
| tag 示例 | 含义 |
|---|---|
python:3.14 | 基于 Debian 的完整版,包含编译工具等大量软件包 |
python:3.14-slim | 精简版 Debian,只保留运行 Python 所需的内容 |
python:3.14-alpine | 基于 Alpine Linux,体积最小 |
node:24-trixie | 指定 Debian 版本代号(trixie = Debian 13) |
nginx:1.30 / nginx:1.31 | nginx 的 stable(偶数)与 mainline(奇数)版本 |
本节后面会实际下载这三种 Python 镜像,并比较它们的大小。
下载镜像:docker pull
如果本机没有镜像,运行 docker run 时会自动下载;docker pull 则只下载,不运行。对已经有的镜像再次执行 pull,Docker 会检查是否有更新:
$ docker pull nginx:1.30
1.30: Pulling from library/nginx
Digest: sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb
Status: Image is up to date for nginx:1.30
docker.io/library/nginx:1.30
Image is up to date 表示本机上的已经是最新版本,无需重新下载。最后一行是镜像的完整名称,可以看到默认的 registry docker.io 与命名空间 library。
亲眼看看“共享层”
接着下载 nginx 的另一个版本 1.31:
$ docker pull nginx:1.31
1.31: Pulling from library/nginx
ecc510c1e359: Already exists
807ab930f3a0: Pull complete
04bdbc7ea6b5: Pull complete
f7e1db57b58b: Pull complete
8020170dc65f: Pull complete
1efc53192927: Pull complete
947d22046304: Pull complete
Digest: sha256:f9ea18bfa4fad859e1ed38259d711da7ccad2c3516e875cec3351a57c859f571
Status: Downloaded newer image for nginx:1.31
docker.io/library/nginx:1.31
第一层 ecc510c1e359 显示 Already exists:nginx 1.30 和 1.31 都以同一个 Debian 13 基础层开始,这一层已经在硬盘上,无需重新下载。这就是第 1 节所说的“镜像共享底层”。
下载 python:3.14-slim 时也一样,它同样基于 Debian 13:
$ docker pull python:3.14-slim
3.14-slim: Pulling from library/python
ecc510c1e359: Already exists
a5883d972f3b: Pull complete
6aaf5b0aae75: Pull complete
bb8166eb34e6: Pull complete
Digest: sha256:a2b82f3c48559aa0a8446d9af49826b6e2b2016f4cd2afabfe6013ec53729170
Status: Downloaded newer image for python:3.14-slim
docker.io/library/python:3.14-slim
查看本机镜像:docker images
$ docker images
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
hello-world:latest 5e2309035332 25.9kB 9.49kB U
nginx:1.30 9bf97bd7714f 242MB 66.5MB
nginx:1.31 f9ea18bfa4fa 243MB 66.7MB
ubuntu:26.04 f144425ff09b 162MB 45.6MB
Docker 29 的
docker images输出格式与旧版不同。旧版字段是REPOSITORY TAG IMAGE ID CREATED SIZE,网上很多教程仍然使用旧格式;看到不一样不用紧张,内容是一样的。
| 字段 | 含义 |
|---|---|
| IMAGE | 名称与 tag |
| ID | 镜像 ID 的前 12 位 |
| DISK USAGE | 解压后在硬盘上占用的空间 |
| CONTENT SIZE | 压缩后的内容大小,大约等于下载量 |
| EXTRA | U 表示有容器正在使用(In use),这里是上一节留下的 hello-world 容器 |
docker image ls 和 docker images 是同一个命令。常用的筛选方式:
$ docker images -q
b9767f56a1cc
a2b82f3c4855
9bf97bd7714f
f9ea18bfa4fa
f6a589d43c42
f144425ff09b
5e2309035332
-q 只输出 ID,常用于搭配其他命令进行批量处理。docker images nginx 只列出 nginx,docker images --filter dangling=true 列出没有名称的“悬空”镜像(通常是重新构建后被替换的旧版本)。
比较 slim、alpine 与完整版
再下载另外两个 Python 版本:
$ docker pull python:3.14-alpine
3.14-alpine: Pulling from library/python
e2de96513ba9: Pull complete
48f6a2588427: Pull complete
2a22c5887fa2: Pull complete
d486488257d0: Pull complete
Digest: sha256:f6a589d43c42b9e7f7dc67a12d37132491f362859a5d750607710cc56da3bc72
Status: Downloaded newer image for python:3.14-alpine
docker.io/library/python:3.14-alpine
$ docker pull python:3.14
3.14: Pulling from library/python
4846f2900730: Pull complete
62fe2e747f69: Pull complete
4dc3950125eb: Pull complete
b2eb680928d4: Pull complete
083b5813628d: Pull complete
9b0ef59a9f4a: Pull complete
6e255bfcc16c: Pull complete
Digest: sha256:b9767f56a1cc620aa72d38cc3557d26412e38a4597c92953476136b78894ccbd
Status: Downloaded newer image for python:3.14
docker.io/library/python:3.14
$ docker images python
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
python:3.14 b9767f56a1cc 1.63GB 433MB
python:3.14-alpine f6a589d43c42 82.6MB 21MB
python:3.14-slim a2b82f3c4855 180MB 45.7MB
同样是 Python 3.14,差距非常大:
| 版本 | 下载量(CONTENT SIZE) | 硬盘空间(DISK USAGE) |
|---|---|---|
python:3.14 | 433 MB | 1.63 GB |
python:3.14-slim | 45.7 MB | 180 MB |
python:3.14-alpine | 21 MB | 82.6 MB |
- 完整版包含 gcc 等编译工具,适合需要在镜像中编译软件包的情况(或作为多阶段构建的构建阶段)。
- slim 是大部分应用程序的好选择。
- alpine 体积最小,但它使用 musl 而不是 glibc,有些需要编译的软件包(例如部分 Python 包)在 Alpine 上安装会比较麻烦。不确定时,选
slim通常更稳妥。
给镜像添加标签:docker tag
docker tag 不会复制镜像,只是添加另一个名称,使其指向同一份内容:
$ docker tag nginx:1.30 myname/nginx:v1
$ docker images --filter reference=nginx:1.30 --filter reference=myname/nginx
IMAGE ID DISK USAGE CONTENT SIZE EXTRA
myname/nginx:v1 9bf97bd7714f 242MB 66.5MB
nginx:1.30 9bf97bd7714f 242MB 66.5MB
两行的 ID 相同,表示它们是同一个镜像。推送到 Docker Hub 前,需要用这种方式将镜像命名为 你的账号/名称:tag,见推送到 Docker Hub。
tag 不等于固定版本
tag 只是一个“标签”,维护者可以随时将它指向新的内容,nginx:1.30 下个月可能会指向 1.30.6。需要完全固定时,可以使用 digest(内容的 SHA256 哈希):
$ docker images --digests nginx
REPOSITORY TAG DIGEST IMAGE ID CREATED SIZE
nginx 1.30 sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb 9bf97bd7714f 6 days ago 242MB
nginx 1.31 sha256:f9ea18bfa4fad859e1ed38259d711da7ccad2c3516e875cec3351a57c859f571 f9ea18bfa4fa 6 days ago 243MB
docker pull nginx@sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb
使用 digest 下载,永远会得到完全相同的内容。
删除镜像:docker rmi
如果有容器(包括已停止的容器)正在使用这个镜像,就无法删除:
$ docker run -d --name web nginx:1.30
e34409bcf1727f02fc3b0558d202dd057f2116b4a2e9186f83bbed4625842272
$ docker rmi nginx:1.30
Error response from daemon: conflict: unable to delete nginx:1.30 (must be forced) - container e34409bcf172 is using its referenced image 9bf97bd7714f
先删除使用它的容器,再删除镜像:
$ docker rm -f web
web
$ docker rmi nginx:1.30
Untagged: nginx:1.30
Deleted: sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb
Untagged:移除名称。Deleted:没有其他名称指向它时,镜像本身才会真正删除。如果还有myname/nginx:v1这类别名指向同一个镜像,就只会看到Untagged。
清理不需要的镜像:
docker image prune # 只删除悬空镜像(没有名称的 <none>)
docker image prune -a # 删除所有未被容器使用的镜像
镜像的分层结构:docker history
docker history 会列出镜像的每一层,以及这一层由 Dockerfile 的哪个命令生成:
$ docker history nginx:1.30
IMAGE CREATED CREATED BY SIZE COMMENT
9bf97bd7714f 6 days ago CMD ["nginx" "-g" "daemon off;"] 0B buildkit.dockerfile.v0
<missing> 6 days ago STOPSIGNAL SIGQUIT 0B buildkit.dockerfile.v0
<missing> 6 days ago EXPOSE map[80/tcp:{}] 0B buildkit.dockerfile.v0
<missing> 6 days ago ENTRYPOINT ["/docker-entrypoint.sh"] 0B buildkit.dockerfile.v0
<missing> 6 days ago COPY 30-tune-worker-processes.sh /docker-ent… 16.4kB buildkit.dockerfile.v0
<missing> 6 days ago COPY 20-envsubst-on-templates.sh /docker-ent… 12.3kB buildkit.dockerfile.v0
<missing> 6 days ago COPY 15-local-resolvers.envsh /docker-entryp… 12.3kB buildkit.dockerfile.v0
<missing> 6 days ago COPY 10-listen-on-ipv6-by-default.sh /docker… 12.3kB buildkit.dockerfile.v0
<missing> 6 days ago COPY docker-entrypoint.sh / # buildkit 8.19kB buildkit.dockerfile.v0
<missing> 6 days ago RUN /bin/sh -c set -x && groupadd --syst… 88.2MB buildkit.dockerfile.v0
<missing> 6 days ago ENV DYNPKG_RELEASE=1~trixie 0B buildkit.dockerfile.v0
<missing> 6 days ago ENV PKG_RELEASE=1~trixie 0B buildkit.dockerfile.v0
<missing> 6 days ago ENV ACME_VERSION=0.4.1 0B buildkit.dockerfile.v0
<missing> 6 days ago ENV NJS_RELEASE=1~trixie 0B buildkit.dockerfile.v0
<missing> 6 days ago ENV NJS_VERSION=1.0.1 0B buildkit.dockerfile.v0
<missing> 6 days ago ENV NGINX_VERSION=1.30.5 0B buildkit.dockerfile.v0
<missing> 6 days ago LABEL maintainer=NGINX Docker Maintainers <d… 0B buildkit.dockerfile.v0
<missing> 7 days ago # debian.sh --arch 'amd64' out/ 'trixie' '@1… 87.7MB debuerreotype 0.17
从下往上读:
- 最底层是 Debian 13(trixie)基础层,87.7 MB。
- 中间的
RUN ... groupadd ...安装了 nginx 本身,88.2 MB,是最大的一层。 COPY放入启动脚本,只有几 KB。ENV、EXPOSE、CMD等只是设置,大小为 0B。
<missing> 不是错误,只表示这些中间层是在其他机器上构建的,本机没有它们各自独立的 ID。
分层有两个好处:
- 共享:多个镜像都以 Debian 13 为基础时,该层只存一份、只下载一次(前面的
Already exists)。 - 缓存:构建镜像时,没有变化的层可以直接复用,这是构建缓存的基础。
容器启动时,Docker 会在这些只读层上面添加一层可写层。容器内新增或修改的文件都写在这一层,容器删除时这一层也会随之消失,因此需要保存的数据应放在 Volume 中。
在 Docker Desktop 中点击某个镜像,也可以看到相同的分层信息:

查看镜像设置:docker inspect
docker inspect 会输出镜像的完整设置(一大段 JSON)。使用 --format 只提取需要的字段:
$ docker inspect --format '{{.Config.Cmd}}' nginx:1.30
[nginx -g daemon off;]
$ docker inspect --format '{{.Os}}/{{.Architecture}}' nginx:1.30
linux/amd64
$ docker inspect --format '{{json .Config.ExposedPorts}}' nginx:1.30
{"80/tcp":{}}
$ docker inspect --format '{{range .Config.Env}}{{println .}}{{end}}' nginx:1.30
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
NGINX_VERSION=1.30.5
NJS_VERSION=1.0.1
NJS_RELEASE=1~trixie
ACME_VERSION=0.4.1
PKG_RELEASE=1~trixie
DYNPKG_RELEASE=1~trixie
从中可以知道:容器启动时默认运行 nginx -g daemon off;、这是 linux/amd64 版本、开放了 80 端口,以及镜像内置的环境变量。
导出与导入:docker save / load
在无法联网的机器之间迁移镜像时,可以将镜像保存为一个 tar 文件:
$ docker save -o nginx-1.30.tar nginx:1.30
$ ls -lh nginx-1.30.tar
-rw------- 1 root root 63.4M Oct 12 14:41 nginx-1.30.tar
$ docker rmi nginx:1.30
Untagged: nginx:1.30
Deleted: sha256:9bf97bd7714f5e24c1ccd545ecb9eb5435cb6d109c97cebb15e7e455e0239edb
$ docker load -i nginx-1.30.tar
Loaded image: nginx:1.30
将 tar 文件复制到另一台机器,运行 docker load 就能使用,无需连接 Docker Hub。
用 Docker Desktop 管理镜像
在 Docker Desktop 左侧菜单中点击 Images,可以查看本机所有镜像,相当于运行 docker images;右侧的按钮可以直接运行或删除镜像:

命令汇总
| 命令 | 作用 |
|---|---|
docker pull 名称:tag | 下载镜像 |
docker images | 列出本机镜像 |
docker images -q | 只列出 ID |
docker tag 来源 新名称 | 添加新的名称 / 标签 |
docker rmi 名称 | 删除镜像 |
docker image prune -a | 删除所有未使用的镜像 |
docker history 名称 | 查看分层 |
docker inspect 名称 | 查看设置 |
docker save -o a.tar 名称 | 导出为 tar 文件 |
docker load -i a.tar | 从 tar 文件导入 |
下一节介绍容器从创建到删除会经历哪些状态。
重点回顾
- 镜像名称是
[registry/]储存库:tag,官方镜像没有前缀。 - 多个镜像可以共享相同的底层,只下载、存储一次。
- slim 是多数应用程序的好选择;alpine 体积最小,但兼容性较差。
docker history显示每一层由哪个命令生成。
动手练习
练习 1:下载 alpine:3.23 和 python:3.14-alpine,观察第二次下载时是否出现 Already exists。
提示
如果两者使用相同的 Alpine 基础层,第二次下载会显示该层 Already exists,无需重新下载。使用 docker history 可以比较两者最底层的内容。
练习 2:给 nginx:1.30 添加一个新名称 mysite/web:test,再删除这个新名称。原来的 nginx:1.30 还在吗?
答案
docker tag nginx:1.30 mysite/web:test
docker rmi mysite/web:test
还在。docker rmi 删除名称时只会显示 Untagged;只要镜像还有其他名称,实际内容就不会被删除。
常见问题
latest 是最新版吗?
不一定。latest 只是一个普通的 tag 名称,由作者决定指向哪个版本。生产环境请写明确的版本,例如 nginx:1.30。
Docker 29 的 docker images 字段怎么和网上的不一样?
Docker 29 改成 IMAGE ID DISK USAGE CONTENT SIZE EXTRA,旧版是 REPOSITORY TAG IMAGE ID CREATED SIZE,见本章说明。
该选 slim 还是 alpine?
大部分应用程序选 slim。alpine 最小,但使用 musl libc,部分需要编译的包(特别是 Python)安装时可能失败或很慢。
更新于 2026年10月14日