目录

Docker 清理教程:用 prune 命令释放磁盘空间

使用 Docker 一段时间后,旧镜像、已停止的容器、构建缓存和无人使用的 Volume 会越积越多,轻易就占用数十 GB。本节先找出空间被什么占用,再安全清理。所有输出都是在同一环境中依次执行的结果。

先看看用了多少

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          13        3         2.886GB   2.377GB (82%)
Containers      4         1         98.3kB    16.38kB (16%)
Local Volumes   4         1         40.61MB   40.61MB (100%)
Build Cache     151       0         3.554GB   2.954GB
字段含义
TOTAL总数
ACTIVE正在被容器使用的数量
SIZE占用的空间
RECLAIMABLE可以清理的部分(未被使用)

这个环境有 13 个镜像,只有 3 个正在使用,2.377 GB(82%)可以回收;构建缓存占用更多,有 2.954 GB。加上 -v 可以查看每个镜像、容器和 Volume 的详细信息:docker system df -v。

当前的镜像和容器:

$ docker images
IMAGE               ID             DISK USAGE   CONTENT SIZE   EXTRA
adminer:latest      74f29c416e14        164MB         43.8MB
alpine:3.23         85fe1e81d675       26.6MB         8.21MB   U
hello-node:latest   4063457524bb        245MB         62.2MB
myapp:latest        80cb5c41a286       54.9MB         24.8MB   U
mysql:8.4           24989179f588       1.12GB          254MB
nginx:1.30          9bf97bd7714f        242MB         66.5MB
nginx:1.30-alpine   0985e772fb9f       93.7MB           27MB   U
node:24-alpine      ebfe2f904627        242MB           62MB
postgres:18         74935e722416        650MB          169MB
python:3.14-slim    a2b82f3c4855        180MB         45.7MB
redis:8-alpine      3811787313eb        161MB         39.6MB
registry:3          ddf754342cfc       86.9MB         20.7MB
ubuntu:26.04        f144425ff09b        162MB         45.6MB
$ docker ps -a
CONTAINER ID   IMAGE               COMMAND                  CREATED         STATUS                     PORTS     NAMES
cc43746c9a29   alpine:3.23         "true"                   7 seconds ago   Exited (0) 6 seconds ago             anon1
7e269fff858b   nginx:1.30-alpine   "/docker-entrypoint.…"   8 seconds ago   Up 7 seconds               80/tcp    web
bf5ff318eb63   alpine:3.23         "echo done"              8 seconds ago   Exited (0) 7 seconds ago             old2
b580380c1fd2   myapp               "cat /version.txt"       9 seconds ago   Exited (0) 8 seconds ago             old1

EXTRA 列中的 U 表示 In Use(有容器正在使用)。容器中只有 web 正在运行,其他三个都已结束(Exited),但仍占用空间。

分项清理

命令清理对象
docker container prune所有已停止的容器
docker image prune悬空镜像(没有名称的 <none>)
docker image prune -a所有没有被任何容器使用的镜像
docker builder prune构建缓存
docker volume prune未使用的匿名 Volume
docker volume prune -a未使用的所有 Volume(包括具名 Volume)
docker network prune未使用的自定义网络

每个命令都会先要求确认(Are you sure you want to continue? [y/N]),加上 -f 可以跳过确认,适合写入脚本。以下示例都加了 -f。

删除已停止的容器

$ docker container prune -f
Deleted Containers:
cc43746c9a2993bda0fb21ab3f161b78603353714f396f86fa8c4b5caf90e25a
bf5ff318eb6331a05239ad7fa39420ff96dc1c8f84b9a3548ce38a0f71a2d63a
b580380c1fd2dc6cca2dc6e009bb877c3eb2df1cf388664a32c8932aff8169fa

Total reclaimed space: 16.38kB

三个已停止的容器已删除,正在运行的 web 不受影响。

如果使用 Docker Desktop,也可以在 Containers 界面中勾选容器,然后点击 Delete:

在 Docker Desktop 的 Containers 界面中勾选容器,然后点击 Delete
Docker Desktop:勾选容器后点击 Delete。图片来源:Docker 官方文档(Apache-2.0)

