WSL2(Ubuntu18.04 LTS)をセットアップしてDocker(on Ubuntu)とGUIアプリを使う

# はじめに
私はWSL2がInsider Previewに入ってからずっと業務の開発で利用してきましたが、もうすぐ正式リリースというのと、社内でも利用する人が増えてきたので知識の整理も含めて記事にしてみました。

localhostとか使えなかったのがもはや懐かしい...

# WSL2
[WSL2について](https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-about)

Windows上のWindowsサブシステムでLinuxを実行できるようにする技術です。
WSL1と異なり、VM(Hyper-V)を利用して実装されています。しかし通常のVMと異なり高速な起動とWindowsとLinuxの連携、VMの管理が不要な点を利点としています。

# WSL有効化

[ドキュメント](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)を参考にセットアップをすすめていきましょう。

```powershell

# Windows Subsystem for Linuxのインストール
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

# 仮想マシンプラットフォームの有効化
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# 再起動後、wslコマンドが利用可能になるはずなのでWSLのデフォルトバージョンを2に設定
wsl --set-default-version 2

```

## カーネル更新パッケージのインストール
以下のmsiファイルをインストールしましょう。

[x64 マシン用 WSL2 Linux カーネル更新プログラム パッケージ](https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi)



## OSの選定

Microsoft Storeもしくはインターネット上からWSL用イメージを取得します。

