仮想環境に導入したDockerをホスト側のWindows10で利用したい

2020年4月10日

以前の記事で仮想環境上のWindows10 HomeにDocker Desktop for Windows WSL2 Backendを導入しましたが、そのDockerをホスト側のWindows10 で使えないか試してみました。

簡単なまとめ

  • 素直な構成にするのが一番です。
    • 今回のケースの場合は仮想環境上でWSL2とDocker Desktop for Windows WSL2 Backendを使いましょう。(後述のホスト側のバインドも正常に動作します)
    • 公式が提供するツールを使いましょう。(Docker Desktop for WindowsDocker Toolboxなど)
  • Visual Studio Code(VS Code)のRemote Containers 機能拡張が使えるようになります。
  • 今回確認できた手順では、ホスト側のディレクトリをDockerで正常にバインドできませんでした。

検証環境

ホスト側

  • Windows10 Pro バージョン1909 64bit
  • PowerShell上でOpenSSHクライアントが利用可能

ゲスト側

  • 仮想化ソフトウェア:VMware Workstation Player 15.5.1
  • Windows10 Home バージョン1909 64bit(Insider Previewを使用)
  • PowerShell上でOpenSSHクライアントが利用可能
  • WSL2が有効
    • Docker Desktop for Windows Edge 2.2.3.0
    • WSL2 Backend機能が有効
    • デフォルトのWSLディストリビューション:Ubuntu 無印版 (18.04.4)

導入の流れ

ホスト側でdockerおよびdocker-composeコマンドを利用できるようにするため、Windows版のdocker-cliとdocker-composeをインストールします。

Windows用のパッケージ管理ツール「Chocolatey」を使うと、単体で導入できます。
※Chocolateyの導入方法については、以下の参考サイト様をご参照ください。
Chocolateyを使った環境構築の時のメモ

# インストール時には管理者権限でコマンドプロンプトを起動する必要があります。
# またはChocolatey GUI上での導入も可能です。

C:\WINDOWS\system32>choco search docker
...省略...
docker-cli 19.03.3 [Approved]
docker-compose 1.25.4 [Approved]
...省略...

C:\WINDOWS\system32>choco install docker-cli docker-compose

次に、ゲスト側のWindows10 HomeにてOpenSSHサーバーを導入および起動し、ファイアウォール設定を行ってSSHを送受信可能にします。
コマンドで実行する場合は、Microsoft公式の手順を実行します。
Windows Server 2019 および Windows 10 用 OpenSSH のインストール

# 管理者権限でPowerShellを起動します。

# OpenSSHサーバーはデフォルトではオプション扱いで無効になっているため、有効化します。
# はじめに、OpenSSH関連の機能の状態を確認します。
PS C:\WINDOWS\system32> Get-WindowsCapability -Online | ? Name -like 'OpenSSH*'

Name  : OpenSSH.Client~~~~0.0.1.0
State : Installed
Name  : OpenSSH.Server~~~~0.0.1.0
State : NotPresent

# OpenSSHサーバーをインストールします。
# インストール時に "OpenSSH-Server-TCP" という名前のファイアウォール規則が作成され、有効になります。 これにより、ポート 22 での SSH 受信トラフィックが許可されます。
PS C:\WINDOWS\system32> Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0

# OpenSSHサーバーを起動します。
PS C:\WINDOWS\system32> Start-Service sshd

# 以下の設定を行うと、Windowsの起動時にOpenSSH serverが自動起動するようになります。
PS C:\WINDOWS\system32> Set-Service -Name sshd -StartupType 'Automatic'

# ファイアウォールの規則が存在するかチェックします。
PS C:\WINDOWS\system32> Get-NetFirewallRule -Name *ssh*

# "OpenSSH-Server-In-TCP"という名前のファイアウォール規則が存在し、起動していれば(※Enabledの項目がTrueになっていれば)この後の作業は不要です。
# ファイアウォール規則が存在しない場合は作成します。
PS C:\WINDOWS\system32> New-NetFirewallRule -Name sshd -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22

WSL2を起動します。ここではデフォルトのディストリビューションで設定しているUbuntuを起動します。
2020/04/09時点のWSL2ではサービスの自動開始ができないため、Ubuntu側のOpenSSHサーバーを手動で開始します。
※systemctlコマンドが使えないため、serviceコマンドで起動します。

$ sudo service ssh start
 * Starting OpenBSD Secure Shell server sshd  [ OK ]

ここまでで、ゲスト側のWSL2上のDocker Engineをホスト側に引き込む準備ができました。
SSHの多段接続とUnixソケットのローカルポートフォワード設定をホスト側で行います。
ホスト側のOpenSSH Client用の設定ファイルを作成します。

ここでは自宅環境のため割り切って公開鍵認証を行わず、ゲスト側のWindows10 HomeおよびWSL2にパスワード認証にて接続しています。

# %UserProfile%\.ssh\config を編集します。

# ゲスト側のWindows10 Homeへの接続情報とローカルポートフォワードを設定します。
# HostNameでIPアドレスを指定する場合は、Windows10 HomeのIPアドレスを指定します。
# userはWindows10 Homeのユーザーを指定します。
Host vm-win10home
    HostName XXX.XXX.XXX.XXX
    User bar