Docker 29:重新构建不再留下 <none> 镜像

以前用同一个名称重新构建镜像(例如多次执行 docker build -t myapp .),旧版本会变成名称为 <none> 的“悬空镜像”,需要用 docker image prune 清理。Docker 29 实测如下:

$ docker build -q --build-arg VERSION=4 -t myapp:latest .
sha256:3f33bc33eb36171280e9b90d904e25c58b2dcf509390536580ffacafc35d4595

$ docker images --filter dangling=true
IMAGE   ID             DISK USAGE   CONTENT SIZE   EXTRA

$ docker ps -a --filter name=old1
CONTAINER ID   IMAGE          COMMAND              CREATED          STATUS                      PORTS     NAMES
b580380c1fd2   80cb5c41a286   "cat /version.txt"   26 seconds ago   Exited (0) 26 seconds ago             old1

连续构建了 4 次 myapp:latest,但 --filter dangling=true 的结果为空。Docker 29 默认使用 containerd 镜像存储,旧版本在名称被新镜像替换时不再保留为 <none>。仍在使用旧版本的容器(old1)的 IMAGE 列会改为显示镜像 ID。

因此,在 Docker 29 上,docker image prune(不加 -a)通常没什么可清理的,真正占空间的是未被使用但仍有名称的镜像和构建缓存。

删除匿名 Volume

$ docker volume ls
DRIVER    VOLUME NAME
local     6f6f8ce590c609d4f39b3a676282da88866c8ab20a064132f7746c3cf6717f2c
local     991c93cb6ebeac8570e9c15a89b4225c2bb5e20cbfde2f5bf665fa4dfa23a1aa
local     5396795eeeaab8415295814207a02f75f6ea136d5c34574ba9b16ecdc1b975f9
local     cleanup-demo_pgdata

$ docker volume prune -f
Deleted Volumes:
5396795eeeaab8415295814207a02f75f6ea136d5c34574ba9b16ecdc1b975f9
991c93cb6ebeac8570e9c15a89b4225c2bb5e20cbfde2f5bf665fa4dfa23a1aa
6f6f8ce590c609d4f39b3a676282da88866c8ab20a064132f7746c3cf6717f2c

Total reclaimed space: 0B

$ docker volume ls
DRIVER    VOLUME NAME
local     cleanup-demo_pgdata
  • 前三个长名称是匿名 Volume。例如,postgres 镜像的 Dockerfile 声明了 VOLUME,即使运行时没有挂载,Docker 也会自动创建匿名 Volume;删除容器后它仍会保留(参见Volume 与数据持久化)。
  • docker volume prune 只会删除未使用的匿名 Volume。
  • cleanup-demo_pgdata 是 Compose 项目的具名 Volume。虽然执行 docker compose down 后已没有容器在使用它,但它不会被删除。

删除构建缓存

$ docker builder du | tail -n 3
Private:	2.996GB
Reclaimable:	3.596GB
Total:		3.596GB

$ docker builder prune -f --filter until=1h | tail -n 3
lv85kuv5xx5h65k941qjoxecz               	true 	98.69kB   	About an hour ago
kc9tcgw8l1aq9dz1agx096se0               	true 	870kB     	About an hour ago
Total:	1.662GB

$ docker builder prune -f | tail -n 3
6os07ml167zpcfh09ushitk2b               	true 	8.285kB   	38 minutes ago
7ir7u28j6esk2x7pyu6q38kvk               	true 	74.75MB   	38 minutes ago
Total:	1.334GB
  • docker builder du 显示构建缓存共 3.596 GB,全部可以回收。
  • --filter until=1h 只删除超过 1 小时未使用的缓存,清理了 1.662 GB。
  • 不加筛选条件则又清理了 1.334 GB。

删除构建缓存的代价是下次构建时必须重新执行所有步骤(例如重新运行 npm ci、pip install),速度会比较慢,但不会影响任何镜像或容器。

一次清理:docker system prune

docker system prune

会删除:已停止的容器、未使用的网络、悬空镜像和构建缓存。

docker system prune -a

