Windows PCでDocker Desktopを利用せずにLinuxコンテナーとWindowsコンテナー環境を構築する方法

#はじめに
先日、[Docker Desktopの有償化](https://www.publickey1.jp/blog/21/docker_desktop250100011.html)がアナウンスされました。大規模な組織などが有償化の対象となりますので、利用されている該当組織では対応の検討・実施が必要です。中にはDocker Desktopを利用しない代替案を検討している方々もいらっしゃると思います。
本記事では、Windows PC (Windows10/11などのクライアント環境）でのDocker Desktopの代替案について、その構築手順を紹介したいと思います。特に、LinuxコンテナーをWindows PCで実行する方法だけでなく、Windowsコンテナーの環境構築についても紹介ています。
[Linuxコンテナー環境の構築](#linuxコンテナー環境構築)、[Windowsコンテナー環境の構築](#windowsコンテナー環境構築)の順に説明していますが、Windowsコンテナー環境だけを構築したい方は、[そちら](#windowsコンテナー環境構築)の手順だけを実施しても問題ありません。

#Linuxコンテナー環境構築
Widows PCでLinuxコンテナーを稼働させる方法はいくつかあると思います。最近では[Windows Subsystem for Linux (WSL)](https://docs.microsoft.com/ja-jp/windows/wsl/about)の利用が一般的になっており、Docker Desktopでもこの方法を利用できます。そこで本記事では[Docker Engine](https://docs.docker.jp/engine/index.html)をWSLの環境で利用し、Linuxコンテナー環境の構築する手順を説明していきます。

##(1)Windows PCへのWSLのインストール
Windows PCにおいて、**管理者権限**のPowershellまたはコマンドプロンプトで下記のコマンドを実行します([参考 MicrosoftのWSLインストールに関するドキュメント](https://docs.microsoft.com/ja-jp/windows/wsl/install)）。これにより、WSLに必要なWindowsの機能やLinuxのディストリビューションがインストールされます。完了には再起動が必要になります。なお、デフォルトではLinuxディストリビューションとしてubuntuがインストールされますが、変更可能です。詳細は[こちらのドキュメント](https://docs.microsoft.com/ja-jp/windows/wsl/install#change-the-default-linux-distribution-installed)を参照ください。本記事では、ubuntuを前提に続く手順を説明します。
再起動後にubuntuのコンソールが開き、最初にubuntuのユーザ名やパスワードの設定を実施します。

```powershell
wsl --install
```
##(2)WSLへのDocker Engineのインストール
WSLの構築が完了すれば、あとはDocker Engineを一般的なLinuxにインストールする手順と同様です。WSLのubuntuコンソールで、[Dockerのドキュメント](https://docs.docker.com/engine/install/ubuntu/)に記載の手順に従い、下記の手順でubuntuにDocker Engineをインストールします。

```bash
#パッケージインデックスのアップデート
sudo apt-get update

#前提ツールのインストール
sudo apt-get install \
    ca-certificates \
    curl \
    gnupg \
    lsb-release

#GPGキーの追加
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg

#Dockerのstableリポジトリの追加
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

#リポジトリ追加後のパッケージインデックスの再アップデート
sudo apt-get update

#最新バージョンのDocker Engineとコンテナランタイム(containerd)のインストール
sudo apt-get install docker-ce docker-ce-cli containerd.io
```
なお、インストールするDocker engineのバージョン指定も可能です。方法は[こちらのドキュメント](https://docs.docker.com/engine/install/ubuntu/)を参照してください。

##(3)Docker Engineの起動とコンテナーの実行
Docker Engineのインストールが完了したら、WSLのubuntuコンソールで下記のコマンドを実行してDocker Engineを起動できます。

```bash
sudo service docker start
```
ここでテスト用のコンテナーを起動してみます。下記のコマンドでテスト用のhello-worldコンテナーを実行します。（sudoを付けずに実行する方法については[後述](#補足ユーザグループ設定)します）

```bash
sudo docker run hello-world
```

上記コマンドの実行後、コンテナーが問題なく実行された場合は、下記ようなメッセージが表示されます。

```
Unable to find image 'hello-world:latest' locally
latest: Pulling from library/hello-world
2db29710123e: Pull complete
Digest: sha256:cc15c5b292d8525effc0f89cb299f1804f3a725c8d05e158653a563f15e4f685
Status: Downloaded newer image for hello-world:latest

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (amd64)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/
```
これで無事にWindows PCのWSL上にDocker Engineを用いたLinuxコンテナーの実行環境が構築できました！

##(補足)ユーザグループ設定
最後に、dockerコマンドをroot権限(sudo)ではなくユーザ権限で実行可能する方法を説明します。Docker Engineのデフォルトでは```docker```というグループが設定されていますので、こちらのグループにDocker Engineを利用したいユーザを下記のように追加します。

```bash
sudo usermod -a -G docker <ユーザ名>
```

#Windowsコンテナー環境構築
個人的にはこちらが本記事のメイントピックスです。ここからは**Windowsコンテナー**をWindows PCでネイティブに実行できるように環境構築する方法を説明します。Windowsコンテナー環境だけを構築したい方は、こちらの手順だけを実施ください。これには、Docker Engineの[バイナリーパッケージを利用したインストール](https://docs.docker.com/engine/install/binaries/#install-server-and-client-binaries-on-windows)を利用します。

##(1)Dockerバイナリーパッケージのダウンロードと展開
まず、Windows PCでPowerShellを開き、下記のコマンドで任意のフォルダーにパッケージをダウンロードし、インストール先に展開します。この記事執筆時点では最新パッケージが```docker-20.10.11.zip```でしたので、そちらを利用しています。もちろんブラウザーで[バイナリーパッケージのページ](https://download.docker.com/win/static/stable/x86_64/)を開いてダウンロードし、エクスプローラーで展開しても問題ありません。

```powershell
#バイナリーパッケージのダウンロード（ダウンロードするフォルダで実行）
curl.exe -O https://download.docker.com/win/static/stable/x86_64/docker-20.10.11.zip

#パッケージのインストール先への展開（この例ではC:\dockerというフォルダー名に展開されます）
Expand-Archive docker-20.10.11.zip -DestinationPath C:\
```
上記手順の結果、インストール先に実行ファイルが展開されるので、環境変数のPathを設定します。下図の例ではWindowsのスタートメニューから「システム環境変数の編集」を検索して開き、環境変数の設定ウインドウでシステム環境変数の```Path```に、今回Dockerをインストールした```C:\docker```を追加しています。

![Pathの設定](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/0c4fa410-461a-3f31-d0f2-38d1800740bf.png)

##(2)Windowsのコンテナー機能の有効化
Windowsコンテナー実行の前提となる、Windowsのコンテナー機能を有効化します。これには、スタートメニューから「Windowsの機能の有効化または無効化」を検索して開き、「コンテナー」のチェックをオンにしてOKボタンをクリックします。
<img width="300" alt="スクリーンショット 2021-12-05 17.23.09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/255074/7b1581a0-36b5-2803-b902-c1c526672c10.png">

##(3)Docker Engineの起動
インストールされた```dockerd.exe```をバックグラウンドで起動します。**管理者権限**でPowerShellを起動し、下記のコマンドを実行します。新しいウインドウが開き、dockerdの実行の様子が表示されます。

```powershell
Start dockerd
```
なお、このDocker EngineをWindowsのサービスとして起動可能です。下記コマンドのように、dockerdの```--register-service```オプションを指定することで、Docker EngineがWindowsのサービスに登録され、起動できます。これによりWindows起動時にも自動起動されます。

```powershell
#WindowsサービスにDocker Engineを登録
dockerd --register-service

#Docker Engineサービスの起動
Start-Service docker
```

##(4)Windowsコンテナーの実行
Windowsコンテナーの実行に関しては、まずWindowsコンテナーは2種類の[分離モード](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/manage-containers/hyperv-container)が存在することに注意が必要です。これによって利用できる[コンテナーイメージの互換性](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10-21H1#windows-client-host-os-compatibility)が異なります。Docker Engineのデフォルトでは、分離にHyper-Vを利用するモードが設定されていますが、利用環境のWindows PCで[Hyper-Vの機能が有効化](https://docs.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/quick-start/enable-hyper-v)されている必要があります。一方、プロセス分離モードを利用する場合、dockerコマンドの```--isolation```オプションで明確に指定するか、デフォルト設定を変更([後述](#補足windowsコンテナー実行環境のデフォルト分離モードユーザーグループ設定)）する必要があります。
どちらのモードで利用するかはコンテナーの実行要件に依存します。特に、Windowsを実行する環境が仮想化をサポートしていない場合（例えば仮想サーバ上で稼働しているが[入れ子になった仮想化](https://docs.microsoft.com/ja-jp/virtualization/hyper-v-on-windows/user-guide/nested-virtualization)をサポートしていない場合）や、組織のポリシー等でHyper-Vの有効化ができない環境の場合には、プロセス分離モードを選択することになります。

Hyper-V分離の場合は、dockerコマンドを用いてそのままコンテナーを実行します。一方、プロセス分離の場合は、```--isolation=process```を指定して実行し、さらに[ホストOSのバージョンと互換性があるベースコンテナーイメージ](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/deploy-containers/version-compatibility?tabs=windows-server-2022%2Cwindows-10-21H1#windows-client-host-os-compatibility)を選択する必要があります。

```powershell
#Hyper-V分離の場合
docker run --rm -it mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd.exe

#プロセス分離の場合(この例ではWindows11バージョン21H2環境で実行しているため、ltsc2022のタグのコンテナーイメージを利用）
docker run --isolation=process --rm -it mcr.microsoft.com/windows/nanoserver:ltsc2022 cmd.exe
```
どちらも、実行後に下記のようなコンテナー内部のコマンドコンソールが表示されれば無事にコンテナーが実行されています。exitコマンドでコンテナーを終了します。

```
Microsoft Windows [Version 10.0.22000.350]
(c) Microsoft Corporation. All rights reserved.

C:\>
```
これで無事にWindows PCでのWindowsコンテナーの実行環境が構築できました！

##(補足)Windowsコンテナー実行環境のデフォルト分離モード・ユーザーグループ設定
ここでは、Windowsコンテナーのデフォルト分離モード、およびユーザグループの設定について補足します。前述の通り分離モードはデフォルトでHyper-Vが指定されていますので、プロセス分離を利用する場合はコンテナー実行時に毎回オプションを指定する必要があります。また、デフォルトの状態では、dockerコマンドを実行するには管理者権限のコンソールを利用する必要があります。これらはDocker Engineの設定により変更できます。
Docker Engineの設定の方法として、```dockerd.exe```のオプションとして指定する方法と、構成ファイルを利用する方法があります。構成ファイルについては[Microsoftのドキュメント](https://docs.microsoft.com/ja-jp/virtualization/windowscontainers/manage-docker/configure-docker-daemon#configure-docker-with-a-configuration-file)に詳しい説明がありますので、こちらを参照ください。ここでは、dockerd.exeのオプションを利用して簡単に設定する方法について紹介します。
dockerd.exeのオプションのうち、分離モードの指定オプションは```--exec-opt```です。また、ユーザーグループを設定するオプションは```-G```もしくは```--group```です。Windowsのユーザーグループを作成しておき、このオプションで当該ユーザーグループ名を指定することで、当該ユーザーグループに登録されたユーザーは、管理者権限のコンソールを開くことなくコンテナー実行環境を利用できます。これをdockerdの起動時やサービスの登録時に指定することで、簡単に指定できます。下記にサービス登録時のオプション指定方法の例を示します。

```PowerShell
#分離モードをプロセス分離に設定し、ユーザーグループを設定してWindowsサービスに登録
dockerd --register-service --exec-opt "isolation=process" -G <ユーザーグループ名>
```

#[参考]クラウドを用いたコンテナーのビルドと簡単な検証
もし、コンテナーのビルド環境としてDocker Desktopを主に利用し、コンテナーの実行は簡単な検証のみに利用していた場合には、別の代替案があります。
Azureのプライベートなコンテナーレジストリーである[Azure Container Registry](https://azure.microsoft.com/ja-jp/services/container-registry/)では、コンテナーのビルドや簡単な検証を実施できる機能があります。詳細はここでは説明しませんが、興味のある方は[こちらのMicrosoftドキュメント](https://docs.microsoft.com/ja-jp/azure/container-registry/container-registry-quickstart-task-cli)を参照ください。もちろん[LinuxコンテナーだけでなくWindowsコンテナーのビルドや実行テストにも対応](https://docs.microsoft.com/ja-jp/azure/container-registry/container-registry-tasks-overview#image-platforms)しています。[Azureのサブスクリプション](https://azure.microsoft.com/ja-jp/free/)とAzure Container Registryの準備は必要ですが、Windows PCなどのクライアント環境では、Azureのコマンドラインツールである[Azure CLI](https://docs.microsoft.com/ja-jp/cli/azure/install-azure-cli)さえインストールされていれば利用することができます。
例えば、Dockerfileやソースコードなどが存在するフォルダで下記のコマンドを実行すれば、コンテナーをビルドしてAzure Container Registryにプッシュする動作が実行されます。

```powershell
#Linuxコンテナーのビルドとレジストリーへのプッシュ
az acr build --image <イメージ名・タグ> --registry <レジストリ名> .

#Windowsコンテナーのビルドとレジストリーへのプッシュ(--platformオプションでWindowsを指定)
az acr build --image <イメージ名・タグ> --registry <レジストリ名> --platform windows/amd64 .
```

#さいごに
本記事では、Windows PCのLinuxコンテナーおよびWindowsコンテナーの環境をDocker Desktopを利用せずに、Docker Engineを利用して構築する方法についてご紹介しました。しかし、Docker Desktopには様々な追加機能があり、Docker Engineに比べで[様々な利点](https://matsuand.github.io/docs.docker.jp.onthefly/desktop/)があります。それらを利用したい場合には、やはりDocker Desktopの利用継続を検討すべきと思います。また、ここでご紹介した方法以外にも、[podman](https://podman.io/)などさまざまな別の方法もあります。さらに同様のテーマの記事も多数ありますので、そちらもぜひ参照して、ご自身に合った方法を検討ください。個人的には、Windowsコンテナー環境の構築に関する情報は、もっと広がるべきと思っています。
本記事がコンテナーを日々活用されている皆様の参考意見の１つとなり、少しでも助力になれば幸いです！