# ゲスト側のWSL2の設定です。
# Windows10 HomeからWSL2へTCP/IPでアクセスする際、ビルド18945以降はアドレスにlocalhostを指定できるようになったので、HostNameではlocalhostを指定しています。
# userはWSL2のユーザーを指定します。
# 特定のUnixソケット(Docker Engineの本体)をポート23750に転送します。
# ProxyCommandのsshは、Windows10 Home側のssh.exeを絶対パスで指定します。
Host wsl2
    HostName localhost
    User baz
    LocalForward localhost:23750 /var/run/docker.sock
    ProxyCommand C:\Windows\System32\OpenSSH\ssh.exe -W %h:%p vm-win10home

ホスト側のPowerShellにて、OpenSSHクライアントを使ってSSHの多段接続を行います。

# WSL2への接続を行います。
# -Nオプションで、リモートでコマンドを実行しないようにしています。
# Windows10 Home側、WSL2側でパスワード認証が発生します。
PS C:\Users\foo> ssh -N wsl2
bar@XXX.XXX.XXX.XXX's password:
baz@localhost's password:

ホスト側のコマンドプロンプトまたはPowerShellにて以下のDockerコマンドを実行し、ゲスト側のDocker Engineが認識できているか確認します。

# コマンド実行時には、管理者権限は不要です。
PS C:\Users\foo>docker -H localhost:23750 version
Client:
 Version:           19.03.3
 API version:       1.40
 Go version:        go1.12.10
 Git commit:        2355349d-
 Built:             10/14/2019 16:41:26
 OS/Arch:           windows/amd64
 Experimental:      false

Server: Docker Engine - Community
 Engine:
  Version:          19.03.8
  API version:      1.40 (minimum version 1.12)
  Go version:       go1.12.17
  Git commit:       afacb8b
  Built:            Wed Mar 11 01:29:16 2020
  OS/Arch:          linux/amd64
  Experimental:     true
 containerd:
  Version:          v1.2.13
  GitCommit:        7ad184331fa3e55e52b890ea95e65ba581ae3429
 runc:
  Version:          1.0.0-rc10
  GitCommit:        dc9208a3303feef5b3839f4323d9beb36df0a9dd
 docker-init:
  Version:          0.18.0
  GitCommit:        fec3683

以下の設定を行っておくと、dockerコマンドの入力時に-H オプションの指定が不要になり、少し手間が省けます。

# docker コンテキストの一覧を表示します。
PS C:\Users\foo>docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT                  KUBERNETES ENDPOINT   ORCHESTRATOR
default *           Current DOCKER_HOST based configuration   npipe:////./pipe/docker_engine                         swarm

# docker コンテキストを新規に作成します。「my-context」部分は自由に名前をつけることができます。
PS C:\Users\foo>docker context create my-context --docker host=tcp://localhost:23750
my-context
Successfully created context "my-context"

# 作成したdocker コンテキストをメインで使用するようにします。
PS C:\Users\foo>docker context use my-context

# docker コンテキストの一覧を再度表示した場合、作成したコンテキストに「*」がついているのを確認します。
PS C:\Users\foo>docker context ls
NAME                DESCRIPTION                               DOCKER ENDPOINT                  KUBERNETES ENDPOINT   ORCHESTRATOR
default             Current DOCKER_HOST based configuration   npipe:////./pipe/docker_engine                         swarm
my-context *                                                  tcp://localhost:23750

最後に、VS CodeのRemote Containers 機能拡張が動作するように設定します。
ホスト側のVS Codeの機能拡張サイドバーより、「Remote」で検索して「Remote Development」機能拡張をインストールします。
※「Remote Containers」機能拡張のみを個別にインストールしてもOKです。

同様に「Docker」機能拡張をインストールします。

Docker機能拡張をインストールすると、設定画面にてdockerのホスト指定が行えるようになります。
設定画面を開き、以下の設定を行います。
以下の設定はVS Codeの再起動は不要で、即座に反映されます。

  • 検索欄に「docker.host」と入力します。
  • 「Docker: Host」の設定欄にSSHでローカルポートフォワーディングしているDockerを指定します。
    ここでは「tcp://localhost:23750」と入力します。

VS Codeのアクティビティバーより「リモート エクスプローラー」(※Remote Development機能拡張インストール後に選択可能)または「Docker」(※Docker機能拡張インストール後に選択可能)をクリックします。

サイドバーにてWSL2上のdockerコンテナやイメージなどが見えること、およびコンテナの起動や起動中のコンテナへVS Codeから接続できることを確認します。

リモート エクスプローラーの場合
Dockerの場合

ハマった点など

  • Dockerfileまたはdocker-compose.ymlにてホスト側のディレクトリをコンテナにバインドしようとすると、エラーになったり正常にバインドできなかったりとうまくいきません。
    今回の構成ではホスト側はゲスト側のDocker Desktop for Windowsの対象範囲外のため、どうしようもないと思われます。
  • 多段SSHを行う際に、「WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!」という警告が出て接続できなくなるときがあります。これは仮想環境やWSL2のVMのIPアドレスが変更になったり、構成に変化があると発生するようです。
    今回は自宅開発のため、警告が出た場合はknown_hostsから対象の環境の定義を削除することで対応します。
    その後、再度多段SSHを行うとうまくいきます。
# PowerShellにて実行します。
PS C:\Users\foo> ssh-keygen -R XXX.XXX.XXX.XXX
PS C:\Users\foo> ssh-keygen -R localhost

参考サイト様