此外还会删除所有未使用的镜像,下次用到时需要重新下载。

实测:--volumes 会删除数据库数据吗?

许多教程(包括本教程旧版)警告说:docker system prune --volumes 会删除 docker compose down 后“暂时无人使用”的数据库 Volume。Docker 29 实测如下:

$ docker system prune --volumes -f
Deleted Containers:
871f1c408d23dd413804105498b5520385dfafc9e558c02447ed940684bbc483

Deleted Volumes:
e5d0caa972c5323d5a64e9baf5fcb21d66ce7fbb4879bdcc7aa068a14fdbbf76

Total reclaimed space: 8.192kB

$ docker volume ls
DRIVER    VOLUME NAME
local     cleanup-demo_pgdata

--volumes 只删除了一个匿名 Volume,Compose 数据库的具名 Volume cleanup-demo_pgdata 仍然存在。从 Docker 23 开始,volume prune 和 system prune --volumes 默认只处理匿名 Volume。

真正会删除具名 Volume 的是 docker volume prune -a:

$ docker volume prune -a -f
Deleted Volumes:
cleanup-demo_pgdata

Total reclaimed space: 40.61MB

$ docker volume ls
DRIVER    VOLUME NAME

这次 cleanup-demo_pgdata 被删除,其中 40.61 MB 的数据库文件也随之消失,无法恢复。

只有确定不需要任何数据时,才使用 docker volume prune -a。要删除特定 Volume,使用 docker volume rm 名称 更安全;Compose 项目则使用 docker compose down -v,只会删除该项目的 Volume。如果使用的是 Docker 20.10 或更早版本,--volumes 仍会删除具名 Volume。

删除所有未使用的镜像

$ docker image prune -a -f | grep -E "^untagged|^Total"
untagged: nginx:1.30
untagged: node:24-alpine
untagged: postgres:18
untagged: python:3.14-slim
untagged: myapp:latest
untagged: mysql:8.4
untagged: redis:8-alpine
untagged: registry:3
untagged: ubuntu:26.04
untagged: adminer:latest
untagged: alpine:3.23
untagged: hello-node:latest
Total reclaimed space: 2.665GB

$ docker images
IMAGE               ID             DISK USAGE   CONTENT SIZE   EXTRA
nginx:1.30-alpine   0985e772fb9f       93.7MB           27MB   U

$ docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          1         1         93.66MB   0B (0%)
Containers      1         1         81.92kB   0B (0%)
Local Volumes   0         0         0B        0B
Build Cache     26        0         599.6MB   506.9MB
  • 除了 web 容器正在使用的 nginx:1.30-alpine,其他 12 个镜像都已删除,共回收 2.665 GB。
  • 最后的 docker system df 显示只剩下 93.66 MB 镜像。

下次运行 docker run 或构建时,这些镜像会自动重新下载。网络较慢,或镜像很大(例如 AI 模型相关镜像往往有数 GB)时,可以考虑使用 --filter 只删除较旧的镜像:

docker image prune -a --filter "until=168h"      # 只删除 7 天前创建的

请注意,until 比较的是镜像的创建时间(镜像作者构建的时间),而不是下载时间。

容器日志也会占用空间

默认的 json-file 日志没有大小上限。下面是在一个持续输出的容器上进行的实测(yes 命令每秒输出大量文本):

$ docker run -d --name noisy alpine:3.23 sh -c "timeout 3 yes hello-docker-log; sleep 600"
863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6

$ docker inspect --format "{{.LogPath}}" noisy
/var/lib/docker/containers/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6-json.log

$ du -h $(docker inspect --format "{{.LogPath}}" noisy)
69.3M	/var/lib/docker/containers/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6/863ccacbc4bcf86a81cc3bf7603cef1d6ecc004553ac4b36dd7ef52172ed3dc6-json.log

$ docker rm -f noisy
noisy

只输出了 3 秒,日志文件就达到 69.3 MB。长期运行且日志很多的容器,日志文件可能增长到数十 GB,而且不会自动删除,直到容器被删除。日志文件位于 /var/lib/docker/containers/容器ID/ 中。在 Linux 主机上,可以这样找出最大的日志文件:

