Windows上のWSLでコンテナによる開発環境を作ってみる（前準備編）

# 記事の内容を三行で言うと
* WindowsにDocker を入れてPython開発環境を作りたい。
* 手元のPCでDocker for Desktop を入れるにはWSLが必要。
* そのためにまずWSLをセットアップします。

という内容の記事になります。


# 経緯
* 最初のきっかけとして、自分のPC上にPythonの開発環境を作りたくなりました。
* 一口にPythonの環境と言っても色々あります。単純にPythonだけ入れるか、Anacondaを入れるか、Jupyter Notebookを入れるかと言った問題があります。またNumpyやPandas、matplotlibなど、どのようなモジュールを環境に取り込むかという違いもあります。今回は手始めなので単純にPythonだけ入れれば良いのですが、いったん環境作った後に他のPython環境に切り替えたくなったら面倒なことになります。環境を汚してしまっているため、いったんアンインストールして綺麗にしてから入れ直しになります。そういう面倒なことはしたくないです。
* それぞれの環境をコンテナ上に構築して、使いたいときに切り替えて使えば便利です。
* Windows用の[Docker Desktop](https://www.docker.com/products/docker-desktop) というものが世の中には存在します。それを使ってWindows上でコンテナを使った環境構築は可能なはずです。ということでやり方を調べてみたのが今回のレポートになります。

# そもそもDockerで開発環境を作ると何がうれしいのか？のおさらい
* コンテナを共有可能で、簡単に自分の環境に導入できます。誰かが環境を一度作ればそれを再利用できるので、チーム全員が開発環境作るのに手順書見ながら丸一日かかるなどのあまり本質的でない苦労から解放されます。
* チームメンバー全員が簡単確実に同じ環境で作業できることが保証されます。（なぜか一人だけ構築に失敗して動かない…などのトラブルから解放）。
* 動作環境のわずかな違いによって生ずるようなタイプのバグを撲滅できる可能性がある。昔からよくある、本番環境では異常がでるのに開発環境では再現しない、ということが減らせます。
* ほかの仮想環境と違い、起動と停止が一瞬でできるので開発時が楽。
* テキストファイルで環境を管理でき、今どういう環境で開発しているのか確認しやすい。
* 同様の理由で環境のバージョン管理もしやすい。
* プロジェクトごとに言語やライブラリ等のバージョンを切り替えるのもコンテナを入れ替えるだけで簡単に対応可能です。
* 数十のコンテナを同時に実行することが可能であり、実働環境そのままの分散システムをエミュレーションできます。VMだけを使う場合に比べて、１台のホストマシンではるかに多くのコンテナを実行できます。
* 少しだけマシンスペックが必要ですが、得られるメリットによって軽減できる人件費や精神的負担の大きさから考えれば微々たるものです。


# 前提知識の整理
* コンテナとは仮想化の仕組みの一種であり、そのための代表的なツールがDockerと呼ばれるものです。このDockerはもともとLinuxカーネルのNamespace機能を利用するものですので、Windows上では直接動きません。Windows上でコンテナ環境を構築したい場合、Windows上で動く仮想環境上にLinuxを動かし、さらにその上でDockerを動かすことで実現します。
* このような場合、Windows上で動く仮想Linux環境には３パターンあるようです[^2]
    1. Windows上でMicrosoft社が提供するLinuxカーネルで動くLinux環境であるWSL(Windows Subsystem for Linux)を動かし、WSL上でDockerを動かす（Docker Desktop WSL版）
    1. Windows上でハイパーバイザ型仮想化ツールであるHyper-Vを動かし、そこでDocker社の提供するLinuxカーネルを動かし、その上でDockerを動かす（Docker Desktop Hyper-V版）
    1. Windows上でホストOS型仮想化ツールであるVirtualBoxを動かし、そこでDocker社の提供するLinuxカーネルを動かし、その上でDockerを動かす。（Docker Toolbox）
* この３パターンのうち、3.はすでに事実上使われておらず、最近MSからWSL2が提供されたことにより、2.よりも1.のやり方を使うのが一般的となっています。また、2.のやり方はWindows10 Pro Editionでしか使えず、Windows10 Home Edition の場合は1.のWSL版一択という状況です。
* 以上から、まずWindows上にWSL環境を用意し、さらにその上でDockerを動かすことを考えます。


## WSLについて
* WSLはMicrosoftが公式に用意した、Windows上で動く完全互換なLinux環境です。Windows10以上であればHome Editionでも無料で使えます。
* これまでのホストOS型仮想環境やデュアルブートよりも手軽に１つのPC上でLinuxとWindowsとを併用することができます。
* WSLの公式ドキュメントはこちらにあります。
  * [Windows Subsystem for Linux に関するドキュメント | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/)

>Linux 用 Windows サブシステムを使用すると、開発者は、従来の仮想マシンまたは
>デュアルブート セットアップのオーバーヘッドなしで、
>ほとんどのコマンドラインツール、ユーティリティ、アプリケーションを含む 
>GNU/Linux 環境を変更せずそのまま Windows 上で直接実行できます。

* WSL2では初代バージョンから進化して、本物の Linux カーネルを直接実行するようになりました。Windows上でWindowsカーネルとLinuxカーネルが並行動作します。
* Windows上でUNIXっぽいAPIを提供する試みとして今までにも [Cygwin](https://www.cygwin.com/)などがありましたが、WSLはMSが公式に提供するものであり、Linux完全互換を謳っているところがポイントです。
* 2020年、WSLの新しいバージョンである WSL2 がリリースされました。ファイル システムのパフォーマンスを向上させ、システムコールの完全な互換性があるとのことです。
* さらにWindows11 からはWSLg と呼ばれる、WSL上でX11プロトコロルやWaylandなどを使ったGUIを動かせる仕組みも提供されます。これによりWSL上で X-WindowアプリやGnomeを使ったアプリも動かせることになります。
※今回は自宅PC上の Windows 10 Home Edition Ver.20H2 で動作確認したためWSLgまでは深堀りしません。

# WSLのセットアップ
* まず初期状態でコマンドラインからWSLコマンドを叩いてみます。ここではPowerShellからコマンドを叩いていますが、普通のコマンドプロンプトからでもOKです。
* 管理者権限で実行する必要があります。

```:PowerShell
PS C:\> wsl

Copyright (c) Microsoft Corporation. All rights reserved.

使用法: wsl.exe [引数]

引数:

     --install <Options>
     Windows Subsystem for Linux の機能をインストールします。オプションが指定されていない場合は、
      既定のディストリビューションと共に、推奨される機能がインストールされます。

既定のディストリビューションおよびその他の有効な配布物の一覧を表示するには、
        'wsl --list --online' を使用してください。

        オプション:
            --distribution, -d [Argument]
              ダウンロードしてインストールするディストリビューションを名前で指定します。

                引数:
                    有効なディストリビューション名 (大文字と小文字は区別されません)。

                例:
                    wsl --install -d Ubuntu
                    wsl --install --distribution Debian

    --list, -l [Options]
        ディストリビューションを一覧表示します。

 オプション：
            --online, -o
                 'wsl --install' を使用してインストールするために使用できるディストリビューションの一覧を表示します。

    --help
        使用方法に関する情報を表示します
```
* WSLに関して何も設定していない初期状態では↑このような表示になるようです。
* この状態ではWSLは無効になっていてカーネルだけしかない状態であり、何らかのディストリビューションをインストールしなければ使えません。
* そのためまずコントロールパネル「プログラムと機能」の Windowsの機能から WSLを有効化します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/5e1a3782-bacb-d9b9-b451-f766f5da7d79.png)
* するとwslコマンドの出力も変わります。

```:PowerShell
PS C:\> wsl
Linux 用 Windows サブシステムには、ディストリビューションがインストールされていません。 
ディストリビューションは Microsoft Store にアクセスしてインストールすることができます:
https://aka.ms/wslstore
```

* この状態では、WSLにはまだLinuxカーネルしかなく、WSLを動かすにはその上にディストリビューションをインストールする必要があります。
* ここで念のため、ディストリビューションを入れる前にx64用WSL2 Linuxカーネル更新プログラムをダウンロードしてインストールしておきます。
* ダウンロード元：https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/95ff0fc0-32cd-4b04-d43e-80c064349fe3.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/20a2517d-5608-a41c-6b89-4601f4315e3b.png)
* 次にWSL2を規定のバージョンとして設定しておきます。

