WindowsアップデートでLinuxカーネルもアップデートされる時代に

![00100trPORTRAIT_00100_BURST20200413122237302_COVER.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/b4f31615-d680-aaac-61f5-31eb04953a84.jpeg)

このたびラップトップを新調しました。6年ほど前に中古のノートにLinuxを入れてつかってましたが、新品のWindowsノートに乗り換えました。そこで以前から気になっていたWindows Subsystem Linuxを使って、Windows上にLinuxの開発環境を用意してみたところ、セットアップもすごく簡単かつ快適な開発環境になったので、詳細を少し調べてみました。その結果と実際の開発現場における利用シーンについて紹介します。

※現段階ではPreview版OSへのアップデートが必要。WSL2を利用するにはbuild 18917以上のOSバージョンが必要です。それにはthe Windows Insider Programというプログラムに登録した上で、OSをPreview版にアップデートする必要があります。

# ターミナルを開くとそこはもうLinuxでした

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/66a5fb65-5988-6cb4-6604-bf7f1c6f8e72.png)

近頃の私が個人的なLinux環境でやる事というのは以下が主でした。

* Docker使ってローカルなネットワークを構築し、各ノードで動くソフトウェアをgolangで開発
* Reactでフロントエンド開発
* Node.jsでミドルウェア開発

この環境はあいにくWindowsを開発環境として想定していないため、Linux環境をどうにかして確保してやる必要があります。そこで今回新しいノート環境上で利用したのが以下の機能です。

* Windows Subsystem Linux 2
* Windows Terminal
* Docker Desktop WSL 2 backend

## 必要なもの

* Windows 10
    * 私はWindows 10 Professionalを使ってますがWindows 10 Homeでも可能らしいです
    * プレビュー版へのアップデートが必要なので会社とかでは使えないケースもあるかと思います
        * 2020年上半期に正式リリース予定らしいです

## 必要な作業

1. OSをWindowsプレビュー版にアップデート
    * https://insider.windows.com/en-us/
* `Windows Subsystem Linux 2(WSL2)`のセットアップ
    * https://docs.microsoft.com/en-us/windows/wsl/wsl2-install
* WSL2のカーネルを最新版にアップデート
    * https://docs.microsoft.com/en-au/windows/wsl/wsl2-kernel
* Linuxディストリビューションをストアからダウンロード
    * https://www.microsoft.com/en-us/search/shop/apps?q=linux
* `Docker Desktop WSL 2 backend`のインストール
    * https://docs.docker.com/docker-for-windows/wsl-tech-preview/
* `Windows Terminal (Preview)`をストアからダウンロード
    * https://www.microsoft.com/en-us/p/windows-terminal-preview/9n0dx20hk701?activetab=pivot:overviewtab
* Windows上のVSCodeに`Visual Studio Code Remote - WSL`プラグインをセットアップ
    * VS code serverを介してWindows上のVS codeでLinux上のソースをコーディング、デバッグ可能

以下の手順に従えば、特に迷うことも、時間を要することもなくセットアップが完了しました（OSアップデートの待ち時間が少しある程度）。

* https://docs.microsoft.com/en-us/windows/wsl/wsl2-install

---

# ネイティブ環境のようにストレスなく使える

今までWindows上でLinuxを使う場合、VirtualBoxなどの仮想環境上にLinuxをインストールして利用していました。またWindows上でDockerを利用する場合には、同じようにBootstrap用のLinuxを仮想環境上にインストールし、その上でDocker Engineを動かしていたかと思います。WSL2でMicrosoft独自の`Lightweight Utility VM`の導入により、ネイティブ環境に近いLinuxおよびDockerのランタイム性能を実現しています。メモリ消費量も小さく抑えられ、Linux上の処理に応じてオンデマンドでメモリを獲得・解放するようです。

