WSL2+VSCode Dev ContainerでFilesharingの警告


## 環境

```
OS: Windows 10 Pro バージョン 2004 (19041.572)
Visual Studio Code: 1.50.1
Docker Desktop: 2.5.0.0 (49427) stable
Docker: version 19.03.13, build 4484c46d9d
自分: DockerやWSLのことよくわかってないけどなんとなく使っている
```

<details><summary>WSL関連</summary><div>

```
$ wsl -l -v --all
  NAME                   STATE           VERSION
* docker-desktop-data    Running         2
  docker-desktop         Running         2
  Ubuntu                 Running         2
```
```
# WSL2上のUbuntu
$ cat /etc/os-release
NAME="Ubuntu"
VERSION="20.04 LTS (Focal Fossa)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 20.04 LTS"
VERSION_ID="20.04"
HOME_URL="https://www.ubuntu.com/"
SUPPORT_URL="https://help.ubuntu.com/"
BUG_REPORT_URL="https://bugs.launchpad.net/ubuntu/"
PRIVACY_POLICY_URL="https://www.ubuntu.com/legal/terms-and-policies/privacy-policy"
VERSION_CODENAME=focal
UBUNTU_CODENAME=focal
```

* Docker Desktop 設定でWSL2をバックエンドに使うよう設定
![docker1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/2d38b817-e01a-367b-fdce-6c9b0500e00e.png)
* Docker Desktop のWSL Integration設定をオン
![docker2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/6d363e85-72c2-ebdf-28fd-6a958d8ef2cc.png)
* WSL2が無限にメモリ使いまくる問題に対処
  * 参考：[WSL2によるホストのメモリ枯渇を防ぐための暫定対処 - Qiita](https://qiita.com/yoichiwo7/items/e3e13b6fe2f32c4c6120)

```.wslconfig
[wsl2]
memory=2GB # ←ホストマシンのメモリがしょぼいので……
swap=0
```

</div></details>


## 使用したコード

```
project
    └ .devcontainer
        ├ devcontainer.json
        └ docker-compose.yml
```

<details><summary>各ファイルの中身</summary><div>

```devcontainer.json
{
  "name": "wsl-devcontainer-example",
  "dockerComposeFile": "docker-compose.yml",
  "service": "web",
  "workspaceFolder": "/workspace"
}
```
```docker-compose.yml
version: '3'
services:
  web:
    image: node:14-alpine
    tty: true
    volumes:
      - ..:/workspace
```
</div></details>


## 問題

開発コンテナを開いたら、以下のような警告が出た。

![poor.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/09835927-76d4-f61d-dcb8-59c0df8b10e5.png)

> Docker Desktop - Filesharing
> Docker Desktop has detected that you shared a Windows file into a WSL 2 container, which may perform poorly. Click here for more details.

* 警告文のリンク先：[Docker Desktop WSL 2 backend | Docker Documentation](https://docs.docker.com/docker-for-windows/wsl/#best-practices)

<details><summary> （補足）そもそもdevcontainerって何</summary><div>

* VSCodeのメチャ便利機能
* 開発環境をDockerコンテナで作るのでホスト環境を汚さずにすむ
* 設定ファイルの用意さえすればVSCodeで開いてちょっとボタン押すだけで↑の環境ができてすごい楽
* 設定ファイルとDocker関連ファイルをリポジトリに入れておけば開発メンバーで環境を統一できてすごい
* [Developing inside a Container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/containers)
</div></details>


### なんの警告？

[上記リンク先](https://docs.docker.com/docker-for-windows/wsl/#best-practices)から一部引用：

> To get the best out of the file system performance when bind-mounting files, we recommend storing source code and other data that is bind-mounted into Linux containers (i.e., with `docker run -v <host-path>:<container-path>`) in the Linux file system, rather than the Windows file system. You can also refer to the [recommendation](https://docs.microsoft.com/en-us/windows/wsl/compare-versions) from Microsoft.

> ファイルをバインドマウントするときファイルシステムのパフォーマンスを最大限に活用するためには、ソースコードやその他、Linuxコンテナに（例えば`docker run -v <host-path>:<container-path>`を使って）バインドマウントされるデータを、WindowsファイルシステムではなくLinuxファイルシステムに保存することが推奨されます。マイクロソフトからの[推奨事項](https://docs.microsoft.com/ja-jp/windows/wsl/compare-versions)も参考にしてください。

WSL2では**Windowsファイルシステム上に保存したファイルにWSL上のコマンドからアクセスするのはかなり遅い**し一部機能が動かない、という警告のようだ。
確かに、`npm install`のようなファイルを大量に書き込む処理をすると、めちゃめちゃ遅いのが体感できる。

## 解決方法

Windowsファイルシステムではなく、WSL上で作ったLinuxファイルシステムのディレクトリを`devcontainer`（開発用コンテナ）にバインドマウントしてやればよいはずである。

### ダメな方法(1):sob:

ただ`docker-compose.yml`を以下のようにしてももちろんダメ。

```docker-compose.yml
version: '3'
services:
  web:
    image: node:14-alpine
    tty: true
    volumes:
      - \\wsl$\Ubuntu\home\username\workspace:/workspace # ✖✖✖
```

`docker-compose`が`\\wsl$\...`をパスとして認識できないようで、動かない。さらに、これだと相対パスが使えないので、プロジェクトメンバーで共有もできない。そもそも「Windowsがネットワークドライブとしてマウントしたフォルダ」を指定しても、意味がない気がする。なにもかもがダメ:sob::sob::sob:

### ダメな方法(2):sob:

以下もダメ。

```docker-compose.yml
version: '3'
services:
  web:
    image: node:14-alpine
    tty: true
    volumes:
      - /mnt/c/Users/username/workspace:/workspace # ✖✖✖
```

これもやはり相対パスが使えない。そして「WSLがマウントしたWindowsファイルシステム上のフォルダ」を指定しているので、意味がない気がする。（動くのかな？試してません……）

### 正しい方法:smile:

以下のドキュメントに、ステップバイステップのチュートリアルがある。

* [Windows Subsystem for Linux で Docker コンテナーの使用を開始する | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/tutorials/wsl-containers)

#### (1) WSLとdockerの環境を確認

前述のチュートリアルにもある通り、以下の環境が必要。

* Windows 10 バージョン2004 ビルド 18362以降 （エディションはHomeでOK）
* VSCodeに[Remote Development 拡張セット](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)を入れておく
* WSL2となんらかのディストリビューション（私はUbuntuにした）
  * 参考：[Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)
* Docker Desktopの設定で`Use the WSL 2 based engine`を有効化
* Docker Desktopの設定で`WSL Integration`を有効化
* （ついでに）WSL2が無限にメモリ使いまくる問題に対処しておいた方がいいかも？　参考：[WSL2によるホストのメモリ枯渇を防ぐための暫定対処 - Qiita](https://qiita.com/yoichiwo7/items/e3e13b6fe2f32c4c6120)

![docker1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/2d38b817-e01a-367b-fdce-6c9b0500e00e.png)
![docker2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/6d363e85-72c2-ebdf-28fd-6a958d8ef2cc.png)

設定ができていると、WSL上のUbuntu上にdockerをインストールしなくても、`docker`や`docker-compose`コマンドが使えるようになる。これが重要っぽい？（WSLからコンテナを起動するので）

```txt:WSL上のUbuntuで実行
$ docker --version
Docker version 19.03.13, build 4484c46d9d
$ which docker
/usr/bin/docker
$ ls -al /usr/bin/docker
lrwxrwxrwx 1 root root 48 Nov  5 10:47 /usr/bin/docker -> /mnt/wsl/docker-desktop/cli-tools/usr/bin/docker
```

#### (2) WSLからVSCodeを開く

**WSLのUbuntuのシェルから操作**する。

```txt:WSL上のUbuntuで実行
$ cd ~
$ git clone https://github.com/mattwojo/helloworld-django.git
$ cd helloworld-django
$ code .
```

VSCodeが開くと、プロジェクト内の`.devcontainer`フォルダを認識して「Dev Container設定があるけど、コンテナで開く？」というようなメッセージを出してくるのだが、**これは無視する**。:no_good:
どうも、このメッセージのボタンからコンテナを開くと、せっかくWSLからVSCodeを起動していても無視されて、Windowsから開発用コンテナを実行しようとしてしまうみたい……？

![warn.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/03840138-a4e3-8840-53e2-b8b4ed24d80e.png)
:no_good::no_good::no_good:

#### (3) VSCode(WSL)からコンテナを開く

1. コマンドパレットから`Remote-Containers: Open Folder in Container...`を選択
2. プロジェクトフォルダを選択（最初から選択されてたのでそのままOK）

この後、ドキュメントには

> プロジェクトフォルダー (リポジトリ) に DevContainer 構成がまだないため、コンテナー定義の一覧が表示されます。

とあったが、現行バージョンだとリポジトリ内に`.devcontainer`がすでに存在しているため、何も聞かれずイメージのビルドが始まる。（けっこう時間がかかった……）

VSCode上で統合ターミナルを開き、Pythonのバージョンを確認してみる。

```
$ python --version
Python 3.9.0
```

WSL(Ubuntu)にはpythonを入れていないので、コンテナのターミナルであることがわかる。
冒頭に示したFilesharingの警告も出ない！
（ちなみに、サンプルプログラムを実行するには`python3 -m pip install django`が必要だった。）

### 元のファイルで試す

1. 問題が出ていた`.devcontainer`を含んだプロジェクトフォルダを、`\\wsl$\Ubuntu\home\username`以下に移動（Windowsのエクスプローラーで開いてコピーしただけ）
2. WSLのUbuntuのシェルから`code .`
3. `Remote-Containers: Open Folder in Container...`
4. できた！

### 次回からは？

毎回これをやるのは面倒だな……と思ったが、一度開けば次からはVSCodeの「最近」のところに`[Dev Container]`と表示され、一発で開けるようになっていた。

![recent.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/171645/6cb3bdc5-78ad-dbc6-f83c-eb4738b6576a.png)


## まとめ

1. コードをWSLのLinuxファイルシステム上に配置する
2. VSCodeを**WSLから`code`コマンドで開く** ←これが重要
3. WSLで開いたVSCodeから`Remote-Containers: Open Folder in Container...`


## その他の参考サイト

* [Developing inside a Container using Visual Studio Code Remote Development](https://code.visualstudio.com/docs/remote/containers#_open-a-wsl-2-folder-in-a-container-on-windows)
* [Visual Studio Code Remote Development Troubleshooting Tips and Tricks](https://code.visualstudio.com/docs/remote/troubleshooting#_container-tips)