Docker Desktopに依存しない、WindowsでのDocker環境

もろもろの事情でDocker Desktopを使いたくなくなったため、Docker Desktop for Windows無しに、似たようなDocker環境をWindowsに構築する手順を確認しました。

**(2021-09-05追記)** 私はWSL2をDocker以外の目的で使用していないので気にしませんが、他の目的にも使っているという方は [「(おまけ) Docker用のディストリビューションを分ける」](#5-%E3%81%8A%E3%81%BE%E3%81%91-docker%E7%94%A8%E3%81%AE%E3%83%87%E3%82%A3%E3%82%B9%E3%83%88%E3%83%AA%E3%83%93%E3%83%A5%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%82%92%E5%88%86%E3%81%91%E3%82%8B) を先に参照したほうが良いかもしれません。

**(2022-01-29追記)** Visual Studio Code (VSCode) に、WSL環境内の `docker` コマンドを直接使用できるオプションが追加されました。この機能を有効にすると、VSCodeからコンテナを使用するために一旦WSLに接続したり、Windows側にDocker CLIをインストールしたり、というステップが不要になります。詳細は [(おまけ2) VSCodeからWSL上のdockerコマンドを直接使用する](#7-%E3%81%8A%E3%81%BE%E3%81%912-vscode%E3%81%8B%E3%82%89wsl%E4%B8%8A%E3%81%AEdocker%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B) を参照してください。


## 1. Dockerのインストール

WSL2のディストリビューション上にDockerをインストールします。

### WSL2にUbuntu 20.04のディストリビューションを導入

以下の「手動インストールの手順」そのままです。

https://docs.microsoft.com/ja-jp/windows/wsl/install-win10#manual-installation-steps

ディストリビューションとして `Ubuntu 20.04 LTS` をインストールします。

以降の手順は、特に記載がない限りこのWSLディストリビューション内で行います。

### Ubuntu上にDocker Engineをインストール

以下の `Install using the repository` の手順そのままです。

https://docs.docker.com/engine/install/ubuntu/#install-using-the-repository

書かれているコマンドを上から実行していけばOKですが、以下の部分は不要です。

- `Install Docker Engine` の `2. To install a specific version of Docker Engine, ...` の部分（最新以外のバージョンをインストールしたい場合の手順なので）
- 最後の `Verify that Docker Engine is installed correctly ...` の部分（この時点ではまだ動きません）

### 一般ユーザーへの権限付与

WSLで使う一般ユーザーから `docker` コマンドが使用できるようにするため、以下のコマンドでWSL用ユーザーを `docker` グループに所属させます。

```
sudo usermod -aG docker $USER
```

### Docker Daemonの起動・自動起動の設定

WSLにインストールした場合、Docker Daemon は自動的に起動しないので、以下のコマンドで手動起動します。

```
sudo /etc/init.d/docker start
```

また、WSLで使うユーザーの `.bashrc` に以下を追記しておくと、ディストリビューションが再起動された後も、一度 `wsl` コマンドで接続するだけで自動的に起動できます。

```bash
# Start dockerd
sudo /etc/init.d/docker start
```

このときパスワードを聞かれるのが煩わしい場合は、以下のコマンドを実行し、`sudoers` ファイルを編集します。

```bash
sudo visudo
```

nanoエディタが起動するので、末尾に以下を追加した後、 `Ctrl+X` -> `Y` -> `Enter` で保存・終了します。

```
%docker ALL=(ALL)  NOPASSWD: /etc/init.d/docker
```

これにより、上記の起動コマンドを実行した場合だけはパスワードが不要になります。

### 動作確認

以下のように Hello World イメージを実行します。

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

`Hello from Docker!` と表示されれば正しくインストールできています。

## 2. Docker Compose (v1) のインストール

Visual Studio Code の Remote Containers 拡張では `docker-compose` コマンドも必要になるため[^1]、インストールします。以下の `Install Compose on Linux systems` の手順そのままです。

https://docs.docker.com/compose/install/#install-compose-on-linux-systems

[^1]: Remote Containersの設定 `Docker Compose Path` (`remote.containers.dockerComposePath`) を `docker compose` に設定すれば v2 でも動作する可能性はありますが、未検証です。

## 3. Dockerコマンドの利用

今後の `docker` コマンドの実行は、 `wsl` コマンドでいったんLinuxに入ってから行うようにします。

ただし、Docker Desktop for WindowsのようにWindowsのパスをそのまま使用はできないので、 `-f C:\src\test\Dockerfile` のようにパスが出てくる個所は、 `-f /mnt/c/src/test/Dockerfile` のようにLinux側からみたパスに置き換える必要があります。

### 追加情報

以下にあるようにバッチやPowerShellスクリプトを作成することで、Windowsから `docker` コマンドをそのまま実行できるようにすることもできます。

https://dev.to/bowmanjd/install-docker-on-windows-wsl-without-docker-desktop-34m9

ただし、上記のパスの問題や、 `--mount` オプションのようなカンマ区切りパラメータの問題（PowerShellではエスケープが必要）もあり、バッチやPowerShellだけではDocker Desktopと全く同じ動作にするのは厳しそうです。


## 4. Visual Studio Code からの利用

**(2022-01-29追記)** Visual Studio Code v1.61から、この操作は不要になりました。詳細は[おまけ2](#7-%E3%81%8A%E3%81%BE%E3%81%912-vscode%E3%81%8B%E3%82%89wsl%E4%B8%8A%E3%81%AEdocker%E3%82%B3%E3%83%9E%E3%83%B3%E3%83%89%E3%82%92%E7%9B%B4%E6%8E%A5%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B)を参照ください。

Windowsから起動したVisual Studio Codeでは、Docker DesktopのようにRemote Containers拡張の機能をそのまま使用することはできません。

WSL内から

```bash
# カレントディレクトリを開く
code .
```

のようにVisual Studio Codeを起動し、WSLに接続された状態にする必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/4caa4b83-c4a5-78a1-b326-baf7d15f1cec.png)

接続した後は、Docker Desktop の場合と同じように `Open Folder in Container...` などのメニューが動作するようになります。

### 参考情報

https://code.visualstudio.com/docs/remote/wsl

https://github.com/microsoft/vscode-remote-release/issues/3534

https://github.com/microsoft/vscode-remote-release/issues/2994

## 5. ダッシュボードの代替

Docker DesktopのダッシュボードのようにGUIでのDocker環境管理を行いたい場合、[Portainer](https://portainer.io/)を使用するのが簡単そうです。

### インストール

以下のドキュメントページを

https://docs.portainer.io/

以下のようにたどり[^2]、

- `Portainer Community Edition`
- `Install Portainer CE`
- `Set up a new Portainer Server installation`
- `Docker Standalone`
- `Install Portainer with Docker on WSL / Docker Desktop`

`Deployment` に記載のコマンドをWSL内から実行すればインストールは完了します。

[^2]: 最新バージョンを指せるURLがないため、このようなまわりくどい書き方になってしまっています。

起動したら、ブラウザから https://localhost:9443 にアクセスすると（ブラウザで自己署名証明書を受け入れる必要があります）、初期ユーザー登録画面になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/b6336828-fc01-7e1b-5d6f-0d8519ec2dc3.png)

適当なパスワードで `Create user` ボタンで登録します。

次の画面では、local environment を使う方 (Get Started) を選択します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/100ba48a-8194-0272-997b-13dfe803ca13.png)

`local` がWSL内のDocker環境を表しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/13e33c74-d765-c7c8-31bc-fd14e0fa6511.png)

この中を確認すると、Docker Desktop のダッシュボードで提供されているようなコンテナ・イメージ・ボリュームなどの状況の確認や操作ができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/e7c61297-c87a-48b2-42f5-665db29cb135.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/66ce9c4b-ca46-8ce3-2398-62cdbae31dbd.png)

