はじめに
最近、Windows 10にアップグレードしたことに伴い、ローカルの仮想マシン用のハイパーバイザを、もともと利用していたOracle VirtualBoxからHyper-Vに乗り換えました。
VirtualBoxとHyper-Vを切り替えて使うという選択肢もゼロではありませんでしたが、切り替えにはOS再起動を伴うので少々面倒です。
Windows 10でも引き続きVirtualBoxを使うという選択肢もありましたが、Docker Desktop for Windowsも使ってみたかったのでHyper-Vに乗り換えました。
やりたかったこと
Vagrant+VirtualBoxの環境を長年使っておりますが、VagrantはVirtualBoxをProviderとした場合、かなり柔軟にいろいろ設定が出来ます。
Hyper-Vに移行した場合でも、VMの操作については同様の使用感を実現したい、というのが大きな目的です。
要件を整理すると下記のようになりました。
- Docker Desktop for Windowsを使う
- 各Docker container内からInternetへ接続できるようにする
- PublishしたPortは、ホストOSからの接続・ネットワーク外部のホストからの接続ができるようにする
- Docker Containerが稼働するOS(MobyLinuxVM)のネットワークは192.168.252.0/23にする
- Hyper-Vの仮想マシン(VM)を普通に使う
- 各VMからInternetへ接続できるようにする(WinNATを利用)
- 各VM間で通信できるようにする
- VagrantでVMを作成・破棄できるようにする
- ホストOSから任意のターミナルソフト(自分の場合はTeraTerm)を使って、VMにSSH接続する
- Hyper-VのVMが稼働するネットワークは192.168.254.0/23にする
- Vagrantfile内の設定をもとにVMに固定のプライベートIPアドレスを付与する(できない)
- 上記の環境を共存させる
- 両環境のネットワークは可能であれば分離する(した)
TL;DR
- Docker Desktop for Windowsについて
- Docker Desktop for Windowsのセットアップは、特に難しいことを追加でやる必要はない
- Docker Desktop for Windowsで起動したコンテナからInternetへの接続、「-p」オプションで公開したポートへの他のPCからの接続も特に難しいことは無い
- Docker Desktop for WindowsのNATの仕組みは詳細不明(※詳細未調査。ただし、WinNATとの併存はできる模様)
- Hyper-Vの仮想ネットワークについて
- Hyper-Vの仮想マシンからInternetへ接続できるようにするには、幾つか手作業での設定(PowerShellベースの操作)が必要
- Hyper-VのVM用ネットワークはWinNATを適用する
- Hyper-Vの仮想ネットワークは、VirtualBoxやVMWareと比べて機能が少ない(NAT/NAPT/DHCPサーバ機能は無い)ので、いろいろと自前で設定する必要がある
- VagrantはHyper-Vの仮想ネットワークを操作する機能が無い(※少なくとも2019/3/18現在の最新版である2.2.4では)
- 「Default Switch」という機能が実装され、NAT/NAPT/DHCPサーバ機能が実装されているが、うちの環境では不安定で使えなかった(コントロールパネルのNetwork Connectionsに表示されたり消えたりを繰り返す)
最終的なネットワーク構成
構成のポイントは下記のとおりです。
- Docker Desktop for Windows用のネットワーク(DockerNAT)
- 192.168.252.0/23のネットワーク
- 対応するVirtual Switch名は「DockerNAT」(※インストール時に自動で生成される)
- ホストOS側のIPアドレスは192.168.252.1/23
- Docker container用VM(MobyLinuxVM)のIPアドレスは192.168.252.2/23(※今回の観測上はこの値であった。このIPアドレスがどのように決定・設定されるかは不明。)
- Docker container内からInternetへの接続が可能
- Hyper-V通常VM用のネットワーク(Hyper-V Internal with WinNAT)
- 192.168.254.0/23のネットワーク
- 対応するVirtual Switch名は「Hyper-V Internal with WinNAT」(※任意に命名可)
- ホストOS側のIPアドレスは192.168.254.1/23
- ゲストOS側(上図のstdsv3)のIPアドレスはネットワークレンジ内であれば任意の値を設定可能。今回は192.168.254.13/23を設定。
- WinNATの機能を利用し、このネットワーク内と外部ネットワークとの通信はNATするよう設定
実際に使う上で必要な通信パターンは、実質的に以下の4つとなりました。
- ①各Docker containerからInternetへ接続
- ②外部のホストから、Publishされたポートを経由してDocker containerに接続
- ③各VMからPublishされたポートを経由してDocker containerに接続
- ④各VMからInternetへ接続
環境
本稿は以下の環境で検証しました。
- OS: Windows 10 Pro 10.0.17763 Build 17763
- GitBash 2.21.0
- Vagrant 2.2.4
- Docker Desktop for Windows Community Edition (CE):
- Version: 2.0.0.3 (31259)
- Channel: stable
- Build: 8853db3
概要
全体の流れは大きく以下のようになります。分量が多いので記事は分割しました。
-
【Windows】Docker Desktop for WindowsとVagrantの便利な環境を共存させる #1/3【Hyper-V】 ←いまココ
- Docker Desktop for Windowsをセットアップする
- Docker container内からInternetへの疎通を確認する
-
【Windows】Docker Desktop for WindowsとVagrantの便利な環境を共存させる #2/3【Hyper-V】
- Hyper-V通常VM用のネットワーク(Hyper-V Internal with WinNAT)を設定する
- Hyper-V通常VM用のネットワーク(Hyper-V Internal with WinNAT)からの疎通を確認する
-
【Windows】Docker Desktop for WindowsとVagrantの便利な環境を共存させる #3/3【Hyper-V】
- Hyper-V通常VM用のネットワーク設定を自動化する
手順
Docker Desktop for Windowsをセットアップする
Docker Desktop for Windowsのインストール
まずは、Docker Desktop for Windowsをインストールします。
インストール手順は下記公式ドキュメントに書いてありますので、これに従います。
Install Docker Desktop for Windows | Docker Documentation
https://docs.docker.com/docker-for-windows/install/
なお、Docker Desktop for Windowsをダウンロードするにあたり、Docker Hubのアカウント(というよりDocker ID)が必要となりますので、事前に登録しておきます。
Docker ID accounts | Docker Documentation
https://docs.docker.com/docker-id/
Hyper-Vからの見え方を確認する
インストールが完了し、Docker Desktop for Windowsの実行が完了したら、Hyper-V Managerを開きます。
下記のように「Virtual Machines」の一覧に「MobyLinuxVM」というインスタンスが追加されていることが確認できます。
「MobyLinuxVM」を選択し、下のペインの「Networking」タブを押すと、「DockerNAT」というネットワーク(正確にはVirtual Switch)に接続されていることを確認できます。
当該Virtual Switchの詳細を見てみましょう。右の「Actions」ペインから「Virtual Switch Manager...」をクリックします。下記のようなウィンドウがポップアップします。
「DockerNAT」というVirtual Switchがあるので、これをクリックします。
「Connection type」が「Internal Network」となっていることが確認できます。
なお、Hyper-Vで作成できるVirtual Switchには3種類あります。挙動の違いは下記ドキュメントを参照してください。
Create a virtual switch for Hyper-V virtual machines | Microsoft Docs
https://docs.microsoft.com/en-us/windows-server/virtualization/hyper-v/get-started/create-a-virtual-switch-for-hyper-v-virtual-machines
Docker Desktop for Windowsで利用するネットワークセグメントの変更
次に、タスクトレイのDockerアイコンから、「Settings」を開きます。
デフォルトでは下記の設定になっていると思います。
- Subnet Address: 10.0.75.0
- Subnet Mask: 255.255.255.0
この値を下記のように変更したのち、Applyボタンを押します。
Networkの設定変更、Docker container用VM(MobyLinuxVM)、Hyper-VのVirtual Switchともに作り直しになるようで、かなり時間がかかるので気長に待ちます。体感では、十数分ぐらいといったところでしょうか。
- Subnet Address: 192.168.252.0
- Subnet Mask: 255.255.254.0
以上で、Docker Desktop for Windowsのセットアップは完了です。
PowerShellからDocker Desktop for Windows用のネットワーク(DockerNAT)の設定を確認する
PowerShellからネットワーク関連の設定を参照することが可能です。
PowerShellをAdministrator権限で実行し、下記コマンドレットを実行してみます。
Get-VMSwitch
Get-VMSwitchで、存在するVirtual Switchの一覧を表示します。
PS C:\WINDOWS\system32> Get-VMSwitch
Name SwitchType NetAdapterInterfaceDescription
---- ---------- ------------------------------
DockerNAT Internal
Get-NetAdapter
Get-NetAdapterで、存在するNIC(Network Adapter)の一覧を表示します。NICには「ifIndex」というUniqueなIDが付与されるようです。NICに何か設定変更をしたい場合、このifIndexの値で指定することが多いです。
Docker Desktop for Windowsのインストールにより、「vEthernet (DockerNAT)」というNICが自動で作られています。このNICの「ifIndex」は「26」であることが分かります。
PS C:\WINDOWS\system32> Get-NetAdapter
Name InterfaceDescription ifIndex Status MacAddress LinkSpeed
---- -------------------- ------- ------ ---------- ---------
ローカル エリア接続 Realtek PCIe GBE Family Controller 9 Up 80-EE-73-2E-ED-3E 1 Gbps
vEthernet (DockerNAT) Hyper-V Virtual Ethernet Adapter 26 Up 00-15-5D-14-25-0E 10 Gbps
Get-NetIPaddress
Get-NetIPaddressで、NICに付与されたIPアドレスを表示します。192.168.252.1が付与されていることが分かります。
PS C:\WINDOWS\system32> Get-NetIPAddress -InterfaceIndex 26
IPAddress : 192.168.252.1
InterfaceIndex : 26
InterfaceAlias : vEthernet (DockerNAT)
AddressFamily : IPv4
Type : Unicast
PrefixLength : 23
PrefixOrigin : Manual
SuffixOrigin : Manual
AddressState : Preferred
ValidLifetime : Infinite ([TimeSpan]::MaxValue)
PreferredLifetime : Infinite ([TimeSpan]::MaxValue)
SkipAsSource : False
PolicyStore : ActiveStore
Docker container内からInternetへの疎通を確認する
では実際に、Docker containerからInternetへ接続できるかどうかを確認していきます。
CentOS 7のDocker imageをもとにcontainerを実行し、net-utils及びbind-utilsをインストールして疎通を確認していきます。
CentOS 7のDocker imageをもとにcontainerを実行する
PowerShellを開き、「-ti」オプション付きでdocker runを実行し、プロセスとしてbashを起動させます。初回はDocker imageのダウンロードが行われるので、少し時間がかかるでしょう。
containerの実行が完了するとcontainerのシェルを操作できるようになります。
PS C:\WINDOWS\system32> docker run -ti centos bash
[root@7381948a82a5 /]#
net-utils及びbind-utilsをインストールする
containerのシェルからyum installを実行します。
[root@7381948a82a5 /]# yum install net-tools bind-utils -y
Loaded plugins: fastestmirror, ovl
Determining fastest mirrors
* base: ftp.jaist.ac.jp
* extras: ftp.jaist.ac.jp
* updates: ftp.jaist.ac.jp
# ※途中省略
Running transaction
Installing : GeoIP-1.5.0-13.el7.x86_64 1/4
Installing : 32:bind-libs-9.9.4-73.el7_6.x86_64 2/4
Installing : 32:bind-utils-9.9.4-73.el7_6.x86_64 3/4
Installing : net-tools-2.0-0.24.20131004git.el7.x86_64 4/4
Verifying : 32:bind-utils-9.9.4-73.el7_6.x86_64 1/4
Verifying : GeoIP-1.5.0-13.el7.x86_64 2/4
Verifying : net-tools-2.0-0.24.20131004git.el7.x86_64 3/4
Verifying : 32:bind-libs-9.9.4-73.el7_6.x86_64 4/4
Installed:
bind-utils.x86_64 32:9.9.4-73.el7_6 net-tools.x86_64 0:2.0-0.24.20131004git.el7
Dependency Installed:
GeoIP.x86_64 0:1.5.0-13.el7 bind-libs.x86_64 32:9.9.4-73.el7_6
Complete!
containerのネットワーク設定を確認する・Internetへの接続を確認する
IPアドレス設定・ルーティングテーブルなどの設定を確認し、Internetへの接続ができるかどうかを確認します。
ifconfigコマンドを実行し、付与されたIPアドレスを確認します。今回は172.17.0.2/16が付与されていることを確認できます。
[root@1787083910dc /]# ifconfig
eth0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST> mtu 1500
inet 172.17.0.2 netmask 255.255.0.0 broadcast 172.17.255.255
ether 02:42:ac:11:00:02 txqueuelen 0 (Ethernet)
RX packets 8790 bytes 12845100 (12.2 MiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 3116 bytes 172364 (168.3 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
lo: flags=73<UP,LOOPBACK,RUNNING> mtu 65536
inet 127.0.0.1 netmask 255.0.0.0
loop txqueuelen 1 (Local Loopback)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
netstat -rnでルーティングテーブルを見てみます。172.17.0.1がDefault Gatewayになっていることが確認できます。
[root@1787083910dc /]# netstat -rn
Kernel IP routing table
Destination Gateway Genmask Flags MSS Window irtt Iface
0.0.0.0 172.17.0.1 0.0.0.0 UG 0 0 0 eth0
172.17.0.0 0.0.0.0 255.255.0.0 U 0 0 0 eth0
適当なInternet上のホストにpingします。ここでは8.8.8.8を利用します。
[root@1787083910dc /]# ping 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=37 time=18.3 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=37 time=14.3 ms
64 bytes from 8.8.8.8: icmp_seq=3 ttl=37 time=14.1 ms
^C
--- 8.8.8.8 ping statistics ---
3 packets transmitted, 3 received, 0% packet loss, time 2003ms
rtt min/avg/max/mdev = 14.156/15.612/18.334/1.931 ms
キャッシュされたARPテーブルを見てみます。Default Gatewayである172.17.0.1のMACアドレスが保持されていることを確認できます。
[root@1787083910dc /]# arp -a
gateway (172.17.0.1) at 02:42:e0:c7:e4:c3 [ether] on eth0
名前解決ができるかどうかdigコマンドを利用して試してみます。問題なく名前解決することができました。
併せてDNSリゾルバとして192.168.65.1が利用されていることが確認できます。
[root@1787083910dc /]# dig google.com
; <<>> DiG 9.9.4-RedHat-9.9.4-73.el7_6 <<>> google.com
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 199
;; flags: qr rd ra; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;google.com. IN A
;; ANSWER SECTION:
google.com. 291 IN A 216.58.197.206
;; Query time: 14 msec
;; SERVER: 192.168.65.1#53(192.168.65.1)
;; WHEN: Sun Mar 17 06:14:05 UTC 2019
;; MSG SIZE rcvd: 55
resolv.confの内容を確認してみます。やはり192.168.65.1が指定されていることが確認できました。
[root@1787083910dc /]# cat /etc/resolv.conf
# This configuration is written to the config.iso
nameserver 192.168.65.1
search ******** # ホストOSの設定が反映される
domain ******** # ホストOSの設定が反映される
Docker container外のホストからcontainerへの疎通ができるかどうか確認する
最後に、適当なDocker conainerを起動させ、ホストOS・他のPCから接続できるかどうかを確認します。
nginxのイメージを使います。
nginxのDocker imageをもとにcontainerを実行する
PowerShellを開き、nginxのイメージを指定してdocker runを実行します。今回は、公開するPortを8080、container側のPortを80として実行します
実行後、エラー等が表示されなければ恐らく成功です。
PS C:\Users\mta> docker run -p 8080:80 nginx
ホストOSからnginxへの疎通を確認する
ホストOSでGitBashを実行し、curl等でTCP/8080にHTTPアクセスして、nginxのWelcomeページが返却されるかどうか確認します。
IPアドレスは、127.0.0.1、物理NICに振られているアドレス(今回の場合は10.1.1.34)それぞれ確認します。
$ curl http://127.0.0.1:8080/
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
$ curl http://10.1.1.34:8080/
<!DOCTYPE html>
※途中省略
</html>
以上で、Docker containerの疎通確認は終了です。container内からInternetへの接続ができること、ホストOSからcontainerに接続できることを確認しました。
外部のほかのホストからcontainerに接続できるかどうかについては、次の作業で確認します。
ちなみにcontainerから見えるネットワーク設定は、LinuxにDockerをインストールした場合と変わらないようです。
Hyper-V通常VM用のネットワーク(Hyper-V Internal with WinNAT)を設定する
※続きます
【Windows】Docker Desktop for WindowsとVagrantの便利な環境を共存させる #2/3【Hyper-V】