Windows 10 WSL 2（Linux 用 Windows サブシステム） + LinuxでのPython環境作成手順

# 概要

Windows 10における、WSL 2にLinuxをインストール～Python仮想環境構築までを記載しています。

|モジュール|役割|
|---|---|
|Python|(2)で説明<br>.pyを実行するインタプリタ|
|pyenv|(3,4)で説明<br>Mac, LinuxでPythonインタプリタを切り替える（複数バージョンを共存）ために使用する |
|venv|(4)で説明<br>Pythonの仮想環境を作成する（仮想環境は基本的にはプロジェクトごとに作成する）。pyenvでインストールされたpython3.3以降では既定で使用可能|

(4)で説明していますが、`pyenv`でインタプリタを切り替え、`venv`で仮想環境を作成・切替を行うことで、プロジェクトごとに適した環境で開発を行います。

# 環境

- Windows 10 Pro バージョン 2004以降、または1903,1909ビルド18362以上
- Ubuntu 20.04 LTS on WSL2
- Linux内のPythonのバージョン3.3以上（venv, pyenvの関係）

# (1) WSL2環境構築

## (1-1) [Windows] WSL2の有効化

以下の公式ページの[手動インストール](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#manual-installation-steps)の手順に従い、WSL2を有効化します。

- [Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs](https://docs.microsoft.com/ja-jp/windows/wsl/install-win10)

以降、**Ubuntu 20.04 LTS** を選択した前提で記載します。

### (1-1-1) [Windows] WSL2メモリ上限の設定

WSL2にはWindowsホストのメモリが枯渇してしまう問題があるため、以下の設定を行います。

Windows 10 ビルド 20175（Insider Preview）ではWindows または 8 GB のメモリ合計の 50% (どちらか少ない方) を上限という対策がされていますが、現時点（21H1以前）ではWindows のメモリ合計の 80% を使用するため設定が必要です。

`%USERPROFILE%\.wslconfig`に以下の設定を行います。

```ini
[wsl2]
memory=8GB
swap=0
```

|||
|--|--|
|memory=8GB|物理メモリが16GBの場合。最大8GB推奨|
|swap=0|SSD等で大量のスワップIn/Outの発生を防ぐため。WSL2側で実際にメモリ不足となった場合は設定しない|

またWSL2が不要となった場合は、Docker Desktopの終了、`WSL --shutdown`コマンドの実行でメモリを開放することができます。

[参考1](https://docs.microsoft.com/ja-jp/windows/wsl/wsl-config)、[参考2](https://qiita.com/yoichiwo7/items/e3e13b6fe2f32c4c6120)

## (1-2) [Windows] インストールしたディストリビューションの起動

スタートメニューからUbuntuを選択します。

初回起動時は以下が表示されるので画面に従いユーザー名とパスワードを設定します。

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

## (1-3) [Windows] Windows Terminalのインストール

[winget](https://github.com/microsoft/winget-cli/releases)を利用してインストール

```bat
winget install -e --id Microsoft.WindowsTerminal
```
## (1-4) [Windows] VSCodeのインストール

https://code.visualstudio.com/download

- User Installを使用する
- 右クリックでCodeで開くにチェックする

## (1-5) [Windows] VSCodeで「Remote Development」のインストール

1. 「Remote Development」をインストール

    以下の拡張機能3つのパック
    ・Remote - SSH
    ・Remote - Containers
    ・Remote - WSL

1. 拡張機能をインストールしたら、VSCodeを再起動

1. 「Remote Development」をインストールすると「Remote Explorer」がVS Codeに追加される。Remote Explorerでは、Linuxディストリビューションに関する情報を確認できる。

## (1-6) [Windows] VSCodeからWSL2上のUbuntuに接続する

1. VSCodeを起動し、「Remote Explorer」からUbuntuに接続する

1. 接続時に必要なコンポーネント(vscode-server)がUbuntuにインストールされる

💡 この手順はプロキシ環境では(1-7)の前に行う必要があります。
　Linux(WSL)がインターネット接続不可（プロキシ未設定の状態）でも、WindowsのVSCodeからLinux(WSL)にvscode-serverのパッケージをインストールすることができます。

## (1-7) [Linux] プロキシ設定

社内環境など外部接続にプロキシが必要な環境では、この項目の設定が必要です。

### (1-7-1) ユーザーの設定

**環境変数**

Windows TerminalのUbuntuターミナルから実行します。

```bash
# -- Ubuntu 20.04 on WSL2
# VSCodeで開く
code ~/.bashrc
``` 

**~/.bashrc**の最後に追加します

```bash
function proxy_on(){
  HOST="XXX.XXX.XXX.XXX"
  PORT="YYYY"

  # 認証が必要なプロキシ
  PROXY="http://$HOST:$PORT/"

  export HTTP_PROXY=$PROXY
  export HTTPS_PROXY=$PROXY
  export FTP_PROXY=$PROXY
  export http_proxy=$PROXY
  export https_proxy=$PROXY
  export ftp_proxy=$PROXY

  export NO_PROXY="localhost,127.0.0.1"
  export no_proxy="localhost,127.0.0.1" 
}

proxy_on
```

💡 `proxy_on`の後で改行が必要です。
💡 Linux環境から社内環境のGitサーバーを参照する場合はNO_PROXYに追加します。
💡 NO_PROXYではワイルドカードが使用できません。また、カンマ区切りを認識しない場合もあるので必要に応じ設定を変更してください。

```bash
# -- Ubuntu 20.04 on WSL2
# bashに反映
source ~/.bashrc
```

### (1-7-2) 管理者の設定

`sudo`による実行ではユーザーで設定した環境変数が引き継がれないため、以下の設定が必要です。

```bash
# -- Ubuntu 20.04 on WSL2
sudo visudo -f /etc/sudoers.d/proxy
（以下を追加する）
Defaults env_keep="HTTP_PROXY"
Defaults env_keep+="HTTPS_PROXY"
Defaults env_keep+="FTP_PROXY"
Defaults env_keep+="http_proxy"
Defaults env_keep+="https_proxy"
Defaults env_keep+="ftp_proxy"
``` 

💡 [参考情報](https://gihyo.jp/admin/serial/01/ubuntu-recipe/0331)

- `visudo`を使用して編集すること（正しく`sudo`を実行するための形式チェックが行われます）。
- 2番目以降の`env_keep`は`+=`であること
- ユーザの環境で引き継ぐ環境変数が正しく設定されていること

💡 上記設定変更以外の方法として`sudo -E your_command`を使用し、実行ごとに環境変数を引き継ぐ方法もあります（すべての環境変数を引き継ぐため、環境によっては注意が必要）。

## (1-8) [Linux] パッケージの更新

Windows TerminalのUbuntuターミナルから実行します。

```bash
# -- Ubuntu 20.04 on WSL2
# パッケージリストの更新
sudo apt update
# パッケージのアップデート
sudo apt upgrade -y
# 上記で保留されたパッケージのアップデート
sudo apt dist-upgrade -y
# 不要になったパッケージの削除
sudo apt autoremove -y
```

# (2) Pythonの導入

## (2-1) [Linux] Pythonのインストール

Windows TerminalのUbuntuターミナルから実行します。

```bash
# -- Ubuntu 20.04 on WSL2
# python3をインストール（インストールされているはずだが念のため）
sudo apt install python3 -y
```

💡 Python3系では`python3`を利用します。

## (2-2) [Windows] Linux環境への拡張機能のインストール

WindowsのVSCodeでWSL2を開き、WSL2のLinux環境に以下の拡張機能をインストールします。（Linux環境ごとにインストールされます。）

- `ms-python.python`
  `ms-python.vscode-pylance`と`ms-toolsai.jupyter`も自動的にインストール

- `visualstudioexptteam.vscodeintellicode`

💡 VSCodeでのリモート接続時は、Linux上にインストールされたVSCodeがLinux上で動作しています。そのため拡張機能も各環境ごとにインストールが必要です。

# (3) pyenvの導入

`pyenv`でPython（インタプリタ）のバージョン切り替えを行うことができます。

💡 Windows上に直接環境構築した場合は、Pythonインストール時にインタプリタ切り替えツール(`py`)がインストールされています。しかしLinux環境には存在しないため、`pyenv`の追加インストールが必要です。

## (3-1) [Linux] pyenvのインストール **(2021年5月14日更新)**

```bash
# -- Ubuntu 20.04 on WSL2
# pyenvのインストール
git clone https://github.com/pyenv/pyenv.git ~/.pyenv
# Ubuntuはpythonのビルドの前に事前設定が必要
# https://github.com/pyenv/pyenv/wiki/Common-build-problems
sudo apt install libedit-dev -y
sudo apt install libncurses5-dev -y
sudo apt-get install -y make build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \
xz-utils tk-dev libffi-dev liblzma-dev python3-openssl git
```

pyenvへのパスを通すために`~/.profile`に以下を追加する。

```
export PYENV_ROOT="$HOME/.pyenv" 
export PATH="$PYENV_ROOT/bin:$PATH" 
eval "$(pyenv init --path)" 
```

ただし`~/.profile`が`~/.bashrc`を読み込んでいる場合は、`~/.bashrc`の読み込み前に追加する

**`~/.profile`変更前（抜粋）**

```bash
(省略)
# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
	. "$HOME/.bashrc"
    fi
fi
(省略)
```

**`~/.profile`変更後（抜粋）**

```bash
(省略)
# if running bash
if [ -n "$BASH_VERSION" ]; then
    export PYENV_ROOT="$HOME/.pyenv" 
    export PATH="$PYENV_ROOT/bin:$PATH" 
    eval "$(pyenv init --path)" 
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
	. "$HOME/.bashrc"
    fi
fi
(省略)
```

pyenvをshellに読み込むために、`~/.bashrc`に以下を追加する

```bash
eval "$(pyenv init -)"
```

ログインセッションを再起動すると `pyenv` コマンドが使えるようになります。

## (3-2) [Linux] pyenvでインストール可能なインタプリタ

pyenvで利用可能なPythonバージョン一覧を確認します。

```bash
# -- Ubuntu 20.04 on WSL2
pyenv install --list
```

💡 バージョン3.3以上でvenvが利用可能

## (3-3) [Linux] pyenvでpythonをインストール

```bash
# -- Ubuntu 20.04 on WSL2
# 例としてPython3.6.9をインストール
pyenv install 3.6.9
# インストールされているPython一覧を確認
pyenv versions
```

## (3-4) [Linux] pyenvで複数のPythonバージョンを切り替え

以下は3.6.9に切り替えてから元に戻す例です。

```bash
# -- Ubuntu 20.04 on WSL2
# インタプリタをPython3.6.9に切り替え
pyenv shell 3.6.9
# 現在のバージョンを確認する
pyenv version
# バージョン3.6.9から元にもどす
pyenv shell system
```

# (4) pyenv + venv + pip で任意のバージョンの仮想環境を構築して開発

`pyenv`+`venv`+`pip`を使って、任意のPythonの仮想環境（パッケージ環境）を構築して開発したいときは、以下の手順でインタプリタの切り替えと仮想環境の切り替えを行います。

1. `pyenv`でインタプリタを切り替え
1. プロジェクトフォルダに移動
1. 切り替えたインタプリタで`venv`を実行しプロジェクトごとの仮想環境を作成
1. 仮想環境に入る
1. ライブラリのインストール（`pip`）など
1. コーディング、実行
1. 仮想環境を抜ける

以下はpyenvで3.6.9をインストールしていた場合のインタプリタの切り替えと仮想環境構築例です。

## (4-1) Linux上に作成したフォルダをカレントとしてWSLリモート接続環境のVSCodeを起動

```bash
# -- Ubuntu 20.04 on WSL2
# プロジェクトフォルダに移動
cd <プロジェクトフォルダ>
# Linux上のプロジェクトフォルダをWindowsのVSCodeで開く
code .
```

💡 Linux上にマウントされたWindows環境のフォルダ（`/mnt/c/~`）でも開発できます。しかしWSL2ではWindows環境へのファイルアクセスが遅いため、Linux上にソースコードを配置して開発することをお勧めします。
💡 Windows上でGPUを利用した機械学習を行いたい場合は、Linuxを使用せず[Windows上に環境を構築](https://qiita.com/c60evaporator/items/ba41cef4b37465c39948)して[GPUを使用](https://qiita.com/rhene/items/31bf4713b9dbda28bcc1)しWindows上でソース管理する、など使い分けが重要です。
💡 Linux上にソースコードを配置した場合、WindowsのエクスプローラーでLinux上のフォルダを開くことができます。
　手順1：Windowsエクスプローラーのアドレスバーに`\\wsl$\Ubuntu`を入力
　手順2：Linuxのターミナルで`explorer.exe .`を入力

## (4-2) インタプリタを切り替え

```bash
# -- Ubuntu 20.04 on WSL2
pyenv shell 3.6.9
```

## (4-3) 仮想環境を構築

```bash
# -- Ubuntu 20.04 on WSL2
cd <プロジェクトフォルダ>
python -m venv .venv
```

💡 `python3`では既定のPythonを参照するため、`pyenv`で切り替えた場合は`python`を指定します。
💡　VSCodeは同じフォルダの仮想環境を自動認識します。プロジェクトフォルダごとに仮想環境を作成し、仮想環境名称は`.venv`で統一することをお勧めします。

## (4-4) 仮想環境に入る

**Linux ターミナル**

```bash
# -- Ubuntu 20.04 on WSL2
# プロジェクトフォルダに移動
cd <プロジェクトフォルダ>
# Python仮想環境切り替え
source .venv/bin/activate
# Pythonのバージョン確認
python --version
```

**Windows VSCode**

左下から作成した仮想環境を選択します。

## (4-5) 仮想環境に必要なモジュールのインストール

**Python仮想環境が切り替わっていることを確認**し（プロンプト前に`(.venv)`が表示されます）、必要なモジュールをインストールします。

```bash
# -- Ubuntu 20.04 on WSL2
# 事前に`pip install wheel`を行うことでインストール時の警告が抑制されることがあります。
pip install wheel
# requirements.txtからインストールする場合の例
pip install -r requirements.txt
```

## (4-6) Python 仮想環境を抜ける

```bash
# -- Ubuntu 20.04 on WSL2
deactivate
```

# (5) Jupyter Notebookのインストール

Windows上にインストールしたPython環境ではPythonプラグインでVSCode上でJupyter Notebookを直接使用できます。しかし2020年12月31日現在、Windows→WSL2では動作しなかったため、通常のJupyter Notebookを使用します。

WSL上で起動したJupyter Notebookには、`http://localhost~`で接続できます。

```bash
# -- Ubuntu 20.04 on WSL2
# python仮想環境を起動
cd <プロジェクトフォルダ>
source .venv/bin/activate
# Jupyter Notebookをインストール
pip install wheel
pip install jupyter
# Jupyter Notebookを起動
jupyter notebook
```

# (6) (PCではなく)WSL2のみを終了、起動する方法

## (6-1) 特定のマシンを停止

1. [Windows環境] `wsl -l -v`で確認

      ```
      NAME      STATE           VERSION
      * Ubuntu    Running         2
      ```

1. [Windows環境] `wsl -t <NAME>`で停止

      💡 bashのヒストリーなどがクリアされるので注意

1. [Windows環境] `wsl -l -v`で確認

      💡 しばらく時間がかかる

      ```
      NAME      STATE           VERSION
      * Ubuntu    Running         2
      ```

## (6-2) すべてのマシンをシャットダウン

1. [Windows環境] `wsl --shutdown`ですべてのマシンをシャットダウン

## (6-3) WSL2を起動するには

起動は特に明示的に指定する必要はなく、通常通りUbuntuを起動すればOK。

- Windows Terminalで新規のUbuntuタブを開く
- Ubuntu2004.exeを実行する（スタートメニューからUbuntu 20.04を選択する）

---
# 補足情報

## 補足1：LinuxでWindowsのVSCodeを簡単に開く

Linux(WSL)で`code .`を実行すると、VSCodeを簡単に開くことができます。

1. Linux(WSL)でVSCodeで開きたいフォルダに移動する
2. `code .`を実行
3. WSLにリモート接続した状態でWindowsのVSCodeが起動する

開発に限らず、Linux上のファイルをVSCodeで編集したいときにも便利です！

## 補足2：LinuxからAzure DevOps (Server)のGitに接続する方法

Azure DevOps (Server)でGitを立てた場合、Windows環境から接続すると、Azure DevOps ServerではWindows認証、Azure DevOpsではダイアログが表示からPersonal Access Token（以下PAT）の発行まで自動的に行われます。

しかしLinux環境からの接続では、PATの発行と設定を手作業で行う必要があります。（[Azure DevOps](https://docs.microsoft.com/ja-jp/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops&tabs=preview-page)、[Azure DevOps Server](https://docs.microsoft.com/ja-jp/azure/devops/organizations/accounts/use-personal-access-tokens-to-authenticate?view=azure-devops-2020&tabs=preview-page)）

1. Azure DevOps (Server)で、PATを作成する
2. Linux環境で手順に記載のコードでPATを利用してクローンする

    ```bash
    # -- Ubuntu 20.04 on WSL2
    MY_PAT=yourPAT
    B64_PAT=$(printf ":$MY_PAT" | base64)
    git -c http.extraHeader="Authorization: Basic ${B64_PAT}" clone https://dev.azure.com/yourOrgName/yourProjectName/_git/yourRepoName
    ```

    毎回資格情報を入力する必要がないように、[資格情報マネージャー](https://github.com/microsoft/Git-Credential-Manager-Core)を導入するか、以下のコードで該当リポジトリの設定として資格情報を保存します。

    ```bash
    # -- Ubuntu 20.04 on WSL2
    cd yourRepoName
    git config http.extraHeader "Authorization: Basic ${B64_PAT}"
    ```

## 補足3：Windows側にソースコードを配置した場合

### VSCodeで開く

ソースコードをWindows側においた場合は、以下の手順でWSLをリモート接続してVSCodeで開くことができます

1. Windowsのエクスプローラーでプロジェクトフォルダに移動
2. アドレスバーに`wsl`を入力して実行し、プロジェクトフォルダに移動した状態でLinuxターミナルを開く
3. Linuxターミナルで`code .`を入力して、WSLにリモート接続しLinuxにマウントされたプロジェクトフォルダをWindowsのVSCodeで開く

### Windowsのフォルダ（`/mnt/c`など）でPythonの仮想環境作成がエラーとなる場合

Windowsのフォルダ（`/mnt/c`など）でPythonの仮想環境を作成するとエラーとなる場合は、[Windowsフォルダのマウントが正しく行われていないことがあります](https://stackoverflow.com/questions/61596003/pip3-is-unable-to-create-virtual-environment-on-ubuntu-20-04-lts-on-windows-10-b)。Linuxにて以下のコマンドを実行してマウントを再作成することで解決することがあります。

**Cドライブの場合**

```bash
# -- Ubuntu 20.04 on WSL2
cd ~
sudo umount /mnt/c
sudo mount -t drvfs C: /mnt/c -o metadata
```

## 補足4：`pyenv`でインタプリタ切り替えを行わず既定でインストールされたPython 3.8.5でvenvを使用する場合

```bash
# -- Ubuntu 20.04 on WSL2
# pip3をインストール
sudo apt install pip3 -y
# venvをインストール
sudo apt-get install python3-venv -y
# 仮想環境を作成
cd <プロジェクトフォルダ>
python3 -m venv .venv
```

## 補足5：Linux on WSL2上にDocker環境構築

以下の手順に従って設定します。
[WSL2 + Ubuntu 20.04 + Docker 開発環境構築 - Qiita - #Docker環境構築](https://qiita.com/amenoyoya/items/ca9210593395dbfc8531#docker-%E7%92%B0%E5%A2%83%E6%A7%8B%E7%AF%89)

## 補足6：会社などで独自の証明書をインストーする場合の手順

https://qiita.com/msi/items/9cb90271836386dafce3#ubuntu-1804

---

# 参考、引用元
https://qiita.com/kenchan1193/items/74edfc67910b51469b45
https://mag.nioufuku.net/2020/05/27/programming/00053-wsl2-setting/
https://gist.github.com/takurx/57342618e21b3c1afdf841956cc23da4
https://qiita.com/NahaFujii/items/a0b0f3d3515c2c185309
https://qiita.com/rhene/items/ff11c7850a9a7617c50f
https://qiita.com/imasaaki/items/25694783ae50dd66303e
https://qiita.com/Gushi_maru/items/5ba23d997e32abc98620
https://dongsu.dev/2018/08/01/other/wsl-proxy/
https://messefor.hatenablog.com/entry/2020/08/22/181519#%E5%B0%8E%E5%85%A5%E3%81%A8%E4%BD%BF%E3%81%84%E6%96%B9
https://kledgeb.blogspot.com/2020/02/ubuntu-2004-11-ubuntu-2004-ltspython2.html
https://astherier.com/blog/2020/08/how-to-terminate-wsl2/
https://qiita.com/rhene/items/ff11c7850a9a7617c50f
https://docs.microsoft.com/ja-jp/windows/wsl/use-custom-distro