目錄
清理 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(含具名的) |
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才包含具名的。- 設定日誌上限
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日