先代のWSL1は使ったことはないですが、飛躍的な性能改善と互換性向上が実現されたらしいです。互換性に関しては、Linuxのシステムコールをフルサポートしているとのことで、あらゆるLinux互換のバイナリがWSL2上でそのまま実行可能ということです。これを実現するために、WSL2ではLinuxカーネルそのものを内包しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/7e0634da-d473-1cf1-06cb-6a6e56a91ead.png)
[The Modern Windows Command-Line: Windows Subsystem for Linux 2 | BRK3322 - YouTube](https://youtu.be/UCAid-NQwWU)より

そのカーネルが前述の`Lightweight Utility VM`上で動いており、性能改善およびシステムコールフルサポートを実現しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/ea4cb974-aa89-8aa3-1dba-86aabca2a069.png)
[The Modern Windows Command-Line: Windows Subsystem for Linux 2 | BRK3322 - YouTube](https://youtu.be/UCAid-NQwWU)より

このカーネルですが、kernel.orgのstableブランチをベースに、MicrosoftがWSL2向けにパッチを当てたもので、MicrosoftによってOSSとして保守されています。このLinuxカーネルが必要に応じてWindows Updateにより更新されるわけです。不思議な響き

[microsoft/WSL2-Linux-Kernel: The source for the Linux kernel used in Windows Subsystem for Linux 2 (WSL2)](https://github.com/microsoft/WSL2-Linux-Kernel)

パッチサイズも修正分は1Kステップにも満たないボリュームです。

```
$ git clone https://github.com/microsoft/WSL2-Linux-Kernel.git
$ cd WSL2-Linux-Kernel
$ git diff --diff-filter=M --stat   v4.19.84
 Documentation/admin-guide/kernel-parameters.txt |  10 ++++++
 MAINTAINERS                                     |   4 +++
 arch/arm64/Kconfig                              |   4 +--
 arch/arm64/Makefile                             |   1 +
 arch/x86/include/asm/hyperv-tlfs.h              |  40 ++++++++++++++++++++++
 arch/x86/include/asm/mshyperv.h                 |   4 +++
 arch/x86/include/asm/pci_x86.h                  |   5 +++
 drivers/acpi/Kconfig                            |   1 -
 drivers/acpi/Makefile                           |   2 +-
 drivers/acpi/acpica/dsutils.c                   |   9 ++++-
 drivers/acpi/arm64/iort.c                       |  20 +++++++----
 drivers/acpi/internal.h                         |   5 +++
 drivers/acpi/nfit/core.c                        |   3 ++
 drivers/hv/Kconfig                              |   5 +--
 drivers/hv/channel_mgmt.c                       |  19 ++++++++--
 drivers/hv/hv.c                                 |   2 ++
 drivers/hv/hv_balloon.c                         | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 drivers/pci/Makefile                            |   2 +-
 drivers/tty/sysrq.c                             |   4 ++-
 include/acpi/acpi_drivers.h                     |   5 +++
 include/linux/acpi.h                            |   6 ++++
 include/linux/list.h                            |  17 +++++++++
 include/linux/mm.h                              |   3 --
 include/linux/mm_types.h                        |   3 ++
 include/linux/mmzone.h                          |  34 ++++++++++++++++++
 include/linux/page-flags.h                      |  11 ++++++
 include/linux/pci.h                             |  36 +++++++++++++++++++
 include/uapi/linux/ndctl.h                      |   2 +-
 init/Kconfig                                    |  26 ++++++++++++--
 kernel/ksysfs.c                                 |   2 +-
 lib/Kconfig                                     |   3 +-
 lib/Kconfig.debug                               |   7 ++--
 lib/raid6/algos.c                               |  61 +++++++++++++++++++++++++++++++++
 mm/Kconfig                                      |  11 ++++++
 mm/Makefile                                     |   8 ++++-
 mm/compaction.c                                 |   7 ++--
 mm/memory_hotplug.c                             |   5 +++
 mm/page_alloc.c                                 | 236 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------------------
 net/vmw_vsock/hyperv_transport.c                |  90 ++++++++++++++++++++++++++++++++++++------------
 39 files changed, 688 insertions(+), 129 deletions(-)
```
# Export/Import機能により開発環境のシェアもカンタン

wsl2にはexport, import機能が備わっています。WSL2上で動かしているディストリビューション環境のスナップショットをストア、リストアするようなものです。exportすると対象のディストリビューションがtarで固められて出力されます。例えば、チームで開発環境をそろえたい場合に、exportしたtarファイルを開発グループ内でシェアし、それぞれWSL2上で動かせば、同一の環境にそろえることが可能です。特筆すべきは、Dockerのexport機能によって出力されたファイルもWSL2にimport可能であるという点です。`ubuntu:18.04`のコンテナイメージをベースに必要なツール群をインストールするDockerfileを書いてGithubでバージョン管理＆シェアすれば、あっという間に同一環境が複数環境に渡ってシェアできます。vagrantを置き換えることもできますし、自分のお気に入り開発環境をすぐにスタートできます。

例えば、以下はUbuntu 18.04上にgolangの古めの環境をセットアップするカスタムディストリビューションの例です。

```dockerfile
FROM ubuntu:18.04

RUN apt-get update
RUN apt-get install -y curl
RUN apt-get install -y zsh

RUN curl -O https://dl.google.com/go/go1.9.linux-amd64.tar.gz
RUN tar -xvf go1.9.linux-amd64.tar.gz  && chown -R root:root ./go && mv go /usr/local

CMD ["zsh"]
```

上記Dockerfileを利用して環境を構築⇒tarへのexport⇒wsl2へのimportを以下の通り実施します。

```shell
# On wsl
$ pwd
/home/atsushi/dev/qiita_test
$ code Dockerfile
$ docker build -t my-distro .
$ docker run --name mydistro -it -d my-distro
6dff538229aa997474db550c180474245774e0ab7c39ac8cba44a7a640181c32
$ docker export --output ./my-distro.tar mydistro
$ ls -lh
total 500M
-rw-r--r-- 1 atsushi atsushi  254 Apr 13 15:49 Dockerfile
-rw------- 1 atsushi atsushi 500M Apr 13 15:55 my-distro.tar

# On power shell
PS >  wsl --import my-distro ./my-distro-ws \\wsl$\Ubuntu-18.04\home\atsushi\dev\qiita_test\my-distro.tar
PS > wsl --list --verbose
  NAME                   STATE           VERSION
* Ubuntu-18.04           Running         2
  my-distro              Running         2
  docker-desktop-data    Running         2
  docker-desktop         Running         2
```

Windows Terminalをリスタートすると自動で新たに作成したディストリビューションがリストに読み込まれました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/355da3ad-5a12-3172-05e4-15bb038020e8.png)

新たに作成したディストリビューションをWindows Terminalのリスト上から起動すると意図したUbuntuバージョン上で指定したgolang環境がインストールされていることが分かります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/0c614caa-abc2-5b24-c3bd-fdbeeb007020.png)

