Hyper-V版DockerからWSL2版Dockerに乗り換えた時にやったことメモ（Previewビルドなし）

書いて半年以上下書き放置してあったけど使う機会があったので公開。

# 前振り
これまでHyper-V版DockerのためにWindows10 Proを使っていて、WSL2版も少し試したうえで、
機材入れ替えにあわせてWindows10 Home+WSL2版Dockerに乗り換えました。

ただ、Hyper-V版と同じ作業環境だと、WSL2版はファイルの読み書き由来の速度低下が著しく、
これまで40秒程度の処理だったものが、平気で3-4分かかります。（知ってた＆しんどい）

せっかく機材もスペックアップしたことなので、作業環境を快適にしたいと思って取り組んだメモをまとめました。
作業時間・費用はWindows10 Proアップグレードライセンス代(￥13,824)以内を目指します。

以下、主にWSL2の環境整備の話で、Dockerはほとんど出てきません。
## 環境
### マシン
- CPU: 11th Gen Intel(R) Core(TM) i7-11800H @ 2.30GHz
- Mem: 32GB
- SSD: 1TB

### Windows
- Windows10 Home 21H1 (ビルド19043.1110)

※Windows Insider Programで配布されているプレビュー版ではPowerShellからのWSL2操作がかなり良くなっているようだけど、今回は使わない方向でいきます。

