Chapter 02

WSL2の要注意ポイント

SHIBUKAWA Yoshiki
SHIBUKAWA Yoshiki
2020.10.15に更新

1. ファイルシステムをクロス環境で使う場合の問題

作業フォルダをWindowsのNTFS上に置くか、WSL2のジャーナルなしext4上に置くかがまず悩みどころです。しかし、WSL2のファイルアクセスはネイティブ同等ではない欠点があります。

WSLが弱いのは次のようなケースです

  • WSLの方のフォルダにGoの開発フォルダを作り、GoLandで編集する
  • Windowsの方のフォルダにNode.jsの開発フォルダを作り、WSLでそのフォルダを開いてnpm installする
  • Windowsの方のフォルダに開発フォルダを作り、Dockerからマウントして開発に利用する

macではDockerでmacのフォルダをマウントすると同期が遅いということで、口汚く罵られがちですが、それはmacのDockerが仮想PCで動作していてフォルダの全コピーが必要だからです。WSL2は9Pプロトコルというリモートファイルシステムを実現するプロトコルで、WSL2→Windows間も、Windows→WSL2も、お互いにリモートアクセスをしています。毎回FTPソフト経由でアクセスしているかのような感覚です。WSL2は互換性などの面で大きくWSL1からは改善されましたが、システムコールラッパーでNTFSを直接扱えるWSL1と比べると、ファイルシステムを跨いだアクセスにペナルティが生じるようになっています。

一括コピーは走ったりはせず、逐次コストを払うことになるはずですが、その中でDockerとかを実行するなど、一括コピーが必要な操作を行うと同じことです。

ファイルシステムをまたぐと遅い問題はWSLでいつも通りコマンド実行するときにも生じます。デフォルトでは、WSLはデフォルトでWindowsのPATH環境変数を引き継ぎます。これにより、かなりの量のPATHを検索しにいくことになります。

また、DockerでWindowsのフォルダをマウントすると、Docker for macと違い、UID/GIDがずれてパーミッションのエラーが出やすくなるという問題があります。起動時に環境変数でUID/GIDをdocker-composeに渡してマッピングしてあげる必要があるとのこと。

PATHを引き継ぐか、UIDやGIDなどはwslの設定ファイルで制御できます。これはWindowsのホームの.wslconfigファイルが該当します。iteropセクションのappendWindowsPathというオプションでPATHの引継ぎは制御できます。

2. どの環境で開発するか選択肢が多い

別に裏の仕組みはどちらでも良いが、コマンドプロンプトよりかはbashの方が慣れているので、そちらで作業したい、みたいなことはよくあると思います。僕もそうです。また、Windowsだと開発ツールがWindowsネイティブなコマンドプロンプト前提だったりするものもあったりして(C++とかだと特に)、まずどれを選ぶのか、という選択が強いられることになりますが、それに新しい選択肢が増えたのが今回のWSL2。

  • Windowsネイティブ(コマンドプロンプト or PowerShell)
  • Windowsの枯れたUNIXライク環境(Cygwin or MinGW or GitBash)
  • WSL2

WSL2は動作がLinuxで本番のデプロイ環境と合わせやすい、みたいな特徴はありますが、現代のプログラミング言語はたいていマルチプラットフォーム対応はしっかりしているため、そこに固執する必要もないと思っています。そもそも、それまでmac使ってた、という人も多いでしょうし100%同じでなくても大丈夫ということはご存知でしょう。また、MinGWとかを使っていても、一部ミドルウェアはLinuxネイティブやDockerで動かすことも可能ですし、それだけでも便利です。

特にファイルシステムの速度が本格的に問題になるようなケースであれば、CygwinとかMinGWで環境を作っちゃうのでもいいかな、と思っています。

CygwinとかMinGWが敬遠されがちだった理由としてはターミナルアプリの使い勝手に由来するものも多かった気がしますが、今となってはどれもWindows Terminal経由で使うと思いますし、ここはかなり改善されています。

3. アプリからみて、OS環境がカオス

