3. 镜像查看与管理:从拉取到清理的全流程
镜像拉下来了,然后呢?说实话,我见过不少新手把镜像一拉,就以为万事大吉了。其实真正的挑战在于——你怎么管理这些镜像?怎么知道哪个镜像能用、哪个是垃圾?今天我们就来聊聊镜像查看与管理的那些事。
3.1 docker images:你的镜像仓库清单
docker images 是最基础的命令,但它的输出信息量其实很大。来,先跑一下看看:
$ docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
nginx latest 605c77e624dd 2 weeks ago 141MB
ubuntu 22.04 2dc39ba059dc 3 weeks ago 77.9MB
python 3.11 7e3b0e4b5c2a 4 weeks ago 1.01GB
alpine 3.18 9c6f072447c4 6 weeks ago 7.05MB
这张表里,每一列都有它的意义:
| 列名 | 含义 | 我的经验 |
|---|---|---|
| REPOSITORY | 镜像来源仓库 | 可以是官方仓库(如 nginx),也可以是私有仓库地址 |
| TAG | 镜像版本标签 | 默认是 latest,但生产环境我从不信任 latest |
| IMAGE ID | 镜像唯一标识 | 前 12 位就够了,但完整的是 64 位 SHA256 |
| CREATED | 镜像构建时间 | 注意,这不是你拉取的时间,是构建时间 |
| SIZE | 镜像大小 | 虚拟大小,不是实际占用磁盘空间 |
docker images --format 可以自定义输出格式。我个人习惯用 docker images --format "table {{.Repository}}\t{{.Tag}}\t{{.Size}}" 只看关键信息。
3.2 镜像标签与 ID:命名背后的门道
标签(Tag)和 ID 是镜像的两个身份标识。说白了,标签是给人看的,ID 是给机器用的。
标签的格式通常是 仓库名:标签名。比如 nginx:1.25-alpine,这里的 1.25-alpine 就是标签。我建议你在生产环境里,永远不要用 latest 标签。为什么?因为 latest 会变。你今天拉的是 1.25,明天可能就变成 1.26 了。你想想看,如果 CI/CD 脚本里用了 latest,哪天镜像更新了,你的构建可能就莫名其妙挂了。
镜像 ID 是 SHA256 哈希值,理论上全球唯一。你可以用前 12 位来操作镜像,比如:
$ docker rmi 605c77e624dd
但要注意,如果前 12 位有冲突(概率极低但存在),Docker 会报错让你用更长的 ID。
3.3 虚悬镜像:那些“无名”的镜像
虚悬镜像(dangling images)是什么?就是那些 没有仓库名、没有标签 的镜像。在 docker images 输出里,它们的 REPOSITORY 和 TAG 都显示为 <none>。
虚悬镜像怎么来的?最常见的情况是:你重新构建了一个镜像,新镜像覆盖了旧镜像的标签,旧镜像就变成了虚悬镜像。比如:
# 第一次构建
$ docker build -t myapp:v1 .
# 第二次构建,同样用 myapp:v1 标签
$ docker build -t myapp:v1 .
# 第一次构建的镜像就变成了虚悬镜像
虚悬镜像占磁盘空间,而且没什么用。我建议定期清理:
$ docker image prune
这个命令会删除所有虚悬镜像。加上 -a 参数会删除所有未被使用的镜像(不只是虚悬的)。
docker image prune -f,释放磁盘空间。这个习惯帮我避免了好几次磁盘满的故障。
3.4 中间层镜像:构建过程中的“半成品”
中间层镜像(intermediate images)是 Dockerfile 构建过程中产生的临时镜像。每个 RUN、COPY、ADD 指令都会生成一个中间层镜像。它们平时是隐藏的,用 docker images -a 才能看到。
为什么要关心中间层镜像?两个原因:
- 缓存利用: 下次构建时,如果 Dockerfile 没变,Docker 会复用中间层镜像,加速构建。
- 调试排查: 如果构建失败,你可以用中间层镜像的 ID 启动一个容器,看看当时的环境状态。
举个例子,假设你的 Dockerfile 是这样的:
FROM ubuntu:22.04
RUN apt-get update
RUN apt-get install -y python3
COPY app.py /app/
CMD ["python3", "/app/app.py"]
构建过程中会生成 4 个中间层镜像(包括基础镜像)。如果 apt-get install 那一步失败了,你可以用上一步的中间层镜像启动容器,手动执行安装命令来排查问题。
docker build --rm=false 保留中间层镜像,然后 docker run -it <中间层ID> /bin/bash 进去看看。
3.5 镜像的删除与清理:别让磁盘爆炸
镜像删除看似简单,但里面有不少坑。先看基本命令:
# 按标签删除
$ docker rmi nginx:1.25
# 按 ID 删除
$ docker rmi 605c77e624dd
# 强制删除(即使有容器在使用)
$ docker rmi -f 605c77e624dd
但要注意,如果镜像正在被容器使用,默认是删不掉的。你需要先停止并删除容器,或者用 -f 强制删除(不推荐)。
批量清理的场景更常见。我整理了几个实用命令:
| 场景 | 命令 | 说明 |
|---|---|---|
| 清理虚悬镜像 | docker image prune |
只删 <none>:<none> 的镜像 |
| 清理所有未使用镜像 | docker image prune -a |
删除没有被任何容器引用的镜像 |
| 清理所有资源 | docker system prune -a |
镜像、容器、网络、卷全清理 |
| 按时间过滤删除 | docker image prune -a --filter "until=24h" |
只删 24 小时前创建的镜像 |
docker system prune -a -f,结果把生产环境正在用的镜像也删了(因为测试环境和生产环境共享同一个 Docker 守护进程)。从那以后,我每次清理前都会先跑 docker system df 看看磁盘使用情况,确认哪些镜像可以删。
3.6 知识体系总览
下面这张图帮你理清镜像管理的核心脉络:
3.7 实战:一个完整的镜像管理流程
最后,我分享一个我在项目中常用的镜像管理流程:
- 查看当前镜像列表:
docker images - 检查磁盘使用情况:
docker system df - 清理虚悬镜像:
docker image prune -f - 按条件清理旧镜像:
docker image prune -a --filter "until=72h" -f(保留最近 3 天的) - 确认清理结果:
docker images和docker system df
这个流程我每周跑一次,基本没出过问题。嗯,记住一点——清理前先确认,确认后再执行。别像我当年那样,手一抖把生产镜像给删了。