Docker 磁碟空間不足怎麼辦:映像檔、建置快取、日誌與資料卷清理指南

Docker 出現 no space left on device 怎麼辦?先用 docker system df 定位映像檔、容器和建置快取,再檢查日誌與掛載目錄,分清 prune 和 compose down 的刪除範圍,設定日誌輪替並驗證業務資料。

Docker 磁碟滿了,先執行 docker system df -v 查看資源用量,再檢查容器日誌和掛載目錄。優先清理確認可以重建的建置快取、懸空映像檔與廢棄容器;資料卷需要另外確認歸屬和備份,不能因為顯示「未使用」就刪除。

自架服務執行幾個月後,映像檔版本、建置快取、日誌和業務資料可能一起增長。 一次 prune 只能處理其中一部分,盲目擴大清理範圍還可能刪掉資料庫。

本文以 Linux Docker Engine 和 Compose V2 為主要環境。 Docker CLI 查詢指令通常也能在 Windows PowerShell 中執行;標為 Bash 的主機指令應在實際執行 Docker 的 Linux 主機上執行。 文件核對日期為 2026 年 10 月 22 日;本文沒有在你的伺服器上執行清理或重建作業。

如果你從 使用 Docker 部署 Syncthing 或 Joplin Server 自架教學 延伸到這裡,先找到那些服務實際使用的資料目錄,再決定清理對象。

先確定哪顆磁碟已滿、連線到哪台主機

Docker CLI 可能連線到本機、遠端 SSH context,或 Docker Desktop 的 Linux 虛擬機器。 在錯誤的 context 下查看空間,得到的數字可能和目前伺服器完全無關。

1
2
3
4
5
docker context show
docker context ls
docker version
docker info
docker compose version

重點核對伺服器端資訊、目前的 context 和 Docker 資料目錄。 Linux 上的預設資料目錄經常是 /var/lib/docker,但 rootless、自訂設定和不同儲存後端可能使用其他路徑。 不要把這個預設路徑直接當成待刪除目錄。

在 Linux 主機檢查檔案系統容量和 inode:

1
2
df -h
df -i

即使磁碟仍有容量,大量小檔案耗盡 inode 也會觸發 no space left on device。 如果寫入目標是綁定掛載的其他磁碟,應檢查那個掛載點,而不是只看系統碟。

Docker Desktop 還有虛擬磁碟這一層。 容器內部釋放的空間、虛擬磁碟可用容量,以及主機磁碟映像檔的實際用量,可能不會同步改變。 因此,Windows 的 C 槽用量沒有立即減少,不能單獨證明 Docker 清理失敗。 本文不提供通用於所有 Desktop 後端的虛擬磁碟壓縮指令。

用用量明細區分五類資料

先執行唯讀查詢:

1
2
3
4
5
docker system df
docker system df -v
docker ps -a --size
docker image ls
docker volume ls

docker system df 顯示 Docker 資源用量,-v 展開映像檔、容器和本機資料卷的明細。 映像檔之間可能共用分層,不能把每個映像檔顯示的 SIZE 直接相加當成實際用量。

類型 常見內容 優先處理方式
映像檔 目前版本、舊版本、建置中間產物 保留可回復的版本,檢查後清理懸空映像檔
容器可寫層 未持久化的上傳檔案、暫存檔 確認資料能否捨棄或移出
建置快取 Dockerfile 各步驟可重複使用的結果 依時間清理,接受後續建置變慢
資料卷與綁定掛載 資料庫、設定、附件、模型 依應用程式管理,先備份再調整
容器日誌 標準輸出、標準錯誤 查明日誌驅動程式,設定輪替

RECLAIMABLE 表示符合資源回收條件的用量估計,不能據此判定業務是否仍需要這些資源。 例如舊映像檔可能是唯一可用的回復版本,未被參照的資料卷可能存著已下線但仍需保留的資料庫。

docker ps --size 中的可寫層大小,也不等於掛載資料和日誌的總大小。 如果這裡顯示很小,而主機磁碟用量仍快速增加,就要沿著後面這兩條線檢查。

清理前先釐清容器與資料的對應關係

假設待檢查容器名為 my-app,先替換成自己的實際名稱:

1
2
3
docker inspect my-app --format '{{json .Mounts}}'
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker inspect my-app --format '{{.LogPath}}'

在 Mounts 中重點查看:

  • Type:區分 volume 和 bind。
  • Name:Docker 管理的資料卷名稱。
  • Source:主機來源路徑。
  • Destination:容器內的掛載位置。
  • RW:容器能否寫入。

例如,容器內 /data 對應主機 /srv/my-app/data,就需要從主機和應用程式層面排查該目錄的增長。 刪除舊映像檔不會縮小這裡的附件庫。

如果資料庫資料仍寫在容器可寫層,先安排備份和持久化遷移。 此時刪除容器可能直接遺失資料,不適合繼續下面的容器清理步驟。

Compose 專案也應在正確的專案目錄執行:

1
2
3
docker compose config --quiet
docker compose ps -a
docker compose images

