Weaveでマルチホストのコンテナ間ネットワークを作ってみる

May 20, 2015   #docker  #weave  #network 

Weaveを使ってコンテナ間の通信をしてみます。

Weaveとは、Weaveworksが開発しているコンテナ間ネットワークを構築するソフトウェアです。 複数のホスト間で仮想ネットワーク(オーバーレイネットワーク)を構築するアプローチで通信を実現します。

weaveworks/weaveから引用

構成

今回の検証は、Amazon Linuxを4台使います。

前提条件:

  • AMIはAmazon Linux AMI 2015.03 (HVM)
  • Dockerのバージョンはv1.6
  • Weaveのバージョンはv0.10.0

登場人物は下記の通りです。

  • ホストA: 172.31.10.26 /16
    • コンテナa1(ubuntu): 10.0.1.1 /24
    • コンテナa2(ubuntu): 10.0.2.1 /24
  • ホストB: 172.31.1.190 /16
    • コンテナb1(ubuntu): 10.0.1.2 /24
    • コンテナb2(ubuntu): 10.0.2.2 /24
  • ホストC: 172.31.10.53 /16
    • コンテナc1(ubuntu): 10.0.1.3 /24
    • コンテナc2(ubuntu): 10.0.2.3 /24
  • テスト用インスタンス: 172.31.6.235 /16

DockerとWeaveをインストールする

まずはDockerを入れます。

sudo yum install docker
sudo service docker start

次にWeaveを入れて実行権限を付与します。

sudo wget -O /usr/local/bin/weave \
  https://github.com/weaveworks/weave/releases/download/latest_release/weave
sudo chmod a+x /usr/local/bin/weave

今のままだとsudoのパスで/usr/local/binが通っていないので追加します。

sudo visudo

secure_pathの末尾に:/usr/local/binを追記してください。

Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin

残り2台のホストも同じようにインストールします。

Weaveを立ち上げる

Weaveルータを立てます。

ホストAでは、下記のコマンドでWeaveを立ち上げます。 初回起動時はWeaveのイメージを引っ張ってくる関係で、少し時間がかかります。

sudo weave launch

ホストBとCでは下記のコマンドを実行します。 最初にWeaveを立ち上げたホストのIPを指定する点が異なります。

sudo weave launch 172.31.10.26

docker psでWeaveルータのコンテナが立っていることがわかります。

sudo docker ps
CONTAINER ID        IMAGE                     COMMAND                CREATED             STATUS              PORTS                                            NAMES
16bab2885f39        weaveworks/weave:0.10.0   "/home/weave/weaver    9 minutes ago       Up 9 minutes        0.0.0.0:6783->6783/tcp, 0.0.0.0:6783->6783/udp   weave

PORTSにあるように、WeaveはTCPとUDPの6783番ポートでホスト間を接続します。

コンテナを立ち上げる

docker runではなく、weave runでコンテナを立ち上げます。 weavedockerのWrapperになっていて、内部的にdockerコマンドを呼んでいます。

具体的に何をしているか知りたい方は、/usr/local/bin/weaveの中身を読んでみてください。

weave runでコンテナを立ち上げる際にIPを指定します。

ホストA:

sudo weave run 10.0.1.1/24 -it --name a1 ubuntu
sudo weave run 10.0.2.1/24 -it --name a2 ubuntu

ホストB:

sudo weave run 10.0.1.2/24 -it --name b1 ubuntu
sudo weave run 10.0.2.2/24 -it --name b2 ubuntu

ホストC:

sudo weave run 10.0.1.3/24 -it --name c1 ubuntu
sudo weave run 10.0.2.3/24 -it --name c2 ubuntu

コンテナ間でPingしてみる

ホストAのコンテナから他のコンテナにPingしてみます。

sudo docker attach a1

まず同一セグメント(10.0.1.0/24)のコンテナにPingします。

ping -c 5 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=2.09 ms
64 bytes from 10.0.1.2: icmp_seq=2 ttl=64 time=0.886 ms
64 bytes from 10.0.1.2: icmp_seq=3 ttl=64 time=0.855 ms
64 bytes from 10.0.1.2: icmp_seq=4 ttl=64 time=0.819 ms
64 bytes from 10.0.1.2: icmp_seq=5 ttl=64 time=0.811 ms

