あるアプリケーションの調査を行うために、VMを作ってそのVMの上で対象のアプリケーションを実行しようとしていたのですが、Docker上でも実行できるのではと思い立ち、Dockerの調査を行いました。
その過程で、DockerでサポートされているOverlayネットワークのVXLANとVXLANが提案されているRFC 7348の調査を行い、実際に物理マシン間でOverlayネットワークを構築しました。
そして、物理マシン上のコンテナ間でpingを実行時に物理マシン上でパケットダンプを実行したり、iperf3を使用してパフォーマンスの確認を行ったので、まとめておきます。
本記事では、VXLANやDockerなどの技術やコマンド自体については、記事が長くなることを避けるため、説明を省略しています。
ご了承ください。
概要
DockerのWebサイト上においても、overlayネットワークドライバを試すための手順が紹介されています。
get-started-overlay
上記リンクの内容は、1つの物理マシン上に、VirtualBoxで3つのVMを立ち上げて、そのVM間で通信をする手順です。
本記事では、WindowsマシンにDocker Toolboxをインストールし、Windowsマシンからローカルの他の物理マシン上にdocker-machineコマンドを経由してアクセスし、他の物理マシン上にコンテナを立ち上げています。
また、異なる物理マシン間でDockerのOverlayネットワークを構築し、コンテナ間でのVXLANによる通信を試しました。
VXLANが提案されているRFCは、以下のリンクから確認することができます。
前提
docker-machineコマンドを実行する場合、操作対象となるLinuxマシンには、事前に以下の設定をしておく必要があります。
それぞれ参考リンクを参照し、設定してください。
- コマンドに指定するユーザが、sudoコマンドをパスワード無しで使用できること
- コマンドに指定するユーザが、SSHの公開鍵認証でログインできること
- WindowsマシンにDocker Toolboxがインストールされていること
参考リンク
ubuntu-without-passwd
参考リンク
SSHの公開鍵認証
参考リンク
docker-toolbox
環境
Windowsマシン
- docker-machine
# docker-machine.exe --version docker-machine.exe version 0.6.0, build e27fb87
物理マシン
- Linux Kernel
$ uname -a Linux host1 3.19.0-25-generic
- ホスト名とIPアドレス
ホスト名 IPアドレス host1 192.168.1.120/24 host2 192.168.1.121/24 host3 192.168.1.122/24
※Windowsマシンは、192.168.1.0/24のネットワークに接続しています。
※各物理マシンは、GbEのネットワークに接続しています。
本記事では、物理マシン全てにhogeユーザを作成し、sudoコマンドがパスワード無しで実行可能、公開鍵認証方式でSSHログインが可能なように設定してあります。
物理マシンにDockerのコンテナ環境を構築
※ここ章の操作は、WindowsにインストールしたCygwinのminttyで実行しています。
host1にDocker環境を構築し、consul用のコンテナを作成します。
# docker-machine.exe create --driver generic --generic-ip-address=192.168.1.120 --generic-ssh-user=hoge --generic-ssh-key=./docker.id_rsa host1 # eval $(docker-machine env host1) # docker.exe run -d -p "8500:8500" -h "consul" progrium/consul -server -bootstrap
host2にDocker環境を構築し、swarm-master用のコンテナを作成します。
# docker-machine.exe create --driver generic --generic-ip-address=192.168.1.121 --generic-ssh-user=hoge --generic-ssh-key=./docker.id_rsa --swarm --swarm-master --swarm-discovery="consul://$(docker-machine.exe ip host1):8500" --engine-opt="cluster-store=consul://$(docker-machine.exe ip host1):8500" --engine-opt="cluster-advertise=eth0:2376" host2
host3にDocker環境を構築し、swarm用のコンテナを作成します。
# docker-machine.exe create --driver generic --generic-ip-address=192.168.1.122 --generic-ssh-user=hoge --generic-ssh-key=./docker.id_rsa --swarm --swarm-discovery="consul://$(docker-machine.exe ip host1):8500" --engine-opt="cluster-store=consul://$(docker-machine.exe ip host1):8500" --engine-opt="cluster-advertise=eth0:2376" host3
物理マシンのDocker環境を確認します。
# docker-machine.exe ls NAME ACTIVE DRIVER STATE URL SWARM DOCKER ERRORS host1 * generic Running tcp://192.168.1.120:2376 v1.10.3 host2 - generic Running tcp://192.168.1.121:2376 host2 (master) v1.10.3 host3 - generic Running tcp://192.168.1.122:2376 host2 v1.10.3
host3上でoverlayネットワークを作成します。
# eval $(docker-machine.exe env host3) # docker network create --driver overlay --subnet=10.0.10.0/24 test-net
test-netというoverlayネットワークが作成されたことを確認します。
# docker network ls NETWORK ID NAME DRIVER 342a27e8171a test-net overlay c423c916549f bridge bridge 93521ceb7c06 none null e3f1894d3548 host host 27093b1af756 docker_gwbridge bridge
pingでの疎通確認
VXLANが使用されるかどうかを確認するために、host2とhost3それぞれに/bin/shのコンテナを作成し、コンテナ間でpingを実行します。
cygwinのterminalでインタラクティブなコンソールを持つコンテナを立ち上げるとエラーになるので、そのようなコンテナを立ち上げる時は、以下のURLで解説されているようなコンソールを使用してください。
Docker Windows Client を Cygwin で動かすと tty を enable にできない件
また、evalコマンドが実行できない場合は、”docker-machine env <マシン名>“を実行した時に表示される”SET”で始まる行をコピー&ペーストすると、対象のマシンを切り替えることができます。
コンソールを起動し、host2用の環境変数を表示します。
# docker-machine env host2 SET DOCKER_TLS_VERIFY=1 SET DOCKER_HOST=tcp://192.168.1.121:2376 SET DOCKER_CERT_PATH=C:\Users\hoge\.docker\machine\machines\host2 SET DOCKER_MACHINE_NAME=host2 REM Run this command to configure your shell: REM FOR /f "tokens=*" %i IN ('docker-machine env host2') DO %i
上記の”SET”で始まる行をコピー&ペーストした後、host2上に/bin/shを実行するコンテナを作成します。
# docker run -it --name=shell --net=test-net busybox /bin/sh
新たにコンソールを起動し、host3用の環境変数を表示します。
# docker-machine env host3 SET DOCKER_TLS_VERIFY=1 SET DOCKER_HOST=tcp://192.168.1.122:2376 SET DOCKER_CERT_PATH=C:\Users\hoge\.docker\machine\machines\host3 SET DOCKER_MACHINE_NAME=host3 REM Run this command to configure your shell: REM FOR /f "tokens=*" %i IN ('docker-machine env host3') DO %i
上記の”SET”で始まる行をコピー&ペーストした後、host3上に/bin/shを実行するコンテナを作成します。
# docker run -it --name=shell2 --net=test-net busybox /bin/sh
そのままコンソール上でhost2上のコンテナ宛てにpingを実行します。
/ # ping shell -I eth0 PING shell (10.0.10.5): 56 data bytes 64 bytes from 10.0.10.5: seq=0 ttl=64 time=0.686 ms 64 bytes from 10.0.10.5: seq=1 ttl=64 time=0.511 ms 64 bytes from 10.0.10.5: seq=2 ttl=64 time=0.482 ms 64 bytes from 10.0.10.5: seq=3 ttl=64 time=0.390 ms 64 bytes from 10.0.10.5: seq=4 ttl=64 time=0.553 ms ^C --- shell ping statistics --- 5 packets transmitted, 5 packets received, 0% packet loss round-trip min/avg/max = 0.390/0.524/0.686 ms
正常にpingの応答が返ってくることが確認できます。
pingパケットの内容
pingを実行している間、host3上でtcpdumpコマンドを使用してパケットダンプを行っていたところ、pingパケットの内容は、以下のようになっていました。
16:25:21.292115 IP (tos 0x0, ttl 64, id 45083, offset 0, flags [none], proto UDP (17), length 134) 192.168.1.122.33874 > 192.168.1.121.4789: [no cksum] VXLAN, flags [I] (0x08), vni 256 IP (tos 0x0, ttl 64, id 39144, offset 0, flags [DF], proto ICMP (1), length 84) 10.0.10.5 > 10.0.10.6: ICMP echo request, id 3072, seq 0, length 64 0x0000: 901b 0e4a e357 101f 743b 3263 0800 4500 0x0010: 0086 b01b 0000 4011 4608 c0a8 017a c0a8 0x0020: 0179 8452 12b5 0072 0000 0800 0000 0001 0x0030: 0000 0242 0a00 0a06 0242 0a00 0a05 0800 0x0040: 4500 0054 98e8 4000 4001 79b6 0a00 0a05 0x0050: 0a00 0a06 0800 7215 0c00 0000 f3ae 863b 0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 0x0070: 0000 0000 0000 0000 0000 0000 0000 0000 0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 0x0090: 0000 0000 16:25:21.292573 IP (tos 0x0, ttl 64, id 661, offset 0, flags [none], proto UDP (17), length 134) 192.168.1.121.53384 > 192.168.1.122.4789: [no cksum] VXLAN, flags [I] (0x08), vni 256 IP (tos 0x0, ttl 64, id 57768, offset 0, flags [none], proto ICMP (1), length 84) 10.0.10.6 > 10.0.10.5: ICMP echo reply, id 3072, seq 0, length 64 0x0000: 101f 743b 3263 901b 0e4a e357 0800 4500 0x0010: 0086 0295 0000 4011 f38e c0a8 0179 c0a8 0x0020: 017a d088 12b5 0072 0000 0800 0000 0001 0x0030: 0000 0242 0a00 0a05 0242 0a00 0a06 0800 0x0040: 4500 0054 e1a8 0000 4001 70f6 0a00 0a06 0x0050: 0a00 0a05 0000 7a15 0c00 0000 f3ae 863b 0x0060: 0000 0000 0000 0000 0000 0000 0000 0000 0x0070: 0000 0000 0000 0000 0000 0000 0000 0000 0x0080: 0000 0000 0000 0000 0000 0000 0000 0000 0x0090: 0000 0000
pingパケットをカプセル化するために、ちゃんとVXLANが使用されています。
それにしても、tcpdumpコマンドがVXLANのパケットを解釈できることに驚きです・・・。
iperf3を使用してパフォーマンスの確認
VXLANのパフォーマンスを確認するために、iperf3というアプリケーションを使用してスループットの計測を行います。host2でiperf3のサーバ、host3でiperf3のクライアントを起動します。
host2用のコンソールでiperf3のサーバを実行するコンテナを起動します。
# docker run -it --name=iperf-server --net=test-net networkstatic/iperf3 -s
host2用のコンソールでiperf3のサーバを実行するコンテナを起動します。
# docker run -it --name=iperf-client --net=test-net networkstatic/iperf3 -c iperf-server Connecting to host iperf-server, port 5201 [ 4] local 10.0.10.6 port 46381 connected to 10.0.10.5 port 5201 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 94.7 MBytes 794 Mbits/sec 0 3.02 MBytes [ 4] 1.00-2.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 2.00-3.00 sec 91.2 MBytes 765 Mbits/sec 0 3.02 MBytes [ 4] 3.00-4.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 4.00-5.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 5.00-6.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 6.00-7.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 7.00-8.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 8.00-9.00 sec 92.5 MBytes 776 Mbits/sec 0 3.02 MBytes [ 4] 9.00-10.00 sec 91.2 MBytes 766 Mbits/sec 0 3.02 MBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 925 MBytes 776 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 925 MBytes 776 Mbits/sec receiver iperf Done.
iperf3実行後のiperf3サーバ側の出力は、以下の通りです。
----------------------------------------------------------- Server listening on 5201 ----------------------------------------------------------- Accepted connection from 10.0.10.6, port 46380 [ 5] local 10.0.10.5 port 5201 connected to 10.0.10.6 port 46381 [ ID] Interval Transfer Bandwidth [ 5] 0.00-1.00 sec 88.3 MBytes 740 Mbits/sec [ 5] 1.00-2.00 sec 92.1 MBytes 773 Mbits/sec [ 5] 2.00-3.00 sec 92.1 MBytes 773 Mbits/sec [ 5] 3.00-4.00 sec 92.1 MBytes 773 Mbits/sec [ 5] 4.00-5.00 sec 92.3 MBytes 775 Mbits/sec [ 5] 5.00-6.00 sec 92.3 MBytes 775 Mbits/sec [ 5] 6.00-7.00 sec 92.4 MBytes 775 Mbits/sec [ 5] 7.00-8.00 sec 92.4 MBytes 775 Mbits/sec [ 5] 8.00-9.00 sec 92.4 MBytes 775 Mbits/sec [ 5] 9.00-10.00 sec 92.4 MBytes 775 Mbits/sec [ 5] 10.00-10.06 sec 5.84 MBytes 774 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 5] 0.00-10.06 sec 925 MBytes 771 Mbits/sec 0 sender [ 5] 0.00-10.06 sec 925 MBytes 771 Mbits/sec receiver ----------------------------------------------------------- Server listening on 5201 -----------------------------------------------------------
計測の結果、コンテナ間でVXLANを使用した場合のスループットは、771Mbpsでした。
比較をするため、host2とhost3の物理マシン上でiperf3を実行しました。その結果は以下の通りです。
- host2上のiperf3のサーバ側の出力
$ iperf3 -s ----------------------------------------------------------- Server listening on 5201 ----------------------------------------------------------- Accepted connection from 192.168.1.122, port 34705 [ 5] local 192.168.1.121 port 5201 connected to 192.168.1.122 port 34706 [ ID] Interval Transfer Bandwidth [ 5] 0.00-1.00 sec 109 MBytes 911 Mbits/sec [ 5] 1.00-2.00 sec 112 MBytes 941 Mbits/sec [ 5] 2.00-3.00 sec 112 MBytes 941 Mbits/sec [ 5] 3.00-4.00 sec 112 MBytes 941 Mbits/sec [ 5] 4.00-5.00 sec 112 MBytes 941 Mbits/sec [ 5] 5.00-6.00 sec 112 MBytes 941 Mbits/sec [ 5] 6.00-7.00 sec 112 MBytes 941 Mbits/sec [ 5] 7.00-8.00 sec 112 MBytes 941 Mbits/sec [ 5] 8.00-9.00 sec 112 MBytes 941 Mbits/sec [ 5] 9.00-10.00 sec 112 MBytes 941 Mbits/sec [ 5] 10.00-10.03 sec 3.74 MBytes 938 Mbits/sec - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 5] 0.00-10.03 sec 1.10 GBytes 939 Mbits/sec 0 sender [ 5] 0.00-10.03 sec 1.10 GBytes 938 Mbits/sec receiver ----------------------------------------------------------- Server listening on 5201 -----------------------------------------------------------
- host3上のiperf3のクライアント側の出力
$ iperf3 -c 192.168.1.121 Connecting to host 192.168.1.121, port 5201 [ 4] local 192.168.1.122 port 34706 connected to 192.168.1.121 port 5201 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 113 MBytes 950 Mbits/sec 0 230 KBytes [ 4] 1.00-2.00 sec 112 MBytes 942 Mbits/sec 0 230 KBytes [ 4] 2.00-3.00 sec 112 MBytes 942 Mbits/sec 0 230 KBytes [ 4] 3.00-4.00 sec 112 MBytes 938 Mbits/sec 0 230 KBytes [ 4] 4.00-5.00 sec 112 MBytes 943 Mbits/sec 0 242 KBytes [ 4] 5.00-6.00 sec 112 MBytes 942 Mbits/sec 0 242 KBytes [ 4] 6.00-7.00 sec 112 MBytes 942 Mbits/sec 0 242 KBytes [ 4] 7.00-8.00 sec 112 MBytes 939 Mbits/sec 0 242 KBytes [ 4] 8.00-9.00 sec 112 MBytes 942 Mbits/sec 0 242 KBytes [ 4] 9.00-10.00 sec 112 MBytes 942 Mbits/sec 0 242 KBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-10.00 sec 1.10 GBytes 943 Mbits/sec 0 sender [ 4] 0.00-10.00 sec 1.10 GBytes 942 Mbits/sec receiver iperf Done.
VXLANを使用した場合、スループットが約167Mbps程度、落ちてしまいました。
VXLANを使用すると、1パケット当たり、Etherヘッダ(14byte) + IPヘッダ(20byte) + UDPヘッダ(8byte) + VXLANヘッダ(8byte) + FCS(4byte)の計54byteが付与されます。
また、カプセル化、デカプセル化の処理負荷もあるため、ある程度のスループットの低下は避けられないことですね。
※RFC 7348によると、カプセル化対象のEtherフレームはFCSを含まないようです。(Page 11の終わりを参照。)
今回は、DockerのOverlayネットワークであるVXLANによる通信を試してみました。
当初予想していたよりも簡単にOverlayネットワークが構築できました。
興味のある方は是非試してみてください。