このように自分のお気に入りな開発環境をDockerfileでバージョン管理して、wslさえあれば、すぐに立ち上げることが可能になります。

# コンテナ環境のテスト＆デバッグを効率的に行える

前述のexport, importの応用です。自分で作成したコンテナイメージ内で問題が発生した場合、デバッグするのは手間ですよね。この場合にも、export, importが役立ちます。問題が発生するコンテナ環境をexportし、wslへimportしてやることで、環境はそのままでVSCode等を利用したデバッグ作業が可能になります!

以下は起動して数秒後に異常終了してしまうNode.jsアプリの例です。

```shell
$ docker run -it -d --name node-debug hyperledger/explorer
c8ed7b77c396289e3330ee5101b45df7054fd5ed56fa17b85f3b7b9fa962223d
$ docker ps -a
CONTAINER ID        IMAGE                  COMMAND                  CREATED             STATUS                     PORTS               NAMES
66239d7f2ac3        hyperledger/explorer   "docker-entrypoint.s…"   8 seconds ago       Exited (1) 2 seconds ago                 node-debug
```

```shell-session
# On wsl
# entrypointを変更してシェルでアイドルさせてコンテナを起動させます
$ docker run -it -d --name node-debug --entrypoint /bin/sh hyperledger/explorer
$ docker export --output node-debug.tar node-debug

# On power shell
PS > wsl --import node-debug ./node-debug-ws \\wsl$\Ubuntu-18.04\home\atsushi\dev\qiita_test\node-debug.tar
```

wsl2にimportしたnode-debug環境を開くとランタイムの環境がShellでのアイドル状態で立ち上がり、VS codeでデバッグができる状態になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/b60ce376-7b5e-efdf-7cc8-4af753d1598f.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/b71f4c6b-2012-3593-dac4-8b8785b556ee.png)

VS code起動後、さきほどimportした環境に接続することで、VS code上のデバッガでブレイクさせながら、先ほど発生していた問題の原因を追うことができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/4d37a39e-e108-e9d7-389f-0f7ddd6d0a33.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/f82244cd-2116-8e5f-205b-076ffcfca2bb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39615/2bc29e99-8ba6-5cf6-deeb-673d749a0424.png)


# その他

* Windows向けDockerの実装は、Microsoftと密に連携して進められているようです。
[Docker ❤️ WSL 2 - The Future of Docker Desktop for Windows - Docker Blog](https://www.docker.com/blog/docker-hearts-wsl-2/)

* 動的にメモリが獲得、解放され、WSL2のfootprintは低く抑えられるといいましたが、現在少し問題があるようでウォッチ中です。
    * https://github.com/microsoft/WSL/issues/4166


# 最後に

昔はCygwinでlinux-likeな環境をWindows上で使ったり、PCをデュアルブートにしてLinux環境を用意したり、色々手間をかけてWindows/Linux両環境を用意していましたが、もうそういった苦労は必要なさそうです。[Surface Duo](https://www.microsoft.com/en-us/surface/devices/surface-duo)でもAndroidを採用するなど、MicrosoftのLinux愛がひしひしと感じられます。公式リリースが待ち遠しいですね。