Cover image

WSLのDockerがCドライブを圧迫する問題の直し方

はじめに

Cドライブの空きが1.2GBまで減った原因と、68GB回収するまでの手順。

BeforeAfter
docker_data.vhdx97.35 GB40.4 GB
Cドライブ空き1.2 GB68.5 GB

何が起きるのか

WSL上でDockerを使って開発していると、いつの間にかCドライブの空きが消える。実際にDockerが使っているデータは数GBなのに、ディスク上では数十〜100GB近く使用している、という状況になる。

犯人は docker_data.vhdx というファイル。DockerのWSLディストリビューションが使う仮想ディスクイメージで、これが 膨張したまま縮まない

C:\\Users\\<ユーザー名>\\AppData\\Local\\Docker\\wsl\\disk\\docker_data.vhdx

なぜ肥大化するのか

原因は2つ。

① Docker のゴミが溜まる

  • ビルドキャッシュdocker compose build するたびに古いレイヤーが残る
  • 未使用イメージ — タグが外れた古いイメージがそのまま
  • 停止済みコンテナ — 明示的に rm しないと残る
  • 未使用ボリュームdocker compose down だけではボリュームは消えない

② VHDXは自動で縮まない

VHDXファイルは「データが増えたら拡張する」が、「データを消しても縮小しない」。つまりDocker内でファイルを消しても、Windows上のVHDXファイルサイズはそのまま。手動で圧縮する必要がある。


現状を確認する

WSL内のディスク使用量

df -h /

Dockerのディスク使用量

docker system df
PS C:\Windows\System32> docker system df
TYPE            TOTAL     ACTIVE    SIZE      RECLAIMABLE
Images          8         8         19.21GB   0B (0%)
Containers      8         6         30.02MB   15.75MB (52%)
Local Volumes   111       8         35.76GB   34.09GB (95%)
Build Cache     81        0         15.06GB   12.41GB

こんな感じで出力される。

使用していない Local VolumesBuild Cache が多くある。これを消せばよい。

VHDXファイルのサイズ(PowerShell)

# Docker の VHDX
Get-ChildItem "$env:LOCALAPPDATA\\Docker\\wsl\\disk\\docker_data.vhdx" |
  Select-Object @{N='GB';E={[math]::Round($_.Length/1GB,2)}}

# Cドライブの空き
Get-PSDrive C |
  Select-Object @{N='FreeGB';E={[math]::Round($_.Free/1GB,1)}}
# Docker の VHDX
PS C:\Windows\System32> Get-ChildItem "$env:LOCALAPPDATA\\Docker\\wsl\\disk\\docker_data.vhdx" |
>>   Select-Object @{N='GB';E={[math]::Round($_.Length/1GB,2)}}

   GB
   --
71.98


PS C:\Windows\System32>
PS C:\Windows\System32> # Cドライブの空き
PS C:\Windows\System32> Get-PSDrive C |
>>   Select-Object @{N='FreeGB';E={[math]::Round($_.Free/1GB,1)}}

FreeGB
------
   0.1

対処手順

Step 1: Docker内の不要データを削除

WSL 内で実行する。

# イメージとビルドキャッシュを削除(ボリュームは残す)
docker image prune -a -f
docker builder prune -a -f
注意: docker system prune -a --volumes を使うとボリュームも消える。DBデータなどが入っている場合はイメージとキャッシュだけに絞ること。
ボリュームを消す場合は、以下で行う。

孤立してて、 0ca61e43693... のようなハッシュ値のものだけ消す。

# 孤立してる(=消える予定の)ボリューム一覧
docker volume ls -f dangling=true
# _ も - も含まないやつ(=純粋なハッシュ名)だけ消す
docker volume ls -f dangling=true -q | grep -vE "[_-]" | xargs docker volume rm

Step 2: Docker Desktop を停止

タスクトレイのDockerアイコンから Quit Docker Desktop する。バックグラウンドでWSLを再起動してしまうため、先に止める。

Step 3: WSLをシャットダウン

PowerShell で実行する。

wsl --shutdown

# 完全に止まったか確認(何も表示されなければOK)
wsl --list --running

まだ動いていたら:

# Docker のプロセスを強制終了
Get-Process *docker* | Stop-Process -Force

# 再度シャットダウン
wsl --shutdown

Step 4: VHDXを圧縮

管理者権限の PowerShell で実行する。

diskpart

diskpart が開いたら 1行ずつ 実行:

select vdisk file="C:\Users\<ユーザー名>\AppData\Local\Docker\wsl\disk\docker_data.vhdx"
compact vdisk
detach vdisk
exit

compact vdisk は数分かかることがある。100%になるまで待つ。

detach vdisk で「既にデタッチされています」と出ても問題ない。

結果

BeforeAfter回収
VHDX サイズ97 GB40 GB57 GB
Cドライブ空き1.2 GB68.5 GB67 GB

今後の予防

定期的にゴミ掃除する

# ビルド後にこまめに
docker image prune -f

# 週1くらいで全掃除(ボリューム以外)
docker image prune -a -f
docker builder prune -a -f

docker compose down の使い分け

コマンドボリューム用途
docker compose down残る普段使い
docker compose down -v消えるまっさらにしたい時だけ

.dockerignore を確認

node_modules.git などが含まれていないと、ビルドコンテキストが無駄に大きくなり、キャッシュも肥大化する。

node_modules
.git
.svelte-kit
dist
.env*

  • 環境: Windows 11 / WSL2 (Ubuntu) / Docker Desktop / SvelteKit 開発中に遭遇