目录
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 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日