マルチホストDockerネットワーキング（pipework＋GRE）

マルチホストで動作するDockerネットワーキングツールについてのまとめ第一段。
（第二弾：[etcd+flannel](http://qiita.com/nmatsui/items/317213cd921e3b2e35d4)）
（第三弾：[weave](http://qiita.com/nmatsui/items/a7caa5a3840b8c920124)）
今回は[jpetazzo/pipework](https://github.com/jpetazzo/pipework)を取り上げる。

# 検証環境
SoftLayerに以下のVirtual Serverを立ち上げて検証した。

||DC|hostname|private IP(eth0)|public IP(eth1)|
|:--|:--|:--|:--|:--|:--|
|ホスト1|Dallas 9|pipework01|10.142.51.197|X.X.X.X|
|ホスト2|Dallas 9|pipework02|10.142.51.196|Y.Y.Y.Y|
|ホスト3|Dallas 6|pipework03|10.106.242.2|Z.Z.Z.Z|

ホスト1とホスト2は同一VLAN上にあり、ホスト3は別VLAN上でホスト1,2とL3で接続されている。

各種バージョンは以下の通り。

| |version|
|:--|:--|
|distribution|Ubuntu 14.04.2 LTS|
|kernel|3.13.0-48-generic|
|docker|1.5.0|
|pipework|commit: 5a1ff19977df4e40f6b82c7b1b86a8d6633a5af9|

# 準備
すべてのホストで以下の作業を実施する。

```text:必要パッケージのインストール
root@pipework01:~# apt-get update
root@pipework01:~# apt-get upgrade -y
root@pipework01:~# apt-get install build-essential bridge-utils curl -y
```

```text:golangとdockerインストール
root@pipework01:~# wget -O - https://storage.googleapis.com/golang/go1.4.2.linux-amd64.tar.gz | tar -C /usr/local -vxzf -
root@pipework01:~# echo 'export PATH=$PATH:/usr/local/go/bin' >> /etc/profile
root@pipework01:~# source /etc/profile
root@pipework01:~# wget -qO- https://get.docker.com/ | sh
```

```text:pipeworkインストール
root@pipework01:~# wget -O /usr/local/bin/pipework https://raw.githubusercontent.com/jpetazzo/pipework/master/pipework
root@pipework01:~# chmod a+x /usr/local/bin/pipework
```

```text:greモジュールをload
root@pipework01:~# lsmod | grep gre
root@pipework01:~# modprobe ip_gre
root@pipework01:~# lsmod | grep gre
ip_gre                 18245  0 
gre                    13796  1 ip_gre
ip_tunnel              23768  1 ip_gre
```

# GREトンネルの設定
ホスト間にIP/Ethernet/GREトンネルを設定する。

ただし全てのホスト間にフルメッシュでトンネルを設定するとパケットがループするため、ホスト1を中心点としてスター型にトンネルを設定する。

今回作成する仮想ネットワークは、**192.168.99.0/24**とするが、各ホストで生成する仮想ブリッジのIPアドレスは重複しないように注意して自力で設定する。

|ホスト|仮想ブリッジのIPアドレス|
|:--|:--|
|ホスト1|192.168.99.251/24|
|ホスト2|192.168.99.252/24|
|ホスト3|192.168.99.253/24|

## ホスト1

```text:仮想ブリッジの作成
root@pipework01:~# brctl addbr br0
root@pipework01:~# ip addr add 192.168.99.251/24 dev br0
root@pipework01:~# ip link set br0 up
root@pipework01:~# ip addr show br0
8: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether f2:c7:9b:2d:20:49 brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.251/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::f0c7:9bff:fe2d:2049/64 scope link 
       valid_lft forever preferred_lft forever
root@pipework01:~# ip route show
default via X.X.X.x dev eth1 
10.0.0.0/8 via 10.142.51.193 dev eth0 
10.142.51.192/26 dev eth0  proto kernel  scope link  src 10.142.51.197 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.42.1 
192.168.99.0/24 dev br0  proto kernel  scope link  src 192.168.99.251 
X.X.X.x/28 dev eth1  proto kernel  scope link  src X.X.X.X 
root@pipework01:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.000000000000       no
```

```text:GREトンネル設定
root@pipework01:~# ip link add gre_to_02 type gretap remote 10.142.51.196 local 10.142.51.197       
root@pipework01:~# brctl addif br0 gre_to_02
root@pipework01:~# ip link set gre_to_02 up
root@pipework01:~# ip link add gre_to_03 type gretap remote 10.106.242.2 local 10.142.51.197
root@pipework01:~# brctl addif br0 gre_to_03
root@pipework01:~# ip link set gre_to_03 up
root@pipework01:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.8e284007d2bb       no              gre_to_02
                                                        gre_to_03
```

## ホスト2

```text:仮想ブリッジの作成
root@pipework02:~# brctl addbr br0
root@pipework02:~# ip addr add 192.168.99.252/24 dev br0
root@pipework02:~# ip link set br0 up
root@pipework02:~# ip addr show br0
8: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 0a:35:5b:bd:28:b5 brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.252/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::835:5bff:febd:28b5/64 scope link 
       valid_lft forever preferred_lft forever
root@pipework02:~# ip route show
default via Y.Y.Y.y dev eth1 
10.0.0.0/8 via 10.142.51.193 dev eth0 
10.142.51.192/26 dev eth0  proto kernel  scope link  src 10.142.51.196 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.42.1 
192.168.99.0/24 dev br0  proto kernel  scope link  src 192.168.99.252
Y.Y.Y.y/28 dev eth1  proto kernel  scope link  src Y.Y.Y.Y 
root@pipework02:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.000000000000       no
```

```text:GREトンネル設定
root@pipework02:~# ip link add gre_to_01 type gretap remote 10.142.51.197 local 10.142.51.196
root@pipework02:~# brctl addif br0 gre_to_01
root@pipework02:~# ip link set gre_to_01 up
root@pipework02:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.7e9ccdb21a54       no              gre_to_01
```

## ホスト3

```text:仮想ブリッジの作成
root@pipework03:~# brctl addbr br0
root@pipework03:~# ip addr add 192.168.99.253/24 dev br0
root@pipework03:~# ip link set br0 up
root@pipework03:~# ip addr show br0
7: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UNKNOWN group default 
    link/ether 2a:85:7d:cb:9b:56 brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.253/24 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::2885:7dff:fecb:9b56/64 scope link 
       valid_lft forever preferred_lft forever
root@pipework03:~# ip route show
default via Z.Z.Z.Z dev eth1 
10.0.0.0/8 via 10.106.242.1 dev eth0 
10.106.242.0/26 dev eth0  proto kernel  scope link  src 10.106.242.2 
172.17.0.0/16 dev docker0  proto kernel  scope link  src 172.17.42.1 
192.168.99.0/24 dev br0  proto kernel  scope link  src 192.168.99.253 
Z.Z.Z.z/28 dev eth1  proto kernel  scope link  src Z.Z.Z.Z
root@pipework03:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.000000000000       no
```

```text:GREトンネル設定
root@pipework03:~# ip link add gre_to_01 type gretap remote 10.142.51.197 local 10.106.242.2
root@pipework03:~# brctl addif br0 gre_to_01
root@pipework03:~# ip link set gre_to_01 up
root@pipework03:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.ae94d8d42c9e       no              gre_to_01
```

ここまでで、各ホストからGREトンネル経由で仮想ブリッジ全てに通信ができるようになる。

![docker_networking_2_01.png](https://qiita-image-store.s3.amazonaws.com/0/37648/a25f442a-81ff-fab9-c997-7213049fff51.png)

# Dockerコンテナ起動
以下のようなコンテナを立ち上げる。

最新版のpipeworkはコンテナIDだけでなくコンテナ名でもIPアドレスを付与できるので、今回はコンテナ名を指定する。

|ホスト|コンテナ名|IPアドレス||
|:--|:--|:--|:--|
|ホスト1|httpd|192.168.99.10/24|apache2を起動|
|ホスト1|client1|192.168.99.11/24||
|ホスト2|client2|192.168.99.21/24||
|ホスト3|client3|192.168.99.31/24||

## ホスト1

```text:httpd起動
root@pipework01:~# HTTPD=$(docker run --name httpd -d -i -t ubuntu:latest /bin/bash)
root@pipework01:~# pipework br0 httpd 192.168.99.10/24
```

```text:client1起動
root@pipework01:~# CLIENT1=$(docker run --name client1 -d -i -t ubuntu:latest /bin/bash)
root@pipework01:~# pipework br0 client1 192.168.99.11/24
```

```text:br0の状態
root@pipework01:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.1ef07eef748e       no              gre_to_02
                                                        gre_to_03
                                                        veth1pl26396
                                                        veth1pl26738
```

### httpdコンテナ

```text:httpdコンテナのネットワーク
root@6f735daafef6:/# ip addr show eth0
11: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link 
       valid_lft forever preferred_lft forever
root@6f735daafef6:/# ip addr show eth1
13: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1462 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 76:73:7e:d5:58:55 brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.10/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::7473:7eff:fed5:5855/64 scope link 
       valid_lft forever preferred_lft forever
root@6f735daafef6:/# ip route show
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2 
192.168.99.0/24 dev eth1  proto kernel  scope link  src 192.168.99.10 
```

```text:apache2のインストール
root@6f735daafef6:/# apt-get install apache2 -y
root@6f735daafef6:/# apachectl start
```

### client1コンテナ

```text:client1コンテナのネットワーク
root@4b4b513ccaf3:/# ip addr show eth0
15: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:03 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.3/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:3/64 scope link 
       valid_lft forever preferred_lft forever
root@4b4b513ccaf3:/# ip addr show eth1
17: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1462 qdisc pfifo_fast state UP group default qlen 1000
    link/ether ae:e6:bb:69:51:5b brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.11/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::ace6:bbff:fe69:515b/64 scope link 
       valid_lft forever preferred_lft forever
root@4b4b513ccaf3:/# ip route show
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.3 
192.168.99.0/24 dev eth1  proto kernel  scope link  src 192.168.99.11 
```

```text:curlのインストール
root@4b4b513ccaf3:/# apt-get install curl -y
```

## ホスト2

```text:client2起動
root@pipework02:~# CLIENT2=$(docker run --name client2 -d -i -t ubuntu:latest /bin/bash)
root@pipework02:~# pipework br0 client2 192.168.99.21/24
```

```text:br0の状態
root@pipework02:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.4ab07b385d05       no              gre_to_01
                                                        veth1pl26981
```

### client2コンテナ

```text:client2コンテナのネットワーク
root@26296693f6f3:/# ip addr show eth0
10: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link 
       valid_lft forever preferred_lft forever
root@26296693f6f3:/# ip addr show eth1
12: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1462 qdisc pfifo_fast state UP group default qlen 1000
    link/ether c6:ea:e6:af:42:2e brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.21/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::c4ea:e6ff:feaf:422e/64 scope link 
       valid_lft forever preferred_lft forever
root@26296693f6f3:/# ip route show
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2 
192.168.99.0/24 dev eth1  proto kernel  scope link  src 192.168.99.21 
```

```text:curlのインストール
root@26296693f6f3:/# apt-get install curl -y
```

## ホスト3

```text:client3起動
root@pipework03:~# CLIENT3=$(docker run --name client3 -d -i -t ubuntu:latest /bin/bash)
root@pipework03:~# pipework br0 client3 192.168.99.31/24
```

```text:br0の状態
root@pipework03:~# brctl show br0
bridge name     bridge id               STP enabled     interfaces
br0             8000.6ad48777397f       no              gre_to_01
                                                        veth1pl27601
```

### client3コンテナ

```text:client3のネットワーク
root@d986d5cedb1a:/# ip addr show eth0
9: eth0: <BROADCAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe11:2/64 scope link 
       valid_lft forever preferred_lft forever
root@d986d5cedb1a:/# ip addr show eth1
11: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1462 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 36:50:b8:f5:e0:93 brd ff:ff:ff:ff:ff:ff
    inet 192.168.99.31/24 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::3450:b8ff:fef5:e093/64 scope link 
       valid_lft forever preferred_lft forever
root@d986d5cedb1a:/# ip route show
default via 172.17.42.1 dev eth0 
172.17.0.0/16 dev eth0  proto kernel  scope link  src 172.17.0.2 
192.168.99.0/24 dev eth1  proto kernel  scope link  src 192.168.99.31 
```

```text:curlのインストール
root@d986d5cedb1a:/# apt-get install curl -y
```

![docker_networking_2_02.png](https://qiita-image-store.s3.amazonaws.com/0/37648/c35687cb-eb5d-c205-4f6a-4b0a7661cd82.png)


# 疎通確認
ここまでで、複数ホストをまたがって敷設された**192.168.99.0/24**という仮想ネットワーク上に4つのコンテナが起動した。ホスト1のeth0にtcpdumpを仕掛け、コンテナやホストから疎通確認を行う。

## ホスト1 → httpdコンテナ
httpdコンテナはホスト1上の仮想ブリッジbr0に直接つながっているため、そのまま通信できる。

```text:ping(ホスト1→httpdコンテナ)
root@pipework01:~# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=0.041 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=0.025 ms
...
```


```text:HTTP(ホスト1→httpdコンテナ)
root@pipework01:~# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...
```

## client1コンテナ → httpdコンテナ
client1コンテナとhttpdコンテナは同じ仮想ブリッジbr0につながっているため、そのまま通信できる。

```text:ping(client1コンテナ→httpdコンテナ)
root@4b4b513ccaf3:/# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=0.039 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=0.027 ms
...
```

```text:HTTP(client1コンテナ→httpdコンテナ)
root@4b4b513ccaf3:/# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...
```

## ホスト2 → httpdコンテナ
同一VLAN上にあるホスト2からのパケットが、ホスト2のbr0を経由してGREでラップされてホスト1のeth0に到達し、ホスト1のbr0を経由してhttpdコンテナと通信できていることがわかる。

```text:ping(ホスト2→httpdコンテナ)
root@pipework02:~# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=0.336 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=0.190 ms
...

root@pipework01:~# tcpdump -v -i eth0 src host 10.142.51.196
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:39:57.990802 IP (tos 0x0, ttl 64, id 61161, offset 0, flags [DF], proto GRE (47), length 122)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 50342, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.252 > 192.168.99.10: ICMP echo request, id 32387, seq 1, length 64
07:39:58.990174 IP (tos 0x0, ttl 64, id 61224, offset 0, flags [DF], proto GRE (47), length 122)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 50568, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.252 > 192.168.99.10: ICMP echo request, id 32387, seq 2, length 64
```

```text:HTTP(ホスト2→httpdコンテナ)
root@pipework02:~# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...

root@pipework01:~# tcpdump -v -i eth0 src host 10.142.51.196
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:42:52.299503 IP (tos 0x0, ttl 64, id 30310, offset 0, flags [DF], proto GRE (47), length 98)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 78
        IP (tos 0x0, ttl 64, id 52399, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.99.252.59501 > 192.168.99.10.http: Flags [S], cksum 0xa609 (correct), seq 4069927267, win 28440, options [mss 1422,sackOK,TS val 2680268 ecr 0,nop,wscale 7], length 0
07:42:52.299796 IP (tos 0x0, ttl 64, id 30311, offset 0, flags [DF], proto GRE (47), length 90)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 70
        IP (tos 0x0, ttl 64, id 52400, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.99.252.59501 > 192.168.99.10.http: Flags [.], cksum 0x39ee (correct), ack 2874439019, win 223, options [nop,nop,TS val 2680268 ecr 2680834], length 0
...
```

## client2コンテナ → httpdコンテナ
ホスト2上にあるclient2コンテナからのパケットが、ホスト2のbr0経由でGREでラップされてホスト1のeth0に到達し、httpdコンテナと通信できていることがわかる。

```text:ping(client2コンテナ→httpdコンテナ)
root@26296693f6f3:/# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=0.452 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=0.196 ms
...
root@pipework01:~# tcpdump -v -i eth0 src host 10.142.51.196
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:46:05.345995 IP (tos 0x0, ttl 64, id 45447, offset 0, flags [DF], proto GRE (47), length 122)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 56407, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.21 > 192.168.99.10: ICMP echo request, id 2908, seq 1, length 64
07:46:06.346171 IP (tos 0x0, ttl 64, id 45684, offset 0, flags [DF], proto GRE (47), length 122)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 56503, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.21 > 192.168.99.10: ICMP echo request, id 2908, seq 2, length 64
```

```text:HTTP(client2コンテナ→httpdコンテナ)
root@26296693f6f3:/# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...
root@pipework01:~# tcpdump -v -i eth0 src host 10.142.51.196
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:49:09.676682 IP (tos 0x0, ttl 64, id 58022, offset 0, flags [DF], proto GRE (47), length 98)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 78
        IP (tos 0x0, ttl 64, id 57881, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.99.21.56184 > 192.168.99.10.http: Flags [S], cksum 0x3150 (correct), seq 2042147917, win 28440, options [mss 1422,sackOK,TS val 2774612 ecr 0,nop,wscale 7], length 0
07:49:09.676978 IP (tos 0x0, ttl 64, id 58023, offset 0, flags [DF], proto GRE (47), length 90)
    10.142.51.196 > 10.142.51.197: GREv0, Flags [none], length 70
        IP (tos 0x0, ttl 64, id 57882, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.99.21.56184 > 192.168.99.10.http: Flags [.], cksum 0xf6d9 (correct), ack 2040333556, win 223, options [nop,nop,TS val 2774612 ecr 2775178], length 0
...
```

## ホスト3 → httpdコンテナ
異るVLAN上にあるホスト3からのパケットが、ホスト3のbr0を経由してGREでラップされてホスト1のeth0に到達し、ホスト1のbr0を経由してhttpdコンテナと通信できていることがわかる。

```text:ping(ホスト3→httpdコンテナ)
root@pipework03:~# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=1.24 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=1.23 ms
...
root@pipework01:~# tcpdump -v -i eth0 src host 10.106.242.2
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:52:23.437254 IP (tos 0x0, ttl 57, id 9749, offset 0, flags [DF], proto GRE (47), length 122)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 46509, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.253 > 192.168.99.10: ICMP echo request, id 1475, seq 1, length 64
07:52:24.438746 IP (tos 0x0, ttl 57, id 9837, offset 0, flags [DF], proto GRE (47), length 122)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 46598, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.253 > 192.168.99.10: ICMP echo request, id 1475, seq 2, length 64
```

```HTTP(ホスト3→httpdコンテナ)
root@pipework03:~# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...

root@pipework01:~# tcpdump -v -i eth0 src host 10.106.242.2
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:54:46.513808 IP (tos 0x0, ttl 57, id 44524, offset 0, flags [DF], proto GRE (47), length 98)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 78
        IP (tos 0x0, ttl 64, id 26818, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.99.253.33516 > 192.168.99.10.http: Flags [S], cksum 0xb799 (correct), seq 3268861327, win 28440, options [mss 1422,sackOK,TS val 2864461 ecr 0,nop,wscale 7], length 0
07:54:46.515162 IP (tos 0x0, ttl 57, id 44525, offset 0, flags [DF], proto GRE (47), length 90)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 70
        IP (tos 0x0, ttl 64, id 26819, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.99.253.33516 > 192.168.99.10.http: Flags [.], cksum 0xa958 (correct), ack 1421784234, win 223, options [nop,nop,TS val 2864461 ecr 2859388], length 0
...
```

## clien3コンテナ → httpdコンテナ
ホスト3上にあるclient3コンテナからのパケットが、ホスト3のbr0経由でGREでラップされてホスト1のeth0に到達し、httpdコンテナと通信できていることがわかる。

```text:ping(client3コンテナ→httpdコンテナ)
root@d986d5cedb1a:/# ping 192.168.99.10
PING 192.168.99.10 (192.168.99.10) 56(84) bytes of data.
64 bytes from 192.168.99.10: icmp_seq=1 ttl=64 time=1.70 ms
64 bytes from 192.168.99.10: icmp_seq=2 ttl=64 time=1.31 ms
...
root@pipework01:~# tcpdump -v -i eth0 src host 10.106.242.2
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
07:59:31.649646 IP (tos 0x0, ttl 57, id 17207, offset 0, flags [DF], proto GRE (47), length 122)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 36443, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.31 > 192.168.99.10: ICMP echo request, id 2908, seq 1, length 64
07:59:32.651510 IP (tos 0x0, ttl 57, id 17293, offset 0, flags [DF], proto GRE (47), length 122)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 102
        IP (tos 0x0, ttl 64, id 36673, offset 0, flags [DF], proto ICMP (1), length 84)
    192.168.99.31 > 192.168.99.10: ICMP echo request, id 2908, seq 2, length 64
```

```text:HTTP(client3コンテナ→httpdコンテナ)
root@d986d5cedb1a:/# curl 192.168.99.10

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
...
root@pipework01:~# tcpdump -v -i eth0 src host 10.106.242.2
tcpdump: listening on eth0, link-type EN10MB (Ethernet), capture size 65535 bytes
08:00:48.250724 IP (tos 0x0, ttl 57, id 29998, offset 0, flags [DF], proto GRE (47), length 98)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 78
        IP (tos 0x0, ttl 64, id 44503, offset 0, flags [DF], proto TCP (6), length 60)
    192.168.99.31.53536 > 192.168.99.10.http: Flags [S], cksum 0x8ae9 (correct), seq 1664400199, win 28440, options [mss 1422,sackOK,TS val 2954896 ecr 0,nop,wscale 7], length 0
08:00:48.252076 IP (tos 0x0, ttl 57, id 29999, offset 0, flags [DF], proto GRE (47), length 90)
    10.106.242.2 > 10.142.51.197: GREv0, Flags [none], length 70
        IP (tos 0x0, ttl 64, id 44504, offset 0, flags [DF], proto TCP (6), length 52)
    192.168.99.31.53536 > 192.168.99.10.http: Flags [.], cksum 0x4003 (correct), ack 2365741000, win 223, options [nop,nop,TS val 2954896 ecr 2949822], length 0
...
```

# まとめ
pipeworkとGREトンネルを使うことで、L2 & L3で接続された複数ホスト間に仮想ネットワークを敷設してDockerコンテナを所属させ、相互に通信させることができた。
各仮想ブリッジのSTPをonにすれば、GREをフルメッシュで設定しても動作するかもしれないが、未検証。