有自訂 -f、-p 或環境檔時,查詢與後續作業要使用同一組參數。 變更專案名稱可能建立另一組資料卷,讓應用程式看起來像「資料清空了」。

記錄實際資料卷名稱、Compose 檔案和映像檔版本,備份檔放到有足夠空間的獨立位置。 資料庫應使用自身支援的邏輯備份或一致性快照;執行中直接封存資料庫目錄,可能得到無法還原的備份。

映像檔和建置快取:從可以重建的內容開始

先評估建置快取

如果空間主要來自 Build Cache,清理快取通常比動到業務資料卷更合適。 代價是下次建置可能重新下載相依套件、編譯並花費更多時間。

1
docker builder prune --filter 'until=168h'

這會依時間條件清理符合條件的建置快取,並保留互動確認。 168h 是七天,屬於保留期間範例,應依建置頻率調整。 它不是「預覽」,確認後會實際刪除快取。 具體參數見 docker builder prune。

使用 Buildx 的多 builder 環境時,也要檢查目前的 builder:

1
2
docker buildx ls
docker buildx du

docker buildx du 查詢目前選取 builder 的快取用量。 不要在一個 builder 上看到快取很大,卻在另一個 builder 上反覆清理。 多台遠端建置主機也需要分別核對,不能假定它們共用本機磁碟。

再判斷懸空映像檔能否刪除

列出懸空映像檔:

1
docker image ls --filter dangling=true

確認不再需要這些建置產物後,可以執行:

1
docker image prune

預設會清理懸空映像檔。 加上 -a 後,範圍擴大到沒有容器參照的映像檔,包括帶有正常標籤的舊版本。 這會影響離線復原和版本回復,不能當成預設的加速參數。 完整規則見 docker image prune。

如果只想刪除一個已確認廢棄的映像檔,指定實際映像檔 ID 更容易控制範圍:

1
docker image rm IMAGE_ID

遇到參照衝突時,先檢查參照它的容器,重新判斷是否仍需保留。 不要立即加上強制參數略過提示。

依名稱逐一處理廢棄容器

停止狀態不代表容器裡的檔案沒有價值。 先查看容器掛載與可寫層,再決定是否刪除:

1
2
3
docker ps -a --filter status=exited --size
docker inspect old-test-container --format '{{json .Mounts}}'
docker diff old-test-container

docker diff 可查看容器檔案系統變更,不是備份,也不能取代掛載目錄檢查。 確認這是可以捨棄的測試容器後,才刪除指定對象:

1
docker container rm old-test-container

此處沒有使用 -f 或 -v。 刪除容器仍會捨棄其可寫層和容器日誌;重要檔案必須提前匯出。 刪除規則可查 docker container rm。

日誌持續增長:清快取之後還要處理根因

如果 docker system df 中可回收空間很少,繼續查看日誌驅動程式和路徑。 Docker 預設的 json-file 日誌驅動程式沒有預設大小限制,高頻錯誤輸出可能持續占用磁碟。

1
2
3
4
docker info --format '{{.LoggingDriver}}'
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker inspect my-app --format '{{.LogPath}}'
docker logs --tail 100 my-app

預設驅動程式和某個容器的實際驅動程式可能不同,以容器的 LogConfig 為準。 LogPath 也不一定總是提供可直接查看的檔案路徑,取決於日誌驅動程式和執行環境。 設定行為見 Docker 日誌驅動程式文件。

在 Linux 上,可以對實際傳回的路徑執行唯讀大小查詢。 例如把下列路徑替換為剛查到的日誌檔:

1
sudo du -h /actual/path/to/container-json.log

不要直接刪除或截斷 Docker 管理的日誌檔。 官方說明這些檔案由 Docker daemon 獨占管理,外部修改可能干擾日誌系統。 如果日誌不斷重複資料庫連線失敗或權限錯誤,先解決應用程式問題,單純輪替仍會產生大量無用日誌。

為 Compose 服務設定日誌輪替

把下列 logging 設定合併到現有服務中,保留原本的映像檔、連接埠、環境變數和資料掛載:

1
2
3
4
5
6
7
services:
  app:
    logging:
      driver: json-file
      options:
        max-size: "10m"
        max-file: "3"

這只是設定片段,不是能獨立啟動的完整 Compose 檔案。 app 要替換成實際服務名稱。 max-size 控制單一日誌檔的輪替門檻,max-file 控制保留檔案數量;具體規則見 json-file 文件。

修改後先檢查語法;在業務允許短暫中斷、資料已持久化並備份的前提下,重建目標服務:

1
2
3
docker compose config --quiet
docker compose up -d --no-deps --force-recreate app
docker compose ps

重建會替換容器,其可寫層內容不會自動保留。 如果服務依賴匿名資料卷,應先確認後續如何重複使用或遷移,再執行重建。 接著找到新容器的實際名稱並檢查:

1
2
docker inspect my-app --format '{{json .HostConfig.LogConfig}}'
docker logs --tail 100 my-app

只修改設定後執行 docker compose restart,不會更新容器建立時決定的日誌選項。 如果檢查仍顯示舊設定,核對服務名稱、Compose 檔案、專案名稱和實際容器 ID。