--- 10.0.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4000ms
rtt min/avg/max/mdev = 0.811/1.092/2.091/0.500 ms


ping -c 5 10.0.1.3
PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=2.98 ms
64 bytes from 10.0.1.3: icmp_seq=2 ttl=64 time=1.01 ms
64 bytes from 10.0.1.3: icmp_seq=3 ttl=64 time=1.06 ms
64 bytes from 10.0.1.3: icmp_seq=4 ttl=64 time=0.964 ms
64 bytes from 10.0.1.3: icmp_seq=5 ttl=64 time=0.906 ms

--- 10.0.1.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4004ms
rtt min/avg/max/mdev = 0.906/1.386/2.982/0.800 ms

同一セグメント間ではPingが成功しました。

次に異なるセグメントのコンテナにPingします。 普通に考えれば失敗するはずです。

ping -c 5 10.0.2.1
PING 10.0.2.1 (10.0.2.1) 56(84) bytes of data.

--- 10.0.2.1 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4033ms


ping -c 5 10.0.2.2
PING 10.0.2.2 (10.0.2.2) 56(84) bytes of data.

--- 10.0.2.2 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4032ms


ping -c 5 10.0.2.3
PING 10.0.2.3 (10.0.2.3) 56(84) bytes of data.

--- 10.0.2.3 ping statistics ---
5 packets transmitted, 0 received, 100% packet loss, time 4032ms

想定通り、異なるセグメントにはPingが失敗しました。

Weaveの状態を確認する

weave statusでWeaveの状態を確認できます。

sudo weave status
weave router 0.10.0
Encryption off
Our name is c2:62:4a:9c:25:1e(ip-172-31-1-190)
Sniffing traffic on &{9 65535 ethwe de:c1:5d:e3:41:25 up|broadcast|multicast}
MACs:
Peers:
c2:62:4a:9c:25:1e(ip-172-31-1-190) (v4) (UID 17779938470500780833)
   -> 82:81:b8:a2:bc:07(ip-172-31-10-26) [172.31.10.26:6783]
   -> b6:7f:08:24:14:52(ip-172-31-10-53) [172.31.10.53:42263]
82:81:b8:a2:bc:07(ip-172-31-10-26) (v4) (UID 9284260985223010690)
   -> c2:62:4a:9c:25:1e(ip-172-31-1-190) [172.31.1.190:51488]
   -> b6:7f:08:24:14:52(ip-172-31-10-53) [172.31.10.53:40095]
b6:7f:08:24:14:52(ip-172-31-10-53) (v4) (UID 1507079788549902253)
   -> 82:81:b8:a2:bc:07(ip-172-31-10-26) [172.31.10.26:6783]
   -> c2:62:4a:9c:25:1e(ip-172-31-1-190) [172.31.1.190:6783]
Routes:
unicast:
c2:62:4a:9c:25:1e -> 00:00:00:00:00:00
b6:7f:08:24:14:52 -> b6:7f:08:24:14:52
82:81:b8:a2:bc:07 -> 82:81:b8:a2:bc:07
broadcast:
82:81:b8:a2:bc:07 -> []
b6:7f:08:24:14:52 -> []
c2:62:4a:9c:25:1e -> [82:81:b8:a2:bc:07 b6:7f:08:24:14:52]
Reconnects:

上記はホストBで実行した結果です。 Peersで他のホストとフルメッシュで接続されていることがわかります。 最初にWeaveを立ち上げたホストAがダウンしても、他のホスト間の通信には影響を与えません。

外部との通信を許可する

デフォルトではWeaveのネットワークは隔離されており、外部との通信ができません。 外部通信を許可するにはweave exposeを使用します。

ホストとコンテナ間の通信を許可

通らないのは薄々感じながらも、一応ホストAからコンテナにPingしてみます。

ping -c 1 10.0.1.1
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
^C
--- 10.0.1.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 4424ms

次に、ホストAでルーティングテーブルとweaveインターフェースの状態を確認してください。

netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         ip-172-31-0-1.a 0.0.0.0         UG        0 0          0 eth0
instance-data.a *               255.255.255.255 UH        0 0          0 eth0
172.17.0.0      *               255.255.0.0     U         0 0          0 docker0
172.31.0.0      *               255.255.240.0   U         0 0          0 eth0
ifconfig weave
weave     Link encap:Ethernet  HWaddr 82:81:B8:A2:BC:07  
          inet6 addr: fe80::8081:b8ff:fea2:bc07/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:65535  Metric:1
          RX packets:117 errors:0 dropped:0 overruns:0 frame:0
          TX packets:100 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:7368 (7.1 KiB)  TX bytes:5948 (5.8 KiB)

次に、weave exposeを使います。 外部との通信を許可したいネットワークで、コンテナにアサインしていないIPを指定してください。

sudo weave expose 10.0.1.100/24

ホストAから、10.0.1.0/24のコンテナに対してPingしてみてください。

ping -c 1 10.0.1.1
PING 10.0.1.1 (10.0.1.1) 56(84) bytes of data.
64 bytes from 10.0.1.1: icmp_seq=1 ttl=64 time=0.078 ms

--- 10.0.1.1 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 0.078/0.078/0.078/0.000 ms
ping -c 1 10.0.1.2
PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.
64 bytes from 10.0.1.2: icmp_seq=1 ttl=64 time=2.17 ms

--- 10.0.1.2 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 2.178/2.178/2.178/0.000 ms
ping -c 1 10.0.1.3
PING 10.0.1.3 (10.0.1.3) 56(84) bytes of data.
64 bytes from 10.0.1.3: icmp_seq=1 ttl=64 time=1.56 ms

--- 10.0.1.3 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 1ms
rtt min/avg/max/mdev = 1.563/1.563/1.563/0.000 ms

Pingが通りましたね。 10.0.2.0/24のコンテナには届きません。

ping 10.0.2.1
PING 10.0.2.1 (10.0.2.1) 56(84) bytes of data.
^C
--- 10.0.2.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1799ms

再度、ルーティングテーブルとweaveインターフェースの状態を確認します。

netstat -r
Kernel IP routing table
Destination     Gateway         Genmask         Flags   MSS Window  irtt Iface
default         ip-172-31-0-1.a 0.0.0.0         UG        0 0          0 eth0
10.0.1.0        *               255.255.255.0   U         0 0          0 weave
instance-data.a *               255.255.255.255 UH        0 0          0 eth0
172.17.0.0      *               255.255.0.0     U         0 0          0 docker0
172.31.0.0      *               255.255.240.0   U         0 0          0 eth0
ifconfig weave
weave     Link encap:Ethernet  HWaddr 82:81:B8:A2:BC:07  
          inet addr:10.0.1.100  Bcast:0.0.0.0  Mask:255.255.255.0
          inet6 addr: fe80::8081:b8ff:fea2:bc07/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:65535  Metric:1
          RX packets:117 errors:0 dropped:0 overruns:0 frame:0
          TX packets:101 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:7368 (7.1 KiB)  TX bytes:5990 (5.8 KiB)

weaveインターフェースに10.0.1.100/24がアサインされ、ルーティングテーブルにもweave向けネットワークが追加されています。

コンテナをホストの外に公開する

公式のチュートリアルにあるncを使う方法で検証してみます。

まず、ホストAでNATの設定を入れます。 ホストAのeth0で受信したTCP2211番宛の通信を、ホストC上のコンテナのTCP4422番宛にNATします。

sudo iptables -t nat -A PREROUTING -p tcp -i eth0 --dport 2211 -j DNAT --to-destination 10.0.1.3:4422

ホストCのC1コンテナ(10.0.1.3 /24)上で、ncをリッスンモードで起動します。

sudo docker attach c1
nc -l -p 4422

テスト用インスタンスから、ホストAのTCP2211に文字列を送信します。

echo 'Hello, world.' | nc 172.31.10.26 2211

C1コンテナで受信していれば成功です。

nc -l -p 4422
Hello, world.