Docker 镜像管理:从拉取到删除,再到分层原理

镜像管理,说白了就是 Docker 的命根子。

你想想看,没有镜像,容器跑什么?我刚开始接触 Docker 那会儿,总觉得镜像就是个“安装包”,拉下来用就完事了。后来线上出过一次事故,才明白这里面门道多着呢。今天咱们就把这块彻底掰开揉碎了讲一遍。

镜像仓库

镜像仓库,就是放镜像的地方,类似于代码的 Git 仓库。

Docker Hub 是最大的公共仓库,官方的 Nginx、Redis、MySQL 都在上面。但我们一般不会直接用,原因很简单:慢,特别慢。

我习惯用国内的加速器,比如阿里云、腾讯云、中科大的镜像站。还有一个方法就是自建仓库,用 Harbor 或者 Registry。

# 登录到一个仓库
docker login registry.example.com

# 登出
docker logout
小技巧:如果你的团队需要管理私有镜像,强烈建议上 Harbor。它支持镜像复制、漏洞扫描、权限控制,比裸 Registry 要安全得多。

拉取镜像

拉取镜像是使用 Docker 的起点。

我记得刚带新人时,总有人问我:“为什么我 pull 一个镜像那么慢?”原因很简单——没配加速器。

# 拉取最新版的 Ubuntu 镜像
docker pull ubuntu:latest

# 拉取指定版本的 Nginx
docker pull nginx:1.25.3

# 从私有仓库拉取
docker pull registry.example.com/myapp:v1.0.0

拉取过程其实分几步:

  1. 你输入 docker pull 命令
  2. Docker 去仓库查这个镜像的 manifest
  3. 按 manifest 列出的 layer 列表,逐个下载
  4. 下载完成后解压到本地存储
我曾经踩过的坑:有一次线上 pull 镜像,一直卡在“Waiting”状态。排查半天发现是网络代理没配对,Docker daemon 拉取时走了错误的 DNS。记住,docker pull 依赖的是 Docker daemon 的网络环境,不是你终端的环境。

查看镜像

拉下来的镜像存在哪里?如何管理?

# 列出本地所有镜像
docker images

# 或者
docker image ls
列名 含义
REPOSITORY 镜像来源仓库
TAG 标签,通常是版本号
IMAGE ID 镜像唯一标识,只显示前12位
CREATED 镜像构建时间
SIZE 镜像大小(注意是逻辑大小)

还有一个我常用的命令,查看镜像的详细配置:

# 查看镜像的底层信息(JSON格式)
docker inspect nginx:1.25.3

# 只看分层信息
docker history nginx:1.25.3

docker history 这个命令很有用,它能告诉你这个镜像的“家族史”——每一层是谁创建的,做了哪些改动。我在排查镜像体积过大时,第一件事就是看 history,看看哪层引入了无用文件。

删除镜像

镜像越拉越多,磁盘报警了怎么办?删。

# 删除一个镜像
docker rmi nginx:1.25.3

# 按 IMAGE ID 删除
docker rmi abc123def456

# 删除所有未被使用的镜像(谨慎使用)
docker image prune -a
注意:如果某个镜像正在被容器使用,你是删不掉的。Docker 会提示:「image is being used by running container」。解决方案:先停掉容器,或者加 -f 参数强制删除。但我一般不建议强制删,容易出问题。

我见过一个案例:有人为了清理空间,对着一台生产机器执行了 docker image prune -a,结果所有没在运行的容器依赖的镜像全被删了,下次启动容器时重新下载,生生拖慢了上线流程。所以,清镜像之前,先想清楚哪些是真正没用的。

镜像分层原理

这是 Docker 最核心的设计,也是面试高频题。说人话就是:镜像是由一层一层只读文件系统堆叠而成的。

为什么这样做?

  • 节省空间:多个镜像可以共享相同的底层。比如 Ubuntu:20.04 和 Ubuntu:22.04,有一部分底层是相同的,不用重复下载。
  • 加速构建:Dockerfile 改动了最后几行,只需重新构建上面几层,底层直接拿缓存。
  • 便于分发:层是增量更新的,网络传输只传变化的部分。

每一层本质上就是一个 Layer Diff,记录了文件和目录的变更。Docker 把这些层用 UnionFS(联合文件系统)叠加起来,对外呈现为一个完整的文件系统。

下面这张图描绘了镜像的层级结构:

Docker 镜像分层结构图 容器可写层 镜像层 5(应用层) 镜像层 4(配置文件) 镜像层 3(运行时库) 镜像层 2(操作系统层) 基础层(BootFS) 写时复制(CoW) 只有修改时才复制 到底层 只读层 所有镜像层 都是只读的

看图就很清晰了:最下面是基础层,往上是操作系统层、运行时库、配置、应用层。最顶上那层是容器可写层,容器运行期间产生的文件改动都写在这里。

写时复制(Copy-on-Write) 是 Docker 的关键机制。容器启动时,所有镜像层保持只读,只有需要修改文件时,Docker 才把文件从底层复制到可写层进行修改。这样既节省空间,又不会污染原始镜像。

我的实战经验:你在 Dockerfile 里每写一个 RUN,就会产生一层新镜像。所以,我会习惯把多个 RUN apt-get 合并成一个,以减少层数,也减少最终镜像体积。

还有一点你可能不知道:docker pull 下载的是分层压缩包,并不是整个镜像一次下载完。如果你网络中断,Docker 会从断点续传,已经下载好的层不会重新下载。这就是分层的另一个好处。

好了,镜像管理这块,我们核心讲了五件事:仓库、拉取、查看、删除和分层原理。记住这些,你日常用 Docker 就不会出大问题了。