輪替會限制本機歷史日誌,需要長期稽核的業務應另外收集與保留。 應用程式自行寫入掛載目錄的日誌,也需要應用程式設定或適合的輪替機制;Docker 的標準輸出輪替不會管理那些檔案。

資料卷:未使用和可刪除是兩回事

列出沒有容器參照的資料卷,可以協助找到待核查對象:

1
2
3
docker volume ls --filter dangling=true
docker volume inspect my-project-data
docker ps -a --filter volume=my-project-data

資料卷沒有關聯容器,可能只是因為執行過 docker compose down。 容器刪除後,資料卷裡的資料庫檔案仍可能是下次啟動所需的全部業務資料。 持久化機制見 Docker Volumes 文件。

實際處理前,應能回答四個問題:

  1. 這個資料卷屬於哪個應用程式和哪個環境?
  2. 應用程式是否已永久下線,還是準備稍後重建?
  3. 是否有獨立備份,而且驗證過還原方法?
  4. 備份存放位置是否會被這次清理一併刪除?

只有確認不再需要的指定資料卷,才考慮使用 docker volume rm 实际卷名 刪除,並將最後的占位文字替換成實際資料卷名稱。 本文不把批次清理資料卷當成日常維護步驟。 若資料卷增長來自資料庫紀錄、附件或模型,應先使用應用程式支援的保留策略、封存或遷移流程。

prune 與 compose down 的界線

不同指令的刪除範圍不能混用:

指令或選項 需要理解的範圍
docker image prune 預設針對懸空映像檔
docker image prune -a 擴展到所有沒有容器參照的映像檔
docker system prune 涉及已停止容器、未使用網路、懸空映像檔和未使用建置快取
docker system prune --volumes 額外涉及未使用匿名資料卷,不能視為備份清理
docker volume prune 目前預設清理未使用匿名本機資料卷;--all 擴大到未使用命名資料卷
docker compose down 預設移除專案容器和網路,不主動刪除資料卷
docker compose down -v 額外刪除宣告的命名資料卷和附屬匿名資料卷;external 資料卷除外

參數行為以安裝版本的 --help 和目前官方文件為準。 參見 system prune、volume prune 和 compose down。

批次清理不是可以直接復原的操作。 快取可以重新產生,映像檔可能重新拉取,已刪除的資料卷則需要有效備份才能還原。 此外,Compose 預設不刪除匿名資料卷,不代表下次 up 一定會自動掛回原本的匿名資料卷。 長期業務應使用明確的資料路徑或命名資料卷,並保存對應設定。

清理後用空間變化與業務讀寫共同驗收

每處理一類資源就重新查看一次,方便確認究竟釋放了哪裡的空間:

1
2
3
4
docker system df -v
docker ps -a --size
docker compose ps
docker compose logs --tail 100

Linux 主機再檢查:

1
2
df -h
df -i

不能只憑容器顯示 Up 就宣布恢復。 至少開啟一次服務、讀取一筆既有紀錄、寫入一筆可刪除的測試紀錄,再確認資料庫或同步目錄確實使用原本的資料。 涉及日誌重建的服務,也要觀察一段時間的磁碟增長,確認輪替設定和應用程式錯誤都已處理。

如果釋放量明顯少於預期,依現象繼續定位:

現象 下一步檢查
映像檔清單很大,實際只釋放少量空間 共用映像層、仍被容器參照的分層
Build Cache 沒變化 目前 context 和 builder 是否一致
Docker 資源很小,磁碟仍滿 綁定掛載目錄、日誌、其他主機檔案
Linux 仍回報空間不足 實際目標檔案系統、inode、配額和儲存後端
Desktop 內可用空間增加,主機用量不變 對應平台的虛擬磁碟回收機制
容器重建後出現初始化頁面 專案名稱、資料卷名稱、綁定路徑或匿名資料卷關聯發生變化

最後一種情況應立即停止繼續寫入,核對舊資料卷是否仍在、設定是否指向新目錄。 不要接著清理資料卷,否則可能真正刪除仍可找回的舊資料。

若清理後服務異常,先還原 Compose 設定,檢查持久化掛載,再使用保留的映像檔版本重建。 如果資料卷已刪除,重新拉取映像檔不會恢復業務資料,需要依事先驗證過的備份流程還原。

後續維護如何安排

維護紀錄至少包括 Docker context、資源用量、實際資料目錄、日誌驅動程式和備份位置。 建置頻繁的開發機可以定期評估快取;長期執行資料庫的伺服器,應優先處理容量告警、資料庫備份和還原演練。

不要把帶強制參數、映像檔全面清理和資料卷清理的指令直接放進排程工作。 先執行一段時間的唯讀統計,確認哪些資源穩定增長,再選擇對應的保留策略。

需要將資料遷移到另一顆磁碟時,可參考 rsync 增量同步與驗證。 對資料庫目錄,仍需先停止相關寫入或使用應用程式支援的一致性備份;檔案複製成功不等於資料庫備份可還原。