```:PowerShell
PS C:\> wsl --set-default-version 2
WSL 2 との主な違いについては、https://aka.ms/wsl2 を参照してください
この操作を正しく終了しました。
```

* この時点で WSL のステータスを表示してみます。

```:PowerShell
PS C:\> wsl --status
既定のバージョン: 2

Linux 用 Windows サブシステムの最終更新日: 2022/01/15
WSL の自動更新が有効になっています。
```

* これでWSL2が有効になりました。

## WSLにディストリビューションをインストールする
* WSL2に入れられる Linux ディストリビューション一覧を表示してみます。

```:PowerShell
PS C:\> wsl -l -o
インストールできる有効なディストリビューションの一覧を次に示します。
'wsl --install -d <Distro>' を使用してインストールします。

NAME            FRIENDLY NAME
Ubuntu          Ubuntu
Debian          Debian GNU/Linux
kali-linux      Kali Linux Rolling
openSUSE-42     openSUSE Leap 42
SLES-12         SUSE Linux Enterprise Server v12
Ubuntu-16.04    Ubuntu 16.04 LTS
Ubuntu-18.04    Ubuntu 18.04 LTS
Ubuntu-20.04    Ubuntu 20.04 LTS
```
* いろいろ入れられるようですが、ここではディストリビューションとして Ubuntu を入れてみます。

