セットアップ - Docker on WSL 2 + Windows ターミナル


はじめに

セットアップ シリーズ、Windows 10 向け Docker 編。
macOS なら Docker Desktop をインストールするだけで良いが、WSL に依存する Windows だとそうもいかない。

便利なので、WSL のついでに Windows ターミナルも紹介する。

確認環境:

  • Windows 10 Home バージョン 20H2(ビルド 19042)
  • Windows 10 Home バージョン 20H1(2004、ビルド 19041)

WSL とは?

公式サイトでは、WSL(Windows Subsystem for Linux)を以下のように説明している。

WSL の対象ユーザーは誰ですか。

これは、主に開発者向けのツールです。
特に Web 開発者と、オープン ソース プロジェクトで作業している開発者が対象です。
これにより、Bash、一般的な Linux ツール (sed、 awk など)、および多くの Linux ファースト ツール (Ruby、Python など) を使用する必要があるユーザーは、Windows でそれらのツールチェーンを使用できます。

WSL ですべての Linux アプリを実行できますか。

いいえ。 WSL は、Bash およびコア Linux コマンド ライン ツールを必要とするユーザーが Windows 上でそれらを実行できるようにすることを目的としたツールです。
WSL は、GUI デスクトップやアプリケーション (例: Gnome、KDE など) をサポートすることを目的としていません。更新については、コマンドラインのブログを参照してください。
また、多くの一般的なサーバー アプリケーション (Redis など) を実行できる場合でも、実稼働サービスをホストする目的には WSL をお勧めしません。
Microsoft は、Azure、Hyper-V、Docker で実稼働 Linux ワークロードを実行するためのさまざまなソリューションを提供しています。

もう少し細かい話:

  • WSL は、従来の「仮想マシン」や「デュアルブート」よりも軽量に、「Windows 環境」と「GNU/Linux 環境」を併用できる仕組み。
  • WSL はただの仮想マシンではなく、Linux と Windows との併用を前提としている。
  • 今では「WSL 1」と呼ばれる初代から進化して、本物の Linux カーネルを直接実行する「WSL 2」ができた。

WSL 2 の詳細:

  • Windows 10 バージョン 2004(20H1)で正式リリースされた。
    • 開発中のプレビュー版を利用する Windows Insider Program への参加が不要に。
  • Windows 10 に Linux カーネルが含まれており、マシン上では「Windows カーネル」と「Linux カーネル」が並行稼働する。
  • Linux 側のファイルシステムは仮想ディスクを使う。
    • そのためルート配下は Linux の支配下で、パスには Windows の禁則文字も使えるが、Linux にマウントされた Windows 上のファイルシステムは Windows の規則に従う。
    • WSL 1 と比べ、WSL 2 は Windows ファイルシステムへのアクセスが低速なため、Linux 側のファイルシステムと往復する場合は WSL 1 の利用が推奨される。
  • その他、「WSL 1」と「WSL 2」の細かい違いは以下。

Docker とは?

  • Docker 社が提供する、あらゆるアプリケーションをどこでも開発・導入・実行するためのプラットフォーム。
    • 正確には、Linux ファイルシステムのスナップショットを Docker イメージとしてパッケージ化し、コンテナーとして動かす。
      • イメージは、Dockerfile(テキストファイル)上の命令文から簡単に作成できる。各命令文がレイヤーとして積み重なってイメージを作る。
      • コンテナーは、読み取り専用レイヤーのみで構成されるイメージに、書込み可能な最上位レイヤーが追加されたもの。
    • コンテナーはホスト上のプロセス ツリーから独立したプロセスで、自身のファイルシステムとネットワークを持つ。
  • WSL 2 の登場以降、Docker Desktop はデフォルトでは「WSL 2 VM」上で以下の 2 つのディストリビューションを動作させる方式が採用された。
    • docker-desktop: ブートストラップ ディストリビューション
      • Docker エンジン本体
    • docker-desktop-data: データ ストア ディストリビューション
      • Docker イメージやコンテナーを格納
      • WSL 2 は、現時点では追加の仮想ディスク(VHD)を直接マウントできないため、クロス ディストリビューション マウントする方式になったそうだ
  • Windows 用 Docker のバックエンドが「WSL 2」の場合と、それ以前の「Hyper-V」の場合の違いは以下。

Windows ターミナルとは?

  • Microsoft 社の提供する、ターミナル アプリケーション。
  • コマンド プロンプト、PowerShell、WSL などの各種コマンドライン ツールを横断的に扱うことができる。
  • 今回は、Ubuntu(WSL)を利用するための使う。

👑 WSL 2