ちなみに普段の開発はVS Codeを使っています。
### WSL2
- Ubuntu 20.04
- この辺(https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#manual-installation-steps )を見て、手動インストール。

※UbuntuはMicrosoft Storeからインストールした。

## やりたいこと
### Docker作業時のファイルI/O速度を上げたい
使ったことがある方はご存じの通り、何も考えずにWindowsからUbuntu配下に8GB(ファイル数35万弱)をコピーしようとすると、6時間程度かかる表示が出て白目になる。

この作業においては主にプロジェクトごとの.git、node_module、(php composerの)vendorで苦しみが増す一方なのです…。

遅いのはファイル読み書き時のファイルシステムの変換が原因。
参考： [WSL2 のDocker for Windowsで動作が重い時の原因と対処方法](https://qiita.com/BlueBaybridge/items/c1adcf1dab5da2b40b4f)

ファイル配置がそのままではどうしようもないので、以下の条件をクリアしていきます。

- Windowsのユーザーディレクトリにファイルを置かない。
- WSL2側から/mnt/経由でアクセスする外付けにも置かない。
- WSL2(Ubuntu)配下か、WSL2で直接マウントできる外付け（Ext4フォーマットの仮想HDDなど）を使う。

もしUbuntu配下に直接おいてしまえるならここで解散できるのですが、今回は外付けを検討します。

余談：ちなみに、PreviewビルドであればWSL2で直接マウントすることもできるそうで、未来は明るいですね。
参考：[ASCII.jpデジタルWSL2で外部ストレージをマウントできるようになった](https://ascii.jp/elem/000/004/026/4026714/)

### WindowsのExplororからも作業データの読み書きをしたい
WSL2インストール後に、ネットワークドライブとしてアクセスできるようになるので、
目視確認やAdobe系バイナリデータ読み書き程度だからまあそれでいいか、ということにしました。

参考：[WSL2のubuntuのディレクトリをWindowsのエクスプローラーで操作する](https://zenn.dev/o2z/articles/zenn-20210622_wsl_directory)

### Windowsのディスク管理ソフトの機能で作業データのバックアップを取りたい
WSL2のバックアップ方法はいくつかあって、
PowerShellで`wsl --export`するのが正しい様子。
参考：[標準機能だけでWSLを好きな場所にインストールする](https://qiita.com/yamada6667/items/9e73193b0167cba2351d)

また、WSL2で使っているディストリビューションのVHDX(仮想HDDファイル)を丸ごとコピーする方法もある。

```cmd:保管場所参考
C:\Users\(USERNAME)\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu20.04onWindows_79rhkp1fndgsc\LocalState\ext4.vhdx
```

試してみたけど、exportもだいぶ時間かかるし、どちらにしてもファイルサイズ的に大きすぎる(現状50GBある)
インストールしてから少し設定したくらいで使うため、ディストリビューションの全ては必要ない…。

私はParagon Softwareの製品が好きなので、[PARAGON Hard Disk Manager for Windows](https://www.paragon-software.com/jp/home/hard-disk-manager-for-windows/)にバックアップを任せたい。
つまり、データ用仮想HDDファイルを管理すればよくない？

### ディストリビューション変えたときの取り回し
別のディストリビューションに乗り換えたくなった時のことを考えると、
やっぱりデータ用だけ独立させたい。

## やることまとめ
というわけで、作業データ用にext4のVHDXを作り、
通常はWSL2からマウントし、Windowsからはネットワークドライブとしてアクセスする。
必要に応じてWindowsからext4を直接マウントする（できるのか？）

# やったこと
## データ用ディストリビューションの作成～再マウント方法まで
そのものずばりのことをなさっていた先人の知恵をありがたく拝借します。

[くんすとの備忘録：WSL2にデータ保持用のディストリビューションを作成し、データを永続化・共有する](https://blog.kunst1080.net/post/2020/06/07/wsl-data-container/)
気になるファイルアクセスのベンチマークも掲載されていて、大変ありがたい。

毎回/dev/sd*の探索するの面倒かもと思いつつもこの手順を進めていきます。

`wsl --import`したときにつけたディストリビューション名は`wsl-works-data`

## Windowsの再起動後のおまじない
データ用のはWindowsの再起動後に終了・切断されており、おまじないをする前にDockerが起きているとダメな感じです。
そのため、再マウントするために以下の手順となります。

### Docker for Windowsはログイン時自動起動させない。
これをしているとデータ用VHDXの中身が正常にバインドできなくなる。
### データVHDXの起動（即終了）とWSL2側からのマウント
```powershell:PowerShell
# 先にデータ用を起動する
wsl -d (データディストリビューション名)
# PowerShell内でWSL2のUbuntuを起動する、あるいはWindows TerminalでUbuntuを開く
wsl -d Ubuntu20.04
```

続いて、目的のデータが入ったマウント先を調べて任意のディレクトリ名で使えるようにするのですが、
マウント手順を簡略化するコマンドを作って、PATHを通した場所に配置することにしました。

※ちなみに、Windows側のシステム環境変数PATHが通った場所にコマンドを配置するとWSL2でも通るようになります。
[WSL コマンドと起動構成:構成オプション:interop](https://docs.microsoft.com/ja-jp/windows/wsl/wsl-config#configuration-options)にある通り、wsl.confのappendWindowsPathによってこの挙動は制限されるようです。

自分の環境の場合、(再)起動直後なら、/dev/sd*を眺めて、最後のもの指定すれば大体正解。
Windowsで外付けHDDやハブの付け外しをすると様子も変わるので、`ls -l`で眺めて確認するまでをコマンドにまとめます

いろいろ雑だけどこんな感じで…

```shell:dataMountコマンド
#!/usr/bin/bash

# マウントするディレクトリ名：先にmkdirで作っておく
MOUNT_DIR=~/dataMount

# すでにマウントされているかチェック
mountpoint -q $MOUNT_DIR
if [ $? = 0 ]; then
  echo "${MOUNT_DIR} mounted.";

  echo -n "Unmount? (y/n)": 
  read INPUT_BOOL
  if [ "$INPUT_BOOL" = "y" ]; then
    sudo umount $MOUNT_DIR
    echo -e "\033[32m${MOUNT_DIR} unmounted. \033[m"
  else
  	echo -e "Unmount canceled."
  fi
  exit 1;
fi

# マウント前調査
lsblk

echo -n "Mount Alphabet (Empty to exit)": 
read INPUT_ALPHA

if [ "$INPUT_ALPHA" = "" ]; then
  echo -e "Mount canceled."
  exit 0;
else
  sudo mount /dev/sd${INPUT_ALPHA} $MOUNT_DIR
  ls -l ~/dataMount
  echo -e "\033[32m${MOUNT_DIR} mounted! \033[m"
fi
```

```shell:マウントするとき
username@Machine2021:~$ dataMount
NAME MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda    8:0    0  256G  0 disk
sdb    8:16   0  256G  0 disk /
sdc    8:32   0  256G  0 disk
sdd    8:48   0  256G  0 disk
Mount Alphabet (Empty to exit):c
[sudo] password for username: [パスワード入力]
total 48
drwxr-xr-x 4 username username  4096 Jul 21 04:14 Works　<-- ここに作業用データが入ってる
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 bin
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 dev
-rwxr-xr-x 1 root    root        0 Jul 31 01:04 init
drwx------ 2 root    root    16384 Apr 11  2019 lost+found
drwxr-xr-x 6 root    root     4096 Jul 22 01:02 mnt
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 proc
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 run
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 sbin
drwxr-xr-x 2 root    root     4096 Jul 21 04:01 sys
/home/username/dataMount mounted!
```
なんか違うのが接続されたら、もう1回実行するとマウント解除できます。

```shell:アンマウントするとき
username@Machine2021:~$ dataMount
/home/username/dataMount mounted.
Unmount? (y/n):y
/home/username/dataMount unmounted.
```
Hyper-Vの頃は考えなくてよかったパーミッションに関するエラーが結構出るので、
適宜chmod/chownを使って書き換えます。
特にnode_moduleと(php composerの)vendorは一度ファイルを削除してinstall実行するほうが早かったです。

これで、`/home/username/dataMount/Works`に作業用データを配置できるようになりました。

# VS Codeからの利用方法(2022.3.8 追記)
VS CodeにはRemote WSL拡張をインストールしておきます。
https://docs.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-vscode

拡張を入れた上記サイトの手順通りVS Codeからプロジェクトを選択してもいいし、
[Windows terminal](https://www.microsoft.com/store/productId/9N0DX20HK701"") などでUbuntu内からプロジェクトのルートディレクトリに移動して、
```shell
username@Machine2021:~/project$ code .
```
とやっても、VS Codeが開きます。
肝心なのは、WSL2で動いているディストリビューション（今回はUbuntu20.04）からVS Codeを呼ぶこと。

逆に、Windows Explororから（ネットワークディレクトリ上の）プロジェクトディレクトリをVS Codeで開いた場合は、ファイルの読み書きのたびにファイル変換が挟まるので __速度は上がりません__ 。

## Dockerの起動(2022.3.8 追記)
Ubuntu内から、いつも通り`docker run`や`docker-compose up` します。
VS CodeのRemote WSL拡張が入っていれば、VS Codeのターミナルからでも実行できます。

# 使ってみた感想
docker-composeの起動や再ビルド、モジュールのインストールがめちゃくちゃ早くなりました…。
VS Codeでの操作感もほとんど変わっていませんが、ファイルパスの都合でエラー行のCtrl+リンクが使えないのだけ何とかしたい。
Windows側からの大量のファイル操作がつらい以外はHyper-Vの頃よりはるかに高速です。

バックアップ関連もいい感じですが、Windowsからは未フォーマットのvhdxファイルなので残念ながら私のスキルでは扱えない。
予備機で復旧実験をしなくては…。(空のtarを`wsl --import`してからext4.vhdxすり替えたらいけるんじゃないかと思っている。)

#### 2022年2月10日追記
同時にマウントするなら「空のtarを`wsl --import`してからext4.vhdxすり替え」でいけました。
とりあえずファイルが引き出せればいいときはこの方法でよさそうです。

その際には、`wsl --shutdown` はもちろん、Windowsのサービスから`LxssManager`を停止が必要です（vhdxファイルのアクセスがはねられるため）。

# 未来が明るい備考
[Insider PreviewのWSL2で仮想ディスクイメージ(VHD/VHDX)をマウントする](https://qiita.com/matarillo/items/da2318e5c1c16f3c06e1#wsl%E3%81%A7%E3%83%95%E3%82%A9%E3%83%BC%E3%83%9E%E3%83%83%E3%83%88%E3%81%99%E3%82%8B)
`wsl --mount`がきていた。

# その他参考
メモリ上限設定やユーザー指定起動など公式Doc
[WSL コマンドと起動構成](https://docs.microsoft.com/ja-jp/windows/wsl/wsl-config)
[WSL でマウントしたファイルシステムでもパーミッションを扱えるようにする](https://sig9.hatenablog.com/entry/2020/02/19/000000)