GoLandがそのままでは動かない問題の原因が、環境の複雑さです。

  • LinuxアプリケーションがLinuxファイルシステムで動いている
  • WindowsアプリケーションがLinuxファイルシステムで動いている
  • LinuxアプリケーションがWindowsファイルシステムで動いている
  • WindowsアプリケーションがWindowsファイルシステムで動いている

Windowsでも、コマンドプロンプトやパワーシェルからはWSL2のフォルダは覗けません。

Linuxアプリとしてビルドされていても、実はWindows環境ということもありえますし、Windowsアプリとしてビルドされていて実行されていても、実はLinux環境ということがあります。

このあたりの環境差異を埋めるためのロジックとして、Go用のAlice in virtuallandというライブラリを作ってみました。WindowsからLinuxの環境変数を見たり、LinuxからWindows側の環境変数を見たり(含ホームディレクトリ取得)。

https://github.com/shibukawa/alice-in

とはいえ、Windowsアプリだからといってそれを起動するユーザーがどちらの環境を欲しているのかはおそらくゼロイチには決まらないかと思います。VSCodeも、初期値としては起動環境を参照しているような動作ではありますがあとから切り替えられるようになっています。ツールとしては、デフォルトは環境から推測するが、コマンドラインオプションでどっちのモードか切り替えられるように、という実装が必要になるでしょう。

あるいは、Linux版は愚直にWSL2、Windows版は愚直にWindowsの操作だけしかしない、お互いにクロスで何かタスクを行うことはない、という割り切りでもいいかもしれません。

4. WindowsのDockerとLinuxのDocker

Docker for Window DesktopはWSL2に対応しました。それにともない、Windows 10 ProじゃなくてもDocker for Windowsが使えるようになったのはとても助かるポイントです。

一方、それと同時に、LinuxネイティブDockerをWSL2内部にインストールという方法もできるようになりました。ふたつの環境は違いがあります。

  • Windows Desktop
    • アップデート通知とかしてくれるし、GUIの設定画面もあるし便利
    • ただし、GPUを使う場合はこちらでは対応できない
    • インストール情報はこちらが多い(WSL2まではこちらがメインだったので)
  • LinuxネイティブDocker
    • 良くも悪くもLinux版
    • GPUが使える

前者の方がインストール記事が豊富なので、いったんこちらで作業したけど、GPU使えないのでインストールし直し・・・・みたいなのは容易に想像しうる落とし穴なので、早急にWindows Desktop版にGPUサポートを入れるようにして欲しい気持ちがあります。

5. hostsやresolve.confが上書きされる

WSLとWindowsはデフォルトで協調動作しようとします。Windows側のネットワーク設定を元にhostsやresolve.confが起動時に生成(上書き)されます。WSLにだけ設定を追加することはできないと思います。

https://docs.microsoft.com/en-us/windows/wsl/wsl-config#set-wsl-launch-settings

6. バグ

WSL2には不具合があります。その中で大きいものはメモリの管理です。WSL2は必要に応じてメモリをWindowsにリクエストし、不要になったら返す機能があります。しかし、Linuxはもともと、メモリがあればあるだけキャッシュメモリなどとして使おうとします。しかも、Windowsのから見えるメモリの5割もしくは8GBがWSL2に見えるので、結果的に、多くのメモリを確保しに走ります。その結果、Windowsから使えるメモリを使い込む可能性があります。WSLの再起動で解消します。

まとめ

普通のLinuxとして使おうとするとハマりそうなポイントを紹介しました。まとめると、ストレージとメモリに注意が必要です。メモリはバグなので、そのうち解消されるかもしれませんが、ストレージに関しては仕組み上、今のアーキテクチャでは避けようがない問題です。

WSL2で開発環境を作るときは、ストレージをWSL2上にきちんと作り、大量アクセスを伴うプログラムから利用する場合は、Linuxのプロセス(含むVSCodeのエージェント)でのみ触るようにしましょう。具体的には、コード補完のためのスキャンを行うエディタやIDE、Dockerのコンテキスト転送、git、Node.jsのWebpack等の開発サーバーのローカル監視などです。もし、Windowsのプログラム(JetBrains製のIDEなど)から触る必要があれば、WSL2ではなく、MinGWなどを使うことも検討してみましょう。