cf.Windows Subsystem for Linux (WSL) を Windows 10 にインストールする | Microsoft Docs

システム要件:

この手順は x64 マシンを想定する。

インストール方法の違い:

WSL は、現在ふたつのインストール方法がある。

  • ➊ 簡略化されたインストール
    • Windows Insider Program に参加して、Windows 10 のプレビュー ビルド(OS ビルド 20262 以降)を使う
  • ➋ 手動インストール
    • Windows Insider Program に参加していない場合用

プレビュー版の Windows が使いたいわけではないので、「➋ 手動インストール」の方法を採用する。

インストール:

公式の手順どおり。悩む点はない。

# 管理者として PowerShell を開く

# Linux 用 Windows サブシステムを有効にする
PS C:\> dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

# 仮想マシン プラットフォーム オプション機能を有効にする
PS C:\> dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# 以下のパッケージをダウンロードし、インストール
# x64 マシン用 WSL2 Linux カーネル更新プログラム パッケージ
# https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi

# WSL 2 を既定のバージョンとして設定(デフォルトでは WSL 1 を使わないように)
PS C:\> wsl --set-default-version 2

設定: メモリ枯渇問題への対策

メモ帳などの任意のテキストエディターで %USERPROFILE%\.wslconfigC:\Users\<yourUserName>\.wslconfig) に、以下のファイルを作成する。
(この機能は Windows 10 ビルド 19041 以降でしか使えない。)

.wslconfig
[wsl2]
memory=8GB

この手順では、上記の設定反映の手順は不要。(この時点で WSL 2 VM が起動してないので)

もし稼働中の WSL 2 VM があれば再起動することで適用される(wsl --shutdown or wsl -t <ディストリビューション名>)。面倒なら Windows を再起動でも良い。

(以下、細かいことが気になる方向け)

  • 現時点の WSL 2 でも、残念ながら「メモリを食いつぶす問題」は残っているらしい。
    • たしかに Vmmem プロセス(WSL 2 VM 全体のプロセス?)のメモリー使用率は高いので気になる。
  • GitHub 上の Issues のアドバイスにしたがって、WSL のグローバルオプション設定である .wslconfig を作成し、WSL 2 VM が確保するメモリー上限を設定している。
  • 公式サイトによれば、デフォルトのままだと PC 搭載メモリーの 80 % が上限となるそうなので、もっと安全な値に変更している。
    • Windows 10 ビルド 20175 以降(プレビュー版)なら、デフォルトは搭載メモリーの 50 % or 8 GB の少ない方が上限となり、この変更をする必要はない。
    • 今回は「ビルド 20175 以降の仕様」を参考に、とりあえず 8 GB にする。
  • 上記 Qiita の参考記事では swap=0 でスワップの無効化を設定しているが、後述のとおり利用するドライブを SSD から HDD へ変更するので、今回の手順では不要。

補足:

cf. Linux ディストリビューションの管理 | Microsoft Docs

ディストリビューションごとの起動設定は、各ディストリビューション内の /etc/wsl.conf を参照する。
たとえば [interop] セクションの appendWindowsPathfalse にすることで、WSL が Windows パス要素を $PATH 環境変数に追加しないようにできる。
今回は特に困らなかったので、設定しない。

👑 Ubuntu(WSL)

WSL VM 上に、Linux ディストリビューションをインストールする。

Docker を使う上では必須ではないが、WSL を試す際には何かと必要になる。
(Linux ディストリビューションがひとつもインストールされていないとエラーになったりして後々面倒なことも。)

こだわりはないが、WSL は Ubuntu の開発元の Canonical 社との連携で生まれたようなので、相性の良さそうな「Ubuntu」を採用。

なお、Windows ストア上の「Alpine Linux」は、開発元(Alpine Linux development team)が公開しているわけではなさそうなので、採用を見送り。

インストール:

利用可能な Ubuntu のリリースは以下で確認できる。
https://wiki.ubuntu.com/WSL#Ubuntu_on_WSL

Windows ストアへのリンクがあるので、そこからインストール。

各 LTS もあるが、今回はアプリ名に「リリースバージョンなし」の常に推奨リリースを使うものを採用。
(現在は「Ubuntu 20.04 LTS」がインストールされる。)

念の為にインストールしたディストリビューションを確認しておく。

# WSL にインストールされているディストリビューションとその詳細を確認
## --list, -l     ディストリビューションの一覧を表示します。
## --verbose, -v  すべてのディストリビューションについての詳細情報を表示します。
PS C:> wsl -l -v
  NAME                   STATE           VERSION
* Ubuntu                 Stopped         2

# バージョンが 2 なら、WSL 2 で動作している