ログの確認やコンソールアクセスなども可能です。

## 6. (おまけ) Docker用のディストリビューションを分ける

Ubuntuのディストリビューションを別の目的で使っていて、Docker環境に汚染されたくない、ディスク肥大化時に消したりできないのが気になる、という場合は、ディストリビューションを分けたほうが良いでしょう。

### Docker用のディストリビューション作成

Windows上で、以下のようなコマンドで既存のディストリビューションをエクスポートします。 `D:\backup\Ubuntu-20.04.tar` の部分はエクスポート先の任意のパスです。

```powershell
wsl --export "Ubuntu-20.04" D:\backup\Ubuntu-20.04.tar
```

続けて、以下のようなコマンドで新しいディストリビューションとしてインポートします。 

```powershell
wsl --import docker D:\wsl\docker D:\backup\Ubuntu-20.04.tar
```
- `docker` の部分は、新しいディストリビューションに付ける名前です。
- `D:\wsl\docker` の部分は、新しいディストリビューション用のディスクイメージを配置したいフォルダです。
- 最後のパラメータは、さきほどエクスポートしたファイルのパスです。

この後、以下のコマンドでディストリビューションの一覧を確認すると、インポートしたものが追加されています。

```powershell
wsl -l -v
```

結果:

```
  NAME            STATE           VERSION
* Ubuntu-20.04    Stopped         2
  docker          Stopped         2
```