```:PowerShell
PS C:\> wsl --install -d Ubuntu
ダウンロード中: Ubuntu
インストール中: Ubuntu
Ubuntu はインストールされました。
Ubuntu を起動しています...
PS C:\>
```
* 別ウィンドウでターミナルが起動し、Ubuntu のユーザ名とパスワードの設定をします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/4c6d0141-c659-3b43-1055-cccd02897a1f.png)
* この時設定したユーザ名でWSLが起動します。パスワードは sudo をやるときに必要になるので控えておきます。
* ここではユーザ名を smatsu としました。

```:Ubuntuのターミナル表示
Installing, this may take a few minutes...
Please create a default UNIX user account. The username does not need to match your Windows username.
For more information visit: https://aka.ms/wslusers
Enter new UNIX username: smatsu
New password:
Retype new password:
passwd: password updated successfully
Installation successful!
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

Welcome to Ubuntu 20.04 LTS (GNU/Linux 5.10.16.3-microsoft-standard-WSL2 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage

  System information as of Sat Jan 15 23:14:27 JST 2022

  System load:  0.05               Processes:             8
  Usage of /:   0.4% of 250.98GB   Users logged in:       0
  Memory usage: 0%                 IPv4 address for eth0: 172.31.128.58
  Swap usage:   0%

0 updates can be installed immediately.
0 of these updates are security updates.


The list of available updates is more than a week old.
To check for new updates run: sudo apt update


This message is shown once once a day. To disable it please create the
/home/smatsu/.hushlogin file.
smatsu:~$
```

* ロケールを確認します。

```:Ubuntu
$ locale -a
C
C.UTF-8
POSIX
en_US.utf8
```

* 英語しかないので日本語ランゲージパックを入れます。※出力表示は割愛

```:Ubuntu
$ sudo apt install -y language-pack-ja
```

* ロケールが追加されました

```:Ubuntu
C
C.UTF-8
POSIX
en_US.utf8
ja_JP.utf8　←
```

* ロケールを日本語に設定します。ログオンし直すと反映されます。

```:Ubuntu
$ sudo update-locale LANG=ja_JP.UTF-8
```

* さらに念のためパッケージも更新しておきます。※出力表示は割愛

```:Ubuntu
$ sudo apt-get update
$ sudo apt-get -y upgrade
```

* OSリリース確認

```: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
```

* いったんexitし、WSLのディストリビューションを確認します。

```:PowerShell
c:\>wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu                 Running         2
```

* これでWSLが動く状態になりました。コマンドラインから wsl と打つことでWSL上のLinuxディストリビューションである Ubuntu に入れます。

```:コマンドライン
C:\Users\smatsu>wsl
smatsu:/mnt/c/Users/smatsu$
```

* 切り替えが非常に簡単で、ユーザ名もパスワードも聞かれません。


# Docker のインストール
* ここまででWSLの準備ができたので、Docker をインストールします。
* インストーラのダウンロード元：Docker Desktop for Mac and Windows | Docker>https://www.docker.com/products/docker-desktop
* インストーラを実行します。非常に簡単です。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/6161f375-6008-5477-a350-21f3068af952.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/c236bcd1-f878-daac-0f4b-34c07a6cc10e.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/1a60ffd0-6e2c-3a4c-ab5d-eaa7122f3e64.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/76bd108d-78ae-b448-778d-84c7b854f49a.png)

* 無事Docker Desktopが起動しました。
* この状態で WSL からディストリビューションを確認するとこうなっています。