# デフォルトのディストリビューションを変更する場合は以下
# wsl --set-default <ディストリビューション名>

# すでに WSL 1 で動作しているディストリビューションを WSL 2 へ移行するには以下(逆もできる)
# wsl --set-version <ディストリビューション名> 2

使い方:

Windows ストアからインストール後、「Ubuntu」を起動すると、Ubuntu が構築 & 起動するまでしばらく待たされる。
起動後、Linux ユーザー名とパスワードを設定を促されるので入力。(パスワードはスーパーユーザーへの昇格時に必要となるなので忘れないように。)

exit コマンドで終了。

なお、WSL 上では poweroffreboot コマンドは制限されており、利用できない。
(おそらく、WLS はひとつのハードウェア上で Windows と Linux を併用するので、何をシャットダウンするコマンドか分かりにくいため?)

どうしてもディストリビューション(WSL 2 VM)を停止させたい場合は、PowerShell などから wsl -t <ディストリビューション名> コマンドを使う。

設定:

cf. Docker のイメージ&コンテナの配置フォルダを変更 - Qiita

WSL 2 VM のディスクは「仮想ディスク」(.vhdx)形式で保持される。

デフォルトの保存先は %LocalAppData%C:\Users\<yourUserName>\AppData\Local)配下のため、C ドライブが SSD の場合はよろしくない。
cf. SSD の選び方(3/5):SSD の寿命を縮める使いかた - Qiita

Windows ストアから取得したディストリビューションの仮想ディスクの保存先は、以下の方法で確認できる。

# cf. [Windows Subsystem for Linux 2(WSL 2)をセットアップしてみた | Developers.IO](https://dev.classmethod.jp/articles/how-to-setup-wsl2/)

# PackageFamilyName を取得
PS C:> $packageName = Get-AppxPackage -Name "*Ubuntu*" | Select-Object -ExpandProperty PackageFamilyName
PS C:> $packageName

# 対象フォルダーを確認
PS C:> dir "$env:LOCALAPPDATA\Packages\$packageName\LocalState\"

仮想ディスクを「別のドライブ」へ移行する手順は以下のとおり。
今回は HDD の D ドライブがあるのでそこに。

# 利用中の WSL 2 VM があれば切断する

# 稼働中の WSL 2 VM を確認
PS C:> wsl -l -v

# 稼働中のものがあれば、以下のコマンドですべて終了させる
PS C:> wsl --shutdown

# vhdx を tar としてエクスポート、登録解除、tar をインポート
PS C:> cd D:\
PS D:> wsl --export <ディストリビューション名> <ディストリビューション名>.tar
PS D:> wsl --unregister <ディストリビューション名>
PS D:> wsl --import <ディストリビューション名> <インストール先パス> D:\<ディストリビューション名>.tar

# 例:
# wsl --export Ubuntu Ubuntu.tar
# wsl --unregister Ubuntu
# wsl --import Ubuntu D:\wsl\Ubuntu D:\Ubuntu.tar

# 複数の WSL 2 VM がある場合は、上記手順を繰り返す

# WSL 2 VM を再確認
PS D:> wsl -l -v

# デフォルトのディストリビューションが変更されている場合は、以下のコマンドで再指定
PS D:> wsl --set-default <ディストリビューション名>

zsh、tmux について

👑 Windows ターミナル

cf. Windows ターミナルのインストール | Microsoft Docs

インストール:

Windows ストアからインストールするだけ。
https://aka.ms/terminal

設定:

起動時に「Ubuntu (WSL)」を開くなど、設定を調整する。

  1. Windows ターミナルを起動する。
  2. 設定 (Ctrl + ,) を開き、既定のプロファイルUbuntu に変更 > 保存 ボタンをクリック。
  3. 画面左のサイドバーの ボタン > Ubuntu > 外観 タブで、以下を設定して 保存 ボタンをクリック。
  4. 画面左のサイドバーの ボタン > Azure Cloud Shell > ドロップダウンからプロファイルを非表示にする を有効に > 保存 ボタンをクリック。
    • 更に、Azure Cloud Shell を使う予定がないので、非表示に。

👑 Docker Desktop

cf. Install Docker Desktop on Windows | Docker Documentation

やっと Docker Desktop のセットアップに入る。
(Docker Engine、Docker CLI client、Docker Compose、Notary、Kubernetes、Credential Helper が含まれる)

システム要件:

インストール:

