WSL2 + Ubuntu:18.04 + DockerCompose でCLI開発環境構築の備忘録

タイトル通り。

* WSL2導入、設定。
* Windows Terminal導入、設定。
* Docker、DockerCompose導入。windows->WSL2へのポートフォワーディング設定
* （その他）Dockerのユーザ定義ネットワークの謎の名前解決不具合対処。

# WSL2導入
やった事が[こちら](https://qiita.com/tomtwinkle/items/92c8c399f9aad62c45b6)の記事にほぼ載ってたので割愛。

完全新規に導入する場合は、WSL2の設定後に、`CMD`か`PowerShell`から、`wsl --set-default-version 2`を実行後に、[Microsoft Store](https://www.microsoft.com/ja-jp/p/ubuntu-1804-lts/9n9tngvndl3q?activetab=pivot:overviewtab)からインストールする。

## WSL2設定

### メモリ上限設定、localhostでの通信許可設定
デフォルトだと、WSL2が無限にメモリを食い尽くそうとしてきた。
あと、WindowsからWSL2環境にアクセスするときに`localhost`を使いたい。
`C:\Users\<yourUserName>\.wslconfig`をつくって、[設定](https://www.microsoft.com/ja-jp/p/ubuntu-1804-lts/9n9tngvndl3q?activetab=pivot:overviewtab)をする。

`memory=2GB`と`localhostForwarding=true`だけ作って、あとは未検証。

### 日本語化 
WSL2関係ない普通のubuntuの日本語化だけど、一応。
Linuxの日本語化の仕組みを良く分かってないから、[言われた通り](https://www.atmarkit.co.jp/ait/articles/1806/28/news043.html)にしただけ。

## Ubuntu用ファイルへのショートカットを作成

`\\wsl$\[ディストリビューション名]`で、ディストリビューションのディレクトリを見る事が出来る。デスクトップにショートカットを作っておくと、何かと便利。

## Windows Terminal導入
[ここ](https://www.microsoft.com/ja-jp/p/windows-terminal-preview/9n0dx20hk701?activetab=pivot:overviewtab)
Microsoft謹製の、Linuxのターミナルっぽい奴。タブも分割表示もできるし、`CMD`も`PowerShell`も一緒に扱えるんで、便利。
フォントも指定できるんで、[Source Han Code JP](https://github.com/adobe-fonts/source-han-code-jp)を入れてみた。OSにインストールしてから、`Windows Terminal`の設定を選択するとひらく`settings.json`の`profiles: defaults:`に`"fontFace" : "Souce Han Code JP"を指定。

## Docker、DockerCompose導入
Dockerを、[公式に言われるがままに](https://docs.docker.com/engine/install/ubuntu/#install-using-the-convenience-script)インストール。
DockerComposeを、[公式に言われるがままに](https://docs.docker.com/compose/install/#install-compose-on-linux-systems)インストール。

#### Dockerデーモンについての 注意点
WSL2では、`systemd`が使えない（原理的にpid 1 が占有されるから使えない、とかなんとからしい）から、Dockerデーモンは自分で起動させる必要がある。
立ち上げるたびに`sudo service docker start`してるけど、大変面倒臭いんで、その内自動化したい。


### Windows -> WSL2のポートフォワーディング設定
今の状態でも、WindowsからWSL2へのアクセスは、`localhost`を使えば出来る様になっているのだけれど、直接`127.0.0.1`を使いたい事もある。
なので、Windowsへの特定のポートへのリクエストを、WSLにポートフォワードさせる設定をする。

##### 問題になった事例（飛ばしてよい）
`AndroidStudio`で立ち上げたエミュレーターから、WSL2の`DockerComopse`で立ち上げたサーバに通信したい時に問題が発生。
`AndroidStudio`のエミュレーターから、ホスト機（Windows）への通信は、`10.0.2.2`を使って実現出来るのだけれど、、この通信はホスト機側では`127.0.0.1`として解釈されるっぽい。
WindowsからWSL2にアクセス出来るのが`localhost`だけのままだと、当然エミュレータ(10.0.2.2）⇒Windows（127.0.0.1、not localhost）だから、Dockerで立ち上げたサーバまでは届かない。
なので、`127.0.0.1`が来た場合でもWSL2側にポートフォワードさせる必要があった。

##### 設定
[こちら](https://qiita.com/yabeenico/items/15532c703974dc40a7f5)を参照させてもらって、スクリプトを作成。

* `listenport`を開発中サービスの待ち受けポートに変更。
* ついでに`ifconfig`を`ip a`に合わせて変更
* 開発用の設定は開発用のgitの中に閉じ込めたいので、windowsでのタスクスケジューラの設定は無しにして、`docker-compose up`前に手でスクリプトを叩く運用にする。

```set_port_forwardings_for_wsl2.sh
#!/bin/bash -x
# !注意!：実行には管理者権限が必要なので、ターミナルを管理者権限で立ち上げる事。

# WSL2での起動時に、windows側から'127.0.0.1'でもアクセス可能にするための設定。

IP=$(ip -4 addr show dev eth0 | grep 'inet ' | awk '{print $2}' | cut -d'/' -f1)

netsh.exe interface portproxy delete v4tov4 listenport=3000
netsh.exe interface portproxy add    v4tov4 listenport=3000 connectaddress=$IP

netsh.exe interface portproxy show v4tov4
```

##### 注意点
WSL2のアドレスは再起動の度に変わるから、スクリプトをしょっちゅう叩かないといけない。大変面倒なんで自動化したい。

## （その他）Dockerの名前解決不具合の対処
WSL2とは関係ないかもしれないけど、コンテナからの名前解決時に変な挙動が発生して、githubとの連携が出来ない現象が発生した。
開発環境としては致命的なんで、是が非でも解決する必要がある。
結論としては、Dockerに追加DNSサーバとしてパブリックなもの（8.8.8.8とか）を設定して回避可能。

##### 現象
* ユーザ定義ネットワークを使ったコンテナ内からの、`github.com`の名前解決をする時にだけ、挙動がおかしい。`google.com`とかは大丈夫。
* `dig`では普通に名前解決が出来る。`curl`や`ping`や`git clone`では、出来たり出来なかったりする。（大抵は`Could not resolve host: github.com`で出来ない）
* `tcpdump`でパケットを確認すると、[ユーザ定義ネットワーク用の内部DNSサーバ](http://docs.docker.jp/engine/userguide/networking/configure-dns.html)までは、ちゃんとレコードが帰って来てるのに、内部DNSサーバでレコードだけが消滅している。DNSのレスポンス自体は返ってくる。
* 内部DNSのキャッシュ機能があるなら変な動きをしてそう。が、内部DNSなんで細かいところが見えず、これ以上は追えない。

WSL2というより、Dockerの内部DNSのバグなんじゃないかって気がする。
バージョンは`Docker version 19.03.9, build 9d988398e7`

以下の手順で再現出来る（かもしれない）

```
docker network create test
docker run --net="test" -it ubuntu:16.04 /bin/bash

apt update && apt install curl -y
curl github.com
```
最初は成功したりもするが、何度か繰り返したり時間をおいてから再実行したりすると、`curl: (6) Could not resolve host: github.com`が出る。

##### 解決
理由は全くわからないから追うのを諦め、必要な機能が達成出来ていれば良い事にした。
ユーザ定義ネットワークは、`DockerCompose`で立ち上げた各コンテナ同士が、サービス名で名前解決して連携するために使うから、必須。
ただ、怪しい動きをしてるユーザ定義ネットワークの内部DNSサーバーは、最低限サービス名での名前解決機能だけ提供してくれれば良いので、内部DNSサーバが名前解決（この場合はgithub.com）に失敗した時用に、別途ちゃんとしたDNSサーバを追加すれば良い。（今回は8.8.8.8）

Dockerなら、`docker run --net="test" --dns=8.8.8.8 -it ubuntu:16.04 /bin/bash`、DockerComposeならymlに`dns: 8.8.8.8`を追加する事で、問題を回避出来た。

## WSL2開発環境所感

これまでの環境が、`Vagrant -> virtualbox -> centos -> DockerCompose`だったんで、1段階減って、Windowsとの連携がしやすくなっただけでもとても便利。
Windows側のリソースもあんまり取らないし、体感速度も大分上がってる。

今のところVimでしか触ってないんだけど、`Docker for Desktop`とか`VSCode`を連携す有ればさらに快適になるのかもしれないという予感は抱かせてくれる。

`Windows Terminal`も良い感じだし、今のMicrosoftはほんと良いなぁ。