[Awesome WSL Supported Distributions](https://github.com/sirredbeard/Awesome-WSL#supported-distributions)

今回記事で取り上げるUbuntu18.04 LTSが現状情報が多く感じます。Ubuntu20.04LTSもストアにリリースされているようです。

個人的には非公式にはなりますが、 [ArchWSL](https://github.com/yuk7/ArchWSL) が結構動いてくれて開発する分にはあまり困ることもなかったので推したいです。

## WSL設定(.wslconfig)
`C:\\User\ユーザー名\.wslconfig`にwsl2の設定を記述できます。

私はメモリ制限、SWAPの有効化を入れています。

設定項目については、[Manage Linux Distributions](https://docs.microsoft.com/en-us/windows/wsl/wsl-config) が詳しいかなと思います。

```ini
[wsl2]
memory=8G
swap=4G
```

# [Windows Terminal](https://www.microsoft.com/ja-jp/p/windows-terminal-preview/9n0dx20hk701?activetab=pivot:overviewtab)
WSL2の発表と同時期に発表されたMicrosoft開発のターミナルです。既存のビルトインのターミナルを置き換えるべく開発をすすめているとかなんとか...

こちらもPreview版のリリース直後は突然クラッシュしたり、表示が崩れたりなどのバグが多かったですがリリースされた現在では安定しています。

描画は高速で綺麗なためVimなどのリッチなCUIプログラム扱うのも非常に快適です。
PowerShell, WSL, Azureとの親和性は高く、WSLのディストリビューションを追加すると勝手に起動オプションを追加してくれて非常に便利です。

私の設定はデフォルトプロファイルをUbuntuに設定したり、カラースキームは個人的に鉄板な [Dracula](https://github.com/dracula/windows-terminal)を利用しています。

ペイン分割も設定していますが、私はtmuxを使うのであまり使いません。

```json
{
    "$schema": "https://aka.ms/terminal-profiles-schema",

    "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

    "profiles":
    {
        "defaults":
        {
            // Put settings here that you want to apply to all profiles
            "fontFace": "Hackgen Console",
            "fontSize": 14,
            "colorScheme": "Dracula"
        },
        "list":
        [
            {
                // Make changes here to the powershell.exe profile
                "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
                "name": "Windows PowerShell",
                "commandline": "powershell.exe",
                "hidden": false
            },
            {
                // Make changes here to the cmd.exe profile
                "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
                "name": "cmd",
                "commandline": "cmd.exe",
                "hidden": false
            },
            {
                "guid": "{2c4de342-38b7-51cf-b940-2309a097f518}",
                "hidden": false,
                "name": "Ubuntu",
                "source": "Windows.Terminal.Wsl",
                "commandline": "wsl ~ -d Ubuntu"
            },
            {
                "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
                "hidden": false,
                "name": "Azure Cloud Shell",
                "source": "Windows.Terminal.Azure"
            },
            {
                "guid": "{a5a97cb8-8961-5535-816d-772efe0c6a3f}",
                "hidden": false,
                "name": "Arch",
                "source": "Windows.Terminal.Wsl"
            }
        ]
    },

    // Add custom color schemes to this array
    "schemes": [
        // 個人的に
        {
            "name" : "Dracula",
            "background" : "#282A36",
            "black" : "#21222C",
            "blue" : "#BD93F9",
            "brightBlack" : "#6272A4",
            "brightBlue" : "#D6ACFF",
            "brightCyan" : "#A4FFFF",
            "brightGreen" : "#69FF94",
            "brightPurple" : "#FF92DF",
            "brightRed" : "#FF6E6E",
            "brightWhite" : "#FFFFFF",
            "brightYellow" : "#FFFFA5",
            "cyan" : "#8BE9FD",
            "foreground" : "#F8F8F2",
            "green" : "#50FA7B",
            "purple" : "#FF79C6",
            "red" : "#FF5555",
            "white" : "#F8F8F2",
            "yellow" : "#F1FA8C"
        }
    ],

    "keybindings": [
        // ペイン分割と移動。Vim風にしています。
        { "command": { "action": "splitPane", "split": "vertical" }, "keys": "ctrl+shift+e" },
        { "command": { "action": "splitPane", "split": "horizontal" }, "keys": "ctrl+shift+d" },
        { "command": { "action": "splitPane", "split": "auto" }, "keys": "alt+shift+|" },
        { "command": { "action": "moveFocus", "direction": "down" }, "keys": "ctrl+shift+j" },
        { "command": { "action": "moveFocus", "direction": "left" }, "keys": "ctrl+shift+h" },
        { "command": { "action": "moveFocus", "direction": "right" }, "keys": "ctrl+shift+l" },
        { "command": { "action": "moveFocus", "direction": "up" }, "keys": "ctrl+shift+k" }
    ]
}
```

# VSCode Remote Development
指定した接続先でVSCodeを開けるスグレモノです。SSH、Docker、WSLまでカバーしています。

[Remote Development Extension Pack](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.vscode-remote-extensionpack)をVSCodeに入れるだけで導入完了です。

WSLのターミナルにログインして、

```shell
code .
```

と実行するだけで、WSL内のディレクトリが開けます。便利です。

# Ubuntu18.04 LTS(20.04 LTS)
# Dockerをセットアップする
## systemd
最近のLinuxディストリビューションでは依存するパッケージも増えてきているsystemdですが、WSL上のLinuxではMicrosoft独自のLinuxカーネルを利用しているため無効化されています。

もちろんsystemdを利用せずとも開発はできるのですが、自動起動周りが微妙に面倒なので自分は後述のgenieを導入してsystemdを稼働させています。

### genie
[https://github.com/arkane-systems/geni](https://github.com/arkane-systems/genie)

wslでsystemdを起動するための便利ツールです。

dotnet runtimeが必要なため[ガイド](https://docs.microsoft.com/ja-jp/dotnet/core/install/linux-package-manager-ubuntu-1804)に沿って、

```shell
# 18.04
wget https://packages.microsoft.com/config/ubuntu/18.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb
sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y aspnetcore-runtime-5.0

# 20.04 LTS
wget https://packages.microsoft.com/config/ubuntu/20.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb

sudo apt-get update; \
  sudo apt-get install -y apt-transport-https && \
  sudo apt-get update && \
  sudo apt-get install -y aspnetcore-runtime-5.0
```

dotnet runtimeをセットアップしたのち、[genieのインストール手順に従って](https://github.com/arkane-systems/genie#debian)、

```shell
apt install apt-transport-https

wget -O /etc/apt/trusted.gpg.d/wsl-transdebian.gpg https://arkane-systems.github.io/wsl-transdebian/apt/wsl-transdebian.gpg

chmod a+r /etc/apt/trusted.gpg.d/wsl-transdebian.gpg

cat << EOF > /etc/apt/sources.list.d/wsl-transdebian.list
deb https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
deb-src https://arkane-systems.github.io/wsl-transdebian/apt/ $(lsb_release -cs) main
EOF

apt update
```

以下のコマンドを実行して `systemd-genie`のインストールをします。

```shell
sudo apt update
sudo apt install systemd-genie
```

これでgenieのセットアップは完了で、シェル上で

```shell
# Ubuntu 18.04 LTS用
genie -c bash

# Arch等々
genie -s

# systemd起動確認
sudo systemctl status
```

と実行することで、新しくシェルが起動されてsystemdが起動出来ます。

何個かサービスがFailedしていますが、開発には今の所支障はありません。気持ち悪いのでいつか修正できたらと思っています。

## genie 1.31以降で "Waiting for systemd....!!" で止まってしまう問題
https://github.com/arkane-systems/genie#warning-timing-out に記載がありますが、systemdのすべてのサービスが正常に起動するまで待つ挙動だが、ここまでセットアップした環境だと数個のサービスが起動しないためブロックしてしまう模様。数秒待機した後、Ctrl+Cして再度 `genie -s` するとsystemdにアクセス可能なシェルにログインできます。

ログインした後、起動に失敗しているサービスを停止しておきます。必要になったらまた考えましょう。

```shell
# 以下のコマンドで失敗しているサービスを一覧できます
sudo systemctl list-units --state failed

# 筆者の環境で失敗していたサービスたち
sudo systemctl mask systemd-remount-fs.service
sudo systemctl disable ssh.service multipathd.service multipathd.socket
```

## Docker
公式の[ガイド](https://docs.docker.com/engine/install/ubuntu/)に沿って進めていきます。

```shell
sudo apt install apt-transport-https ca-certificates curl gnupg-agent software-properties-common

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -

sudo apt-key fingerprint 0EBFCD88

sudo add-apt-repository \
   "deb [arch=amd64] https://download.docker.com/linux/ubuntu \
   $(lsb_release -cs) \
   stable"

sudo apt update && sudo apt install docker-ce docker-ce-cli containerd.io

sudo gpasswd -a $USER docker

# 再ログイン後

docker run hello-world

# docker-compose
sudo apt install python3-pip

sudo curl -L "https://github.com/docker/compose/releases/download/1.29.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose

sudo chmod +x /usr/local/bin/docker-compose

docker-compose -v
```

# GUIアプリを使う
最近のWeb関係の開発はDockerやVSCodeだけで事足りてしまうのですが、Cypressのようなブラウザを利用するテストツールはHeadlessモードがあるとはいえGUIの使えない開発はしんどいです。
なのでWSL経由でGUIを起動できるようにX ServerをWindows側にセットアップしています。

## Xサーバー
### X410
[Microsoft Store](https://www.microsoft.com/ja-jp/p/x410/9nlp712zmn9q?activetab=pivot:overviewtab)

自分は有償ですがこちらを利用しています。ファイアウォールの設定をしてしまえばアプリを起動するだけで勝手に常駐してくれるので楽です。
動作も結構安定しています。

### VcXsrv
[Source Forge](https://sourceforge.net/projects/vcxsrv/)

利用者や情報が多いのはこちら。無償です。

起動時の設定で

- Display Settings
    - Multiple Windows(任意)
- Start Clients
    - Start no client
- Extra Settings
    - Clipboard: true
    - Native opengl: true
    - Disable access control: false
    - Additional parameters for VcXsrv
        - `-ac`
 
 で設定するのがおすすめです。

 ### 共通
 どちらも共通なのですが、コントロールパネル -> ファイアウォール -> Windows Defenderファイアウォールを介したアプリまたは機能を許可

 でX410、VcXsrvの許可をしておかないとWSL側からWindowを立ち上げられません。

![Untitled.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314367/294620ab-96ea-d6e0-644d-83090a4dec51.png)

![Untitled (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/314367/066fe66c-eb8b-b1ae-94c9-928acecc4536.png)


 ### 動作確認

 ```shell
sudo apt install x11-apps

export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0

xeyes
 ```

DISPLAYを設定している行は.bashrcにでも追記しておくと便利です。

## [Cypress](https://www.cypress.io/)

試しにちょっとリッチなGUIアプリケーションを動作させてみます。

### セットアップ・起動
必要な依存関係をインストール

```shell
sudo apt install libgtk2.0-0 libgtk-3-0 libnotify-dev libgconf-2-4 libnss3 libxss1 libasound2 libxtst6 xauth xvfb
```

nodeをセットアップして、

```shell
mkdir cypress test
npm init

# yes, yes, yes...

npm install cypress
npx cypress open

```