sudo du -h /var/lib/docker/containers/*/*-json.log | sort -h | tail

为单个容器设置上限

$ docker run -d --name noisy --log-opt max-size=10m --log-opt max-file=3 alpine:3.23 sh -c "timeout 3 yes hello-docker-log; sleep 600"
fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161

$ ls -lh $(dirname $(docker inspect --format "{{.LogPath}}" noisy)) | grep json
-rw-------    1 root     root        3.2K Oct 13 01:07 config.v2.json
-rw-r-----    1 root     root        7.2M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log
-rw-r-----    1 root     root        9.5M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log.1
-rw-r-----    1 root     root        9.5M Oct 13 01:07 fab1c34ceecb955dc33c01f0e7aa0a60b4137e68d0fe465d52ce23b49ba66161-json.log.2
-rw-------    1 root     root        1.5K Oct 13 01:07 hostconfig.json

$ docker inspect --format '{{json .HostConfig.LogConfig}}' noisy
{"Type":"json-file","Config":{"max-file":"3","max-size":"10m"}}

$ docker rm -f noisy
noisy

max-size=10m 表示每个文件最大 10 MB,max-file=3 表示最多保留 3 个文件,旧文件会轮换为 .1、.2。相同的输出量下,日志总共只占约 26 MB,之后也不会再增加。

Compose 的写法:

services:
  app:
    image: myapp
    logging:
      options:
        max-size: "10m"
        max-file: "3"

设置全局日志上限

让所有新容器都应用上限:在 Linux 上编辑 /etc/docker/daemon.json;在 Docker Desktop 中则进入 Settings → Docker Engine,编辑相同的 JSON:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  }
}

在 Linux 上修改后运行 sudo systemctl restart docker;在 Docker Desktop 中点击 Apply & restart。只有之后新创建的容器会应用设置。已有容器需要删除后重建(Compose 使用 docker compose up -d --force-recreate)。

Docker Desktop:清理后磁盘空间没有增加

在 Windows 和 macOS 上,Docker 的所有数据都存储在一个虚拟磁盘文件中。删除镜像后,虚拟磁盘中的空间虽然释放了,但文件本身不一定会立即缩小。

  • Docker Desktop:在 Settings → Resources → Advanced 中可以查看和调整虚拟磁盘的上限。Troubleshoot 界面中的 Clean / Purge data 会清空所有 Docker 数据(镜像、容器、Volume 全部删除),只应作为最后手段。
  • Windows(WSL 2):如果 .vhdx 文件仍然很大,可以先运行 wsl --shutdown,再使用 diskpart 的 compact vdisk 压缩对应的 .vhdx 文件。

定期清理建议

在服务器上可以使用 cron 每周运行一次:

docker container prune -f --filter "until=168h"
docker image prune -af --filter "until=168h"
docker builder prune -af --filter "until=168h"

这组命令不会影响任何 Volume,数据库数据是安全的。再配合全局日志上限,磁盘空间就不容易失控。

重点回顾

  • 先用 docker system df 查看,再决定清理什么。
  • image prune -a 删除所有未使用的镜像;builder prune 清理构建缓存。
  • volume prune 只删除匿名 Volume,-a 才会包括具名 Volume。
  • 设置日志上限 max-size 和 max-file。

动手练习

练习 1:写一组可以放进 cron、不会影响任何 Volume 的清理命令,只清理 7 天以上的镜像和构建缓存。

答案
docker image prune -af --filter "until=168h"
docker builder prune -af --filter "until=168h"

常见问题

docker system prune 安全吗?

不加 --volumes 时不会影响任何 Volume;Docker 23 起,即使加上 --volumes 也只会删除匿名 Volume。真正危险的是 docker volume prune -a。

清理后 Windows 的磁盘空间没有增加?

Docker Desktop 的数据存储在虚拟磁盘文件中,删除镜像后文件不一定会立即缩小,详见本章最后一节。

构建缓存可以全部删除吗?

可以,不会影响任何镜像或容器,只是下次构建会比较慢。

更新于 2026年10月14日