インストーラーは以下から入手。
cf. Docker Desktop for Mac and Windows | Docker

  1. Docker Desktop Installer.exe を実行する。
  2. Install required Windows components for WSL 2(WSL 2 に必要な Windows コンポーネントをインストール)にチェックが入っていることを確認する。
  3. インストーラーに促されるまま OS 再起動後する。
  4. Docker Desktop が再起動するので、しばらく待つ。 (タスクトレイのクジラのアイコンのアニメーションが止まるまで数分かかった)
  5. タスクトレイから Docker Desktop の画面を表示すると、チュートリアルが開始される。 (別に初学者に優しいチュートリアルでもないなので、ファイアウォールで通信をあらかじめ許可することが主な役割だと割り切ってスキップしても良い
# 一応、チュートリアル内容について説明する。

# alpine/git の Docker イメージを取得 & コンテナーとして起動し、コンテナー内で clone コマンドを実行
## --name オプションで、「コンテナー名」を割り当て
## cf. alpine/git <https://hub.docker.com/r/alpine/git>
$ docker run --name repo alpine/git clone https://github.com/docker/getting-stared.git

# コンテナー内の clone したリポジトリーを、ホストのカレントディレクトリーへコピー
$ docker cp repo:/git/getting-started/ .

# コピーしたフォルダーへ移動
$ cd getting-started

# コピーしたフォルダー内の Dockerfile を元に、「docker101tutorial」というイメージ名で Docker イメージを作成
## -t オプションで、「イメージ名」を割り当て(タグを省略したため、自動的に latest に)
$ docker build -t docker101tutorial .

# 作成した Docker イメージ「docker101tutorial」をコンテナーとして起動
## -d オプションで、バックグラウンド実行
## -p <ホスト側のポート>:<コンテナー側のポート> で、ホストとコンテナー間のポートフォワード設定(デフォルトだと、コンテナー内と通信できないため)
## --name オプションで、「コンテナー名」を割り当て
$ docker run -d -p 80:80 --name docker-tutorial docker101tutorial
  1. Windows Defender ファイアウォールなどが Docker をブロックするので、許可する。
  2. この後の You must be signed in to Docker Hub to share your image. Sign in here. 以降は、 Docker Hub の案内なので無視しても良い。(Docker イメージを公開する予定がなければ関係ないし、あとでもできる)
  3. チュートリアルの最後に、docker101tutorial のコンテナー内の Web サーバー上のページが表示される。(http://localhost/tutorial/
  4. 確認が終われば Docker Desktop の GUI から docker101tutorial コンテナーを停止させる。

確認:

# WSL にインストールされているディストリビューションとその詳細を確認
## --list, -l     ディストリビューションの一覧を表示します。
## --verbose, -v  すべてのディストリビューションについての詳細情報を表示します。
PS C:\Users\user> wsl -l -v
  NAME                   STATE           VERSION
  docker-desktop-data    Running         2
  docker-desktop         Running         2

# バージョンが 2 なら、WSL 2 で動作している

追加設定:

cf. WSL2 Docker のイメージ・コンテナの格納先を変更したい (WSL2 の vhdx ファイルを移動させたい) - Qiita

Docker の使う WSL 2 VM の仮想ディスク(VHD)のドライブを変更する手順は、以下のとおり。
(SSD の寿命問題への対策。手順は上記の Ubuntu のものと同じ)

  • 参考: デフォルトの仮想ディスクの格納先パス
    • docker-desktop: %LocalAppData%\Docker\wsl\data\ext4.vhdx
    • docker-desktop-data: %LocalAppData%\Docker\wsl\distro\ext4.vhdx
# タスクトレイのクジラのアイコンを右クリック > Quit Docker Desktop

# その他に利用中の WSL 2 VM があれば切断する

# 稼働中の WSL 2 VM を確認
PS C:> wsl -l -v

# 稼働中のものがあれば、以下のコマンドですべて終了させる
PS C:> wsl --shutdown

# vhdx を tar としてエクスポート、登録解除、tar をインポート
PS C:> cd D:\
PS C:> wsl --export <ディストリビューション名> <ディストリビューション名>.tar
PS C:> wsl --unregister <ディストリビューション名>
PS C:> wsl --import <ディストリビューション名> <インストール先パス> D:\<ディストリビューション名>.tar

# 例:
# wsl --export docker-desktop docker-desktop.tar
# wsl --unregister docker-desktop
# wsl --import docker-desktop D:\wsl\docker-desktop D:\doc\docker-desktop.tar
#
# wsl --export docker-desktop-data docker-desktop-data.tar
# wsl --unregister docker-desktop-data
# wsl --import docker-desktop-data D:\wsl\docker-desktop-data D:\doc\docker-desktop-data.tar

# WSL 2 VM を再確認
PS C:> wsl -l -v

# デフォルトのディストリビューションが変更されている場合は、以下のコマンドで再指定
PS C:> wsl --set-default <ディストリビューション名>