1. 引言

我们之前已经了解了 Docker 镜像和容器的区别。简单来说,镜像就像 Java 中的类,而容器则像是类的实例对象

在本文中,我们将聚焦于 Docker 镜像的各种删除方式,帮助我们释放磁盘空间并保持 Docker 引擎的整洁。

2. 为什么需要删除 Docker 镜像?

Docker 引擎负责存储镜像、运行容器,以及管理全局卷、网络等资源。为此,Docker 引擎会预留一部分磁盘空间作为“存储池”

一旦这个存储池满了,Docker 就会停止工作。我们无法再创建或下载新的镜像,容器也会无法运行。

镜像是 Docker 存储池中占用空间最多的部分,因此我们需要删除不需要的镜像来释放空间

此外,删除镜像也有助于保持 Docker 引擎的整洁。例如,在开发过程中我们可能会创建大量临时镜像,或者下载了一些用于测试的镜像,这些都可以在使用后删除。

对于从远程仓库拉取的镜像,删除后我们可以随时再次拉取。但如果是自己构建的镜像,就需要注意备份。一旦删除且未保存或上传,镜像将永久丢失。可以通过推送到仓库或 导出为 TAR 文件 来进行备份。

3. 下载 PostgreSQL 13 Beta 镜像

PostgreSQL 是一个开源的关系型数据库。我们以两个 PostgreSQL 13 beta 的 Docker 镜像为例进行演示。这两个镜像体积较小,下载速度快。由于是 beta 版本,我们本地 Docker 引擎中应该还没有它们。

在下载之前,先查看当前 Docker 引擎中镜像的占用情况:

$ docker system df --format 'table {{.Type}}\t{{.TotalCount}}\t{{.Size}}'

输出示例(仅显示第一行):

TYPE                TOTAL               SIZE
Images              71                  7.813GB

接下来,下载两个 PostgreSQL 镜像并再次查看:

$ docker pull postgres:13-beta1-alpine
$ docker pull postgres:13-beta2-alpine
$ docker system df --format 'table {{.Type}}\t{{.TotalCount}}\t{{.Size}}'

输出示例:

TYPE                TOTAL               SIZE
Images              73                  8.119GB

可以看到,镜像数量增加了 2 个,总大小增加了约 300MB。

4. 删除单个镜像

我们先用 PostgreSQL 13 beta 2 镜像启动一个容器:

$ docker run -d -e POSTGRES_PASSWORD=secr3t postgres:13-beta2-alpine
$ docker ps --format 'table {{.ID}}\t{{.Image}}\t{{.Status}}'

输出示例:

CONTAINER ID        IMAGE                      STATUS
527bfd4cfb89        postgres:13-beta2-alpine   Up Less than a second

尝试删除该镜像:

$ docker image rm postgres:13-beta2-alpine

此时会报错,因为该镜像正在被一个容器使用:

Error response from daemon: conflict: unable to remove repository reference
"postgres:13-beta2-alpine" (must force) - container 527bfd4cfb89 is using its referenced image cac2ee40fa5a

我们需要先停止并删除容器:

$ docker container stop 527bfd4cfb89
$ docker container rm 527bfd4cfb89

然后再删除镜像:

$ docker image rm postgres:13-beta2-alpine

输出示例:

Untagged: postgres:13-beta2-alpine
Untagged: postgres@sha256:b3a4ebdb37b892696a7bd7e05763b938345f29a7327fc17049c7148c03ff6a92
removed: sha256:cac2ee40fa5a40f0abe53e0138033fe7a9bcee28e7fb6c9eaac4d3a2076b1a86
...

最后确认空间已释放:

$ docker system df

输出示例:

TYPE                TOTAL               SIZE
Images              72                  7.966GB

5. 按名称删除多个镜像

再次拉取 beta 2 镜像:

$ docker pull postgres:13-beta2-alpine

现在我们想同时删除 beta1 和 beta2 的镜像。由于 docker image rm 不支持按名称过滤,我们可以借助 Linux 命令组合实现:

$ docker image ls --format '{{.Repository}}:{{.Tag}}' | grep '^postgres:13-beta'

输出示例:

postgres:13-beta2-alpine
postgres:13-beta1-alpine

然后执行删除命令:

$ docker image rm $(docker image ls --format '{{.Repository}}:{{.Tag}}' | grep '^postgres:13-beta')

⚠️ 注意:必须确保没有容器使用这些镜像,否则删除失败。

6. 按大小删除镜像

为了节省空间,可以优先删除体积较大的镜像。使用如下命令按大小排序:

$ docker image ls | sort -k7 -h -r

输出示例:

collabora/code   4.2.5.3         8ae6850294e5   3 weeks ago  1.28GB
nextcloud        19.0.1-apache   25b6e2f7e916   6 days ago   752MB
nextcloud        latest          6375cff75f7b   5 weeks ago  750MB

我们可以通过镜像 ID 一次性删除多个镜像:

$ docker image rm 6375cff75f7b 5c44e8445287

确认删除后空间释放:

TYPE                TOTAL               SIZE
Images              69                  7.128GB

7. 按创建时间删除镜像

Docker 也支持按创建时间删除镜像。我们可以使用 docker image prune 命令:

$ docker image prune -a --force --filter "until=2020-07-07T00:00:00"

也可以指定时间跨度(单位为小时):

$ docker image prune -a --force --filter "until=168h"

⚠️ 注意:-a 参数表示删除所有未被使用的镜像,非常危险,使用时需谨慎。

8. 清理容器和镜像

docker image prune 可以批量删除未被使用的镜像,与之配合使用的还有 docker container prune,用于批量删除已停止的容器。

清理容器

$ docker container prune

确认删除:

WARNING! This will remove all stopped containers.
Are you sure you want to continue? [y/N] y

清理镜像

$ docker image prune

默认只删除“悬空镜像(dangling images)”,即未被任何容器使用的中间镜像。

如果想删除所有未被使用的镜像:

$ docker image prune -a

⚠️ 危险操作:该命令会删除所有未被容器引用的镜像,慎用!

9. 强制删除容器和镜像

9.1 删除所有容器

$ docker rm $(docker ps -qa)

⚠️ 如果有容器正在运行,会报错:

Error response from daemon: cannot remove container "/<CONTAINER_NAME>":
container is running: stop the container before removing or force remove

9.2 强制删除所有容器

$ docker rm -f $(docker ps -qa)

-f 参数会强制终止并删除所有容器,包括正在运行的。

9.3 删除所有镜像

$ docker rmi $(docker images -aq)

⚠️ 如果有容器正在使用某个镜像,删除失败。

9.4 强制删除所有镜像

$ docker rmi -f $(docker images -aq)

-f 参数会强制删除镜像,即使它被容器引用(但不会删除正在运行的容器所使用的镜像)。

⚠️ 删除后可能出现 <none> 标签的“悬空镜像”,可以后续使用 docker image prune 清理。

10. 总结

本文我们学习了以下内容:

✅ 删除单个镜像的方法
✅ 按名称、大小、创建时间批量删除镜像
✅ 使用 docker image prunedocker container prune 清理资源
✅ 强制删除所有容器和镜像的方式

⚠️ 注意:删除操作具有破坏性,特别是带有 -f-a 参数的命令,务必确认后再执行。建议在执行前使用 docker system df 检查当前存储情况,避免误删重要镜像或容器。


原始标题:Removing Docker Images