広告 ubuntu

WSL2のディスク容量を削減する方法|ext4.vhdxが100GB超えた時の対処法

Docker環境でゴリゴリ開発していたら、突然「ディスク容量不足」の警告が。調べてみると、WSL2のext4.vhdxが100GB超えてました...。

WSL内でdf -hしてみたら20GBくらいしか使ってないのに、なんでこんなに肥大化してるんだ?と思って調べた結果をまとめます。

TL;DR(結論だけ知りたい人向け)

  • WSL2は削除したファイルの領域を自動で解放しない
  • PowerShellのOptimize-VHDで圧縮できる(DiskPartより簡単)
  • 100GB→22GBまで削減できた(実使用20GB)
  • 月1回の定期メンテナンスで予防可能

まず現状確認:VHDXファイルどこにある?

WSL2のディスクイメージは以下のパスにあります:

C:\Users\<ユーザー名>\AppData\Local\Packages\
CanonicalGroupLimited.Ubuntu<バージョン>_xxxxx\LocalState\ext4.vhdx

PowerShellで一発確認する場合はこちらをpowershellで実行します。

# VHDXファイルのパスを取得
$wslPath = (Get-ChildItem "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" | Select-Object -First 1).FullName

# サイズを確認
Get-ChildItem $wslPath | Select-Object Name, @{Name="Size(GB)";Expression={[math]::Round($_.Length/1GB,2)}}

僕の場合、103.67GBありました。やばい。

WSL内の実使用量も確認:

df -h

結果は19.8GB。えっ、差分80GB以上...?

これが「削除したファイルの領域が解放されてない問題」だと判明。

解決方法:PowerShellで圧縮(これが一番楽だった)

最初Googleで調べたら「DiskPart使え」って記事ばかり出てきたんですが、試したらattach vdiskでエラー連発...。

色々調べた結果、PowerShellの方が圧倒的に簡単でした。

手順1:WSLを完全停止

# WSLをシャットダウン
wsl --shutdown

# 停止確認(全部Stoppedになってること)
wsl --list --verbose

重要: これやらないとデータ破損のリスクあり。必ず停止確認してください。

手順2:圧縮実行

powershell

# VHDXパス取得
$wslPath = (Get-ChildItem "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" | Select-Object -First 1).FullName

# 圧縮(Full Modeが効果高い)
Optimize-VHD -Path $wslPath -Mode Full

実行したら5分くらい待って...

手順3:結果確認

# 圧縮後のサイズ
Get-VHD -Path $wslPath | Select-Object @{Name="FileSize(GB)";Expression={[math]::Round($_.FileSize/1GB,2)}}

結果:103.67GB → 22.15GB

削減率78.6%! めっちゃ減った。

DiskPartで失敗した話(参考までに)

最初DiskPartで試したんですが、これが結構ハマりました。

やったこと

wsl --shutdown
diskpart
select vdisk file="C:\Users\...\ext4.vhdx"
attach vdisk readonly

エラー発生

DiskPart にエラーが発生しました: プロセスはファイルにアクセスできません。
別のプロセスが使用中です。

は?wsl --shutdownしたのに...

原因を調査

# WSLプロセスが残ってないか確認
Get-Process | Where-Object {$_.Name -like "*wsl*"}

やっぱりwslserviceが残ってた。強制終了してもダメ。

結局、WSL2はHyper-Vベースだからロックされやすいことが判明。
DiskPartはVHDXを直接操作するから、ロック回避できないっぽい。

結論:PowerShellのOptimize-VHDの方がWSL2に最適化されてる

定期メンテナンス用のスクリプト作った

毎回手動でやるの面倒なので、スクリプト化しました。

wsl-optimize.ps1:

Write-Host "WSL2ディスク最適化スタート..." -ForegroundColor Green

# WSL停止
wsl --shutdown
Start-Sleep -Seconds 3

# VHDXパス取得
$vhdxPath = (Get-ChildItem "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" | Select-Object -First 1).FullName

if ($vhdxPath) {
    # 圧縮前サイズ
    $beforeSize = [math]::Round((Get-Item $vhdxPath).Length/1GB, 2)
    Write-Host "圧縮前: ${beforeSize}GB"
    
    # 圧縮実行
    Optimize-VHD -Path $vhdxPath -Mode Full
    
    # 圧縮後サイズ
    $afterSize = [math]::Round((Get-Item $vhdxPath).Length/1GB, 2)
    $saved = $beforeSize - $afterSize
    Write-Host "圧縮後: ${afterSize}GB (${saved}GB削減)" -ForegroundColor Cyan
} else {
    Write-Host "VHDXファイルが見つかりません" -ForegroundColor Red
}

タスクスケジューラで週1自動実行:

  1. タスクスケジューラ起動
  2. 基本タスク作成
  3. トリガー:毎週日曜深夜
  4. 操作:powershell.exe -ExecutionPolicy Bypass -File "C:\path\to\wsl-optimize.ps1"

これで放置OK。

容量肥大化を予防する設定

WSL内の不要ファイル削除

定期的にこれ実行してます:

# Dockerのゴミ掃除(これが一番効く)
docker system prune -a

# APTキャッシュ削除
sudo apt clean
sudo apt autoclean
sudo apt autoremove

# ログファイル削除
sudo journalctl --vacuum-time=7d

.wslconfigで自動解放を有効化(実験的機能)

C:\Users\<ユーザー名>\.wslconfig を作成:

[wsl2]
[experimental]
autoMemoryReclaim=gradual
sparseVhd=true

sparseVhd=trueで削除時に領域解放されやすくなる...らしい(まだ実験段階)。

Dockerデータを別ドライブへ

Dドライブに余裕あるなら、移動するのもあり:

sudo systemctl stop docker
sudo mv /var/lib/docker /mnt/d/docker
sudo ln -s /mnt/d/docker /var/lib/docker
sudo systemctl start docker

まとめ:やってよかったこと・分かったこと

即効性あった対処

  1. PowerShellでの圧縮(DiskPartより簡単・確実)
  2. Docker定期クリーンアップdocker system prune -a
  3. 週1の自動メンテナンス(スクリプト化)

分かったこと

  • WSL2は削除ファイルの領域を自動解放しない仕様
  • DiskPartよりPowerShellのOptimize-VHDが安全
  • Docker使ってるとめちゃくちゃ肥大化する
  • 月1メンテすれば予防できる

トラブったときのチェックリスト

自分用メモ:

  • wsl --list --verboseで完全停止してるか確認
  • PowerShell管理者権限で実行してるか
  • それでもダメならPC再起動

よくある質問(自分が疑問に思ったこと)

Q: 圧縮でデータ消えない?

A: 消えない。削除済みファイルの「空き領域」を解放するだけ。

Q: どのくらいの頻度でやればいい?

A: 僕は月1。Dockerヘビーユーザーなら週1推奨。

Q: DiskPartとPowerShellどっち使う?

A: PowerShell一択。DiskPartはWSL2と相性悪い。

Q: 時間かかる?

A: 100GBで5〜10分くらい。寝る前にやってる。

同じ問題で困ってる人の参考になれば。何か質問あればコメントください!

-ubuntu
-