これで、以下のコマンドのように新しいディストリビューションを指定してWSLを起動できるようになります。

```powershell
wsl -d docker
```

### デフォルトユーザーの変更

インポートしたディストリビューションでは、上記のように起動するとデフォルトユーザーが `root` になっているので、元のユーザーと同じになるようにします。

まず、以下のコマンドで元のディストリビューションのデフォルトユーザーのUIDを確認します（おそらく `1000` のはず）。

```powershell
wsl -d "Ubuntu-20.04" id -u
```

確認できたら、PowerShellで以下のコマンドを実行します。

```powershell
# さっき確認したUID
$uid = 1000
# 新しいディストリビューションの名前
$to_dist = 'docker'
Get-ItemProperty Registry::HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Lxss\*\ DistributionName | Where-Object -Property DistributionName -eq $to_dist | Set-ItemProperty -Name DefaultUid -Value $uid
```

これは、ディストリビューション用のレジストリの `DefaultUid` を設定しているのと同じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/714ab81b-4a39-63d7-ffac-28ed64e262ec.png)

この後は、以下のコマンドで一般ユーザーとして新しいディストリビューションを起動できます。

```powershell
wsl -d docker
```

### この後

あとは、このディストリビューションの中で 1～4 の手順と同様にDocker環境を構築していきます。

ディスクが肥大化したりしてディストリビューションを消したくなったら、以下のようなコマンドで消せます。

```powershell
wsl --unregister docker
````

## 7. (おまけ2) VSCodeからWSL上のdockerコマンドを直接使用する

VSCodeのv1.61で、VSCodeがDocker機能を呼び出すときにWSL上の `docker` コマンドを使うようにするオプションが追加されました。

VSCodeで以下のオプション "Execute In WSL" (`remote.containers.executeInWSL`) にチェックを入れて有効にすると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/ea91e739-467f-2ade-3bf3-06025ab4d92c.png)

`Open Folder in Container` などでRemote Containers拡張がdockerコマンドを実行するときに、自動的にWSL内のDockerで実行してくれるようになります。

これにより、WSL上だけにDockerをインストールすれば、（VSCodeの操作の上では）Docker Desktopと全く同じ感覚で Remote Containers を使えるようになりました。

ログを見ると、以下のようにwsl上でコマンドを実行し、パスも自動的に変換してくれています。

```
[55 ms] Remote-Containers 0.209.6 in VS Code 1.63.2 (899d46d82c4c95423fb7e10e68eba52050e30ba3).
[54 ms] Start: Resolving Remote
[60 ms] Start: Run: wsl -l -v
[91 ms] Start: Run: wsl -d docker -e wslpath -u d:\src\sandbox
[162 ms] Start: Run: wsl -d docker -e /bin/sh -c cd '/mnt/d/src/sandbox' && /bin/sh
```

VSCode v1.64 以降では、設定 "Execute In WSLDistro" (`remote.containers.executeInWSLDistro`) で対象のディストリビューションを指定することもできます。何も指定しないとデフォルトのディストリビューションが使われます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/43355/11caebdb-7da9-696b-9e19-f50e1dc09666.png)



## 8. 結論

金を払えるなら払ったほうが楽ですね。