Dockerで物理マシン間のOverlayネットワーク(VXLAN)を試す

あるアプリケーションの調査を行うために、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は、以下のリンクから確認することができます。

RFC 7348

前提

docker-machineコマンドを実行する場合、操作対象となるLinuxマシンには、事前に以下の設定をしておく必要があります。
それぞれ参考リンクを参照し、設定してください。

  • コマンドに指定するユーザが、sudoコマンドをパスワード無しで使用できること
  • 参考リンク
    ubuntu-without-passwd

  • コマンドに指定するユーザが、SSHの公開鍵認証でログインできること
  • 参考リンク
    SSHの公開鍵認証

  • WindowsマシンにDocker Toolboxがインストールされていること
  • 参考リンク
    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ネットワークが構築できました。
興味のある方は是非試してみてください。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

*