🤕
Docker Desktopのvhdxが肥大化して縮まない時の対処法
導入
Docker Desktop(WSL2バックエンド)のvhdxファイルは、コンテナ内のデータを削除しても自動では縮小しない。
本記事では、diskpart単体では効かない理由と、ゼロ埋め→compactの2段階で確実に縮小させる手順を解説する。
問題
Docker Desktop(WSL2バックエンド)の仮想ディスク docker_data.vhdx は、コンテナ内のデータが増えると自動で膨張するが、データを削除しても自動では縮小しない。
たとえば以下のような状況がこれにあたる:
- 大量のデータを投入後に削除・ロールバックしたが、vhdxが縮まない
- OPTIMIZE TABLE 等でDB内部の断片化を解消したのに、ファイルサイズが変わらない
- Dドライブの空き容量が想定より少なく、vhdxが原因と判明した
今回のケース:
- MySQL内部データ: 72GB
- vhdxファイル: 169.3GB(約97GBが無駄)
- 原因: 大量INSERT → 容量不足で強制終了 → ロールバック → OPTIMIZE TABLE実行後も未使用領域がvhdx内に残存
なぜ diskpart compact だけでは縮まないのか
diskpartの compact vdisk はゼロ埋めされたブロックしか解放できない。
WSL2内のext4ファイルシステムは、ファイル削除時にブロックをゼロクリアしないみたい。
結果、diskpartから見ると「まだ使用中」に見え、compactが空振りする。
解決手順
前提
- Windows 11
- Docker Desktop(WSL2バックエンド)
- vhdxの場所を把握していること(デフォルト:
%LOCALAPPDATA%\Docker\wsl\disk\docker_data.vhdx)
1. コンテナ内から未使用領域をゼロ埋め
docker compose exec <サービス名> bash -c "dd if=/dev/zero of=/tmp/zerofill bs=1M || true; rm -f /tmp/zerofill; sync"
未使用領域をゼロで埋めたファイルを作り、即削除する。
ディスクの空き容量分の書き込みが発生するため時間がかかる(数分〜数十分)。
fstrim について: ゼロ埋めより高速なため先に試す価値はあるが、WSL2環境では the discard operation is not supported となって使えないことが多い。使えなかった場合は上記の dd による力技が確実。
2. Docker・WSLを完全停止
docker compose down
wsl --shutdown
3. diskpart compactを実行
管理者PowerShellで:
diskpart
select vdisk file="<vhdxのフルパス>"
attach vdisk readonly
compact vdisk
detach vdisk
exit
4. 結果確認
Get-ChildItem "<vhdxのフルパス>" | Select-Object @{N='Size_GB';E={[math]::Round($_.Length/1GB,1)}}
今回の結果
| 項目 | Before | After |
|---|---|---|
| MySQL内部データ | 72GB | 72GB |
| vhdxファイル | 169.3GB | 76.2GB |
| 回収した容量 | — | 93.1GB |
まとめ
- vhdxは膨張するが自動で縮小しない
-
diskpart compact単体では効かない(ゼロ埋めされていないため) - ゼロ埋め → compact の2段階が必要
-
fstrimが使えない場合はdd if=/dev/zeroで力技のゼロ埋めが確実
Discussion