```:コマンドライン
c:\>wsl -l -v
  NAME                   STATE           VERSION						
* Ubuntu                 Running         2						
  docker-desktop         Running         2						
  docker-desktop-data    Running         2						
```

* WSL上に docker-desktop と docker-desktop-data という２つのディストリビューションが追加されています。
* このDockerによって追加された２つのディストリビューションが何者なのかというと、下記の記事に少し説明がありました。
  * [セットアップ - Docker on WSL 2 + Windows ターミナル - Qiita](https://qiita.com/yokarikeri/items/367741844abde4d3c7f4)

>Docker Desktop はデフォルトでは「WSL 2 VM」上で以下の 2 つのディストリビューションを動作させる方式が採用された。
>　　docker-desktop: ブートストラップ ディストリビューション
>　　　　Docker エンジン本体
>　　docker-desktop-data: データ ストア ディストリビューション
>　　　　Docker イメージやコンテナーを格納

* この情報のモトネタはこちらのDocker公式blogからのようです。
    * [Introducing the Docker Desktop WSL 2 Backend - Docker Blog](https://www.docker.com/blog/new-docker-desktop-wsl2-backend/)


# WSLとWindows 上のファイルの相互参照
* WindowsとWSL上のLinuxからはお互いの配下にあるファイルを参照可能です。


## WSL上のUbuntu からWindows配下のファイルを見る場合
* WSLからWindows上のファイルにアクセスしたい場合、 /mnt/c の下にドライブがマウントされています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/8962daad-0933-87ea-2c55-576a00f9af7a.png)

* このPCではCドライブとFドライブがあるのでここに表示されています。
* /mnt/wsl というのは、ドキュメントによるとマウントされたドライブがポイントされる既定のパスだそうです。
  * 参考：[WSL 2 で Linux ディスクのマウントを開始する | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/wsl2-mount-disk)

## Windows上からWSL配下のファイルを見る場合
* エクスプローラで \\\\wsl$ にアクセスするとディストリビューションのフォルダが見えるようになっています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/9ea47cdb-7924-e2c5-f9f1-d3a2e8bed508.png)

* Ubuntu の中です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/99b584db-e67c-ec12-2a6f-7d7829f98fed.png)

* docker-desktop の中です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/a9e2341d-1e25-e146-c93e-66d120bea51c.png)

* docker-desktop-data の中です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2261111/129bbf95-9060-5be7-761e-62d7fcddd8eb.png)

# Dockerのバージョンを確認
* WSLに戻って docker のバージョンを確認してみます。

```:Ubuntu
$ docker version
Client:
 Cloud integration: v1.0.22
 Version:           20.10.12
 API version:       1.41
 Go version:        go1.16.12
 Git commit:        e91ed57
 Built:             Mon Dec 13 11:44:07 2021
 OS/Arch:           windows/amd64
 Context:           default
 Experimental:      true

Server: Docker Engine - Community
 Engine:
  Version:          20.10.12
  API version:      1.41 (minimum version 1.12)
  Go version:       go1.16.12
  Git commit:       459d0df
  Built:            Mon Dec 13 11:43:56 2021
  OS/Arch:          linux/amd64
  Experimental:     false
 containerd:
  Version:          1.4.12
  GitCommit:        7b11cfaabd73bb80907dd23182b9347b4245eb5d
 runc:
  Version:          1.0.2
  GitCommit:        v1.0.2-0-g52b36a2
 docker-init:
  Version:          0.19.0
  GitCommit:        de40ad0
```

# いよいよDockerを使ってPython環境のコンテナを構築する…のですが

* これでやっとコンテナ上に Python環境を作る準備ができましたが、ここまででかなり長い記事になってしまったのでいったんここまでとします。
* 次回のレポートで実際にコンテナ上にPython環境を作って動かしてみる所まで行きたいと思います。
* やりたいこととしては
    * Dockerfile 、docker-compose.yml でコンテナの構築方法を書きコンテナを起動。
    * コンテナ上でPythonプログラムを実行し、VSCode からリモートでつないでデバッグしたい。
* 続きの記事を投稿しました。こちらになります
    * [Windows上のWSLでコンテナによる開発環境を作ってみる（Python環境編）](https://qiita.com/smats-rd/private/e65feae601b4496be381)

以上です。

[^2]: [Windows版Docker｜3種類の違い](https://penpen-dev.com/blog/windows-docker-tigai/)