動かない時

WSL2 で bind mount が激遅

WSL2 で `/mnt/c` 配下のソースをコンテナに bind mount すると、ビルドやテストが桁違いに遅くなる現象の原因と正しい置き場所。

WSL2 で bind mount が激遅 diagram

症状

  • Windows の C:\Users\you\project を WSL2 の Docker から /mnt/c/Users/you/project として bind mount している
  • npm install / pnpm install がローカル(ネイティブ Linux や Mac)の 5〜20 倍遅い
  • ファイル監視(chokidarvite dev)が変更を検知しない、または数秒〜数十秒遅れる
  • node_modules 配下のファイル列挙だけで数分かかる

原因

WSL2 は Windows ファイルシステム(NTFS)と Linux ファイルシステム(ext4)を別々の仮想マシンで管理し、/mnt/c 経由のアクセスは 9P プロトコル越しのリモートファイルシステム になります。

ファイル 1 つ読み書きするごとに Windows 側との IPC が発生するため、node_modules のように小さなファイルが大量にあるディレクトリでは致命的に遅くなります。

一方、WSL2 の Linux ホームディレクトリ(~/ すなわち \\wsl$\Ubuntu\home\you\ 相当)は ext4 上にあり、Docker Desktop の WSL2 バックエンドも同じ仮想マシン内で動くため、bind mount は純粋なローカルファイルシステムアクセスとして高速に動きます。

確認コマンド

実際にどれくらい差があるかを数値で見ると納得できます。

以下を両方のパスで実行して比較します。

bash
# ファイル操作の速度比較(ダミーファイル 5000 個生成)
time (cd /mnt/c/tmp && mkdir -p bench && cd bench && for i in $(seq 1 5000); do touch $i; done)
time (cd ~/tmp && mkdir -p bench && cd bench && for i in $(seq 1 5000); do touch $i; done)

# 実プロジェクトで npm install を比較
cd /mnt/c/Users/you/project && time npm ci
cd ~/project && time npm ci

# コンテナからのマウント経由でも確認
docker run --rm -v /mnt/c/Users/you/project:/app -w /app node:20 time ls -R > /dev/null
docker run --rm -v ~/project:/app -w /app node:20 time ls -R > /dev/null

解決策

  • ソースコードは WSL2 の Linux ホーム(~/ 以下)に置く: これが最優先。git clone は WSL 内のターミナルから ~/projects/... に対して行う
  • VS Code は Remote - WSL 拡張で Linux 側を開く: code ~/projects/my-app で開けば VS Code もファイルシステムを理解して動作する。C:\ から開くとパス変換のため遅い
  • どうしても Windows 側に置きたい場合の緩和策:
    • node_modules はコンテナ内のボリューム(名前付きボリュームで /app/node_modules を分離)に逃がす
    • ファイル監視は CHOKIDAR_USEPOLLING=true でポーリングに切り替える(CPU は食うが動く)
    • ただしこれらは 対症療法。根本解決は Linux 側への移動
  • Docker Desktop の「Use the WSL 2 based engine」を ON にする: Hyper-V バックエンドより WSL2 バックエンドのほうが ext4 ネイティブでマウントできる
  • docker-compose.yml の volumes: は相対パスで書く: WSL 内から起動すれば自動で WSL ホーム基準の高速パスが使われる