マルチホストDockerネットワーキング（native overlay）

2015/11/13追記

docker 1.9 正式版での検証した記事を、[マルチホストDockerネットワーキング（正式版 native overlay）](http://qiita.com/nmatsui/items/2811f2297343e1d50739)で公開した。

正式版のoverlay networkは、サブネットアドレスが指定できるようになるなどかなり進化しているため、今後は[コチラ](http://qiita.com/nmatsui/items/2811f2297343e1d50739)を参照してほしい。

----
ずいぶん間が空いてしまったが、マルチホストで動作するDockerネットワーキングツールについてのまとめ第四弾。

（第一弾：[pipework＋GRE](http://qiita.com/nmatsui/items/fb7fc01dbba16b0ecb8e)）
（第二弾：[etcd+flannel](http://qiita.com/nmatsui/items/317213cd921e3b2e35d4)）
（第三弾：[weaveworks/weave](http://qiita.com/nmatsui/items/a7caa5a3840b8c920124)）
今回はDockerのnative overlay networkを取り上げる。

# Dockerのnative networkについて
Docker libnetworkの[Wiki page](https://github.com/docker/libnetwork/wiki)にあるように、Dockerは1.7.0からネットワーク機能を「libnetwork」として切り離し、networkをfirst class objectとして扱うように実装を修正している。ただし2015/10/07時点の最新リリース（1.8.2）ではまだCLIが封印されており、libnetworkの機能を直接操作することはできない。

## libnetworkのコンセプト
libnetworkのコンセプトは「The Container Network Model（CNM）」と呼ばれており、以下３つの概念から構成されている。

![The Container Network Model (CNM)](https://blog.docker.com/media/2015/04/cnm-model.jpg)
出展：Docker Blog - [Docker Networking takes a step in the right direction](https://blog.docker.com/2015/04/docker-networking-takes-a-step-in-the-right-direction-2/)

1. Sandbox
    * コンテナのネットワークスタックの設定（インタフェースやルーティングテーブル、DNS設定等）を隠蔽するもの。
    * LinuxであればNetwork Namespace、FreeBSDであればJail等を用いて実装される。
    * 一つのSandboxが複数のEndpointを持っていても良い。
1. Endpoint
    * SandboxをNetworkに参加させるもの。
    * Endpointはveth pairやOpen vSwitch internal port等を用いて実装される。
    * Endpointは一つのNetwork、一つのSandboxに所属する。
1. Network
    * お互い直接通信できるEndpointの集合を表すもの。
    * NetworkはLinux bridgeやVLAN等を用いて実装される。
    * Networkは複数のEndpointを持つ。

詳細は[libnetworkのdesignドキュメント](https://github.com/docker/libnetwork/blob/master/docs/design.md)を参照


## 現時点で実装されているlibnetwork driver

https://github.com/docker/libnetwork/tree/master/drivers を見る限り、現時点では以下のlibnetwork driverが実装されているようだ。

|ドライバ|備考|
|:--|:--|
|Null|driverが備えるべきAPIの空実装。ネットワークが不要なコンテナの場合に利用する。（従来の `--net=none` に相当）|
|Bridge|Linux Bridgeとiptablesを用いたネットワークを実現。 `docker0` を作り、Endpointとbridge間を `veth pair` で接続する。（デフォルトで用いられるdockerネットワーク  `--net=bridge` に相当）|
|Host|ホストOSのネットワークをそのまま利用する。（従来の `--net=host` に相当）|
|Overlay|VXLANでカプセリングしたオーバーレイネットワークを複数ホスト間に延伸する。|
|Remote|動的に登録されるDriverの接続ポイントとなる。Remoteパッケージ自体はDriverの実装を持たず、libnetworkのpluginとして動作するdriverプロセスへのプロキシを提供する。|

上記以外にもdrivers以下には[windows.go](https://github.com/docker/libnetwork/blob/master/drivers/windows/windows.go)なるコードもあるが、**"TODO Windows. This is a placeholder for now"** とコメントされているだけで中身はnull driverとほぼ同じでしかない。

またWeaveworksの[weave](http://weave.works/)は、libnetworkの[Remote Driver plugin](https://github.com/weaveworks/docker-plugin)を実装しているようである。が、未検証。


## overlay network driverの前提条件

libnetworkのoverlay driverを動作させるためには、以下の環境が必要となる。

* 3.16以上のLinux kernel
    * Ubuntu 14.04 LTSのカーネルは3.13のため、カーネルアップデートが必要
* Experimental Docker Client
    * 正式リリースされている1.8.2のDocker Clientにはlibnetworkを操作するCLIが搭載されていないため、experimental releaseのDockerが必要
* 分散KVS
    * libnetworkのoverlay driverは、NetworkやEndpoint等のメタデータを保持するために[libkv](https://github.com/docker/libkv)を用いる
    * libkvは現時点で次の分散KVSをサポートしている
    * `consul >= 0.5.1` or `etcd >= 2.0` or `zookeeper >= 3.4.5`

# Docker native overlay networkの検証環境の準備

ではここから、SoftLayerのVMを用いてlibnetworkのoverlay driverを検証するための環境を準備する。今回は以下のバージョンで検証を行った。

| |DC|hostname|private IP address (eth0)|private network address|
|:--|:--|:--|:--|:--|
|ホスト1|Dallas9|overlay01|10.121.212.207|10.121.212.192/26|
|ホスト2|Dallas9|overlay02|10.121.212.217|10.121.212.192/26|
|ホスト3|Dallas6|overlay03|10.107.33.254|10.107.33.192/26|

| |version|
|:--|:--|
|distribution|Ubuntu 14.04.3 LTS|
|kernel|3.19.0-30-generic|
|consul|v0.5.2|
|docker|1.9.0-dev, build 93bd57b, experimental|

## カーネルアップデート

SoftLayerではUbuntu 15.04のOSイメージが提供されていないため、14.04 LTSで立ち上げた仮想マシンのカーネルを15.04のカーネルにアップデートする。

```text:全てのホストで最新版(15.04)カーネルにアップデート
root@overlay01:~# apt-get install linux-generic-lts-vivid -y
root@overlay01:~# reboot
```

```text:カーネルのバージョン確認
root@overlay01:~# uname -r
3.19.0-30-generic
root@overlay01:~# cat /etc/lsb-release 
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=14.04
DISTRIB_CODENAME=trusty
DISTRIB_DESCRIPTION="Ubuntu 14.04.3 LTS"
```

## パッケージインストール

全てのホストで必要なパッケージをインストールする。

```text:全てのホストでパッケージをインストール
root@overlay01:~# apt-get update
root@overlay01:~# apt-get upgrade -y
root@overlay01:~# apt-get install curl unzip git build-essential bridge-utils -y
```

（bridge-utilsはネットワークの状態確認のためにインストールするので、overlay networkを動作させるだけならば不要）。

## consulのインストール

今回は分散KVSとしてconsulを利用する。全てのホストに最新版のconsulをインストールする。

```text:全てのホストにconsulのインストール
root@overlay01:~# curl -OL https://dl.bintray.com/mitchellh/consul/0.5.2_linux_amd64.zip
root@overlay01:~# unzip 0.5.2_linux_amd64.zip
root@overlay01:~# mv consul /usr/local/bin/
```

```text:consulのバージョン確認
root@overlay01:~# consul version
Consul v0.5.2
Consul Protocol: 2 (Understands back to: 1)
```

## experimental Dockerのインストール

全てのホストにDockerをソースコードからビルドしてインストールする。

### 公式リリースのDockerをインストール

DockerのソースコードをビルドするためにはDockerが必要なので、まずは公式リリースのDocker（1.8.2）をインストールする。

```text:リリースバージョンのDockerをインストール
root@overlay01:~# curl -sSL https://get.docker.com/ | sh
```

### Dockerのソースコード取得

Dockerのソースコードをgithubからcloneする。

```text:Dockerのソースコードをclone
root@overlay01:~# git clone https://github.com/docker/docker.git
```

### Dockerのビルド

**重要：2015/09/26に、大きな改修が入ったlibnetworkとlibkvがDocker本体に取り込まれ、Dockerデーモンに指定するoverlay networkの設定オプションも変更された。**
**（これまで `--kv-store=consul:localhost:8500` と指定していた分散KVSオプションが、 `--cluster-store=consul://localhost:8500` と指定するようになった等）**

実装が不安定なのかオプションが足りないのか不明だが、2015/10/07の本記事の執筆時点のmasterの最新Commit（0137e3eda2bae42a83cecd967249e4da54f2fa52）では、ホスト間の通信が届かない。

そのため2015/09/26の大規模改修以前のコードで検証を行うことにする。全てのホストで以下の作業を実施する。

```text:大規模改修直前のcommitでDockerをビルド
root@overlay01:~# cd docker/
root@overlay01:~/docker# git checkout -b overlay_test 93bd57b0b21e1a802b80388c8fc034780e3200fc
root@overlay01:~/docker# make DOCKER_EXPERIMENTAL=1 binary
```

### Docker 1.8.2 の無効化

Dockerのビルドが成功すれば最初にインストールした正式リリースのDockerは不要となるため、Dockerデーモンを停止して自動起動しないように設定する。

```
root@overlay01:~/docker# service docker stop
root@overlay01:~/docker# mv /etc/init/docker.conf /etc/init/docker.conf.disable
root@overlay01:~/docker# cd
```

### Experimental DockerへPATHを設定

正式リリースのDockerではなくビルドしたDockerを使うようにPATHを差し替える。

```text:PATHの変更
root@overlay01:~# echo 'PATH=$HOME/docker/bundles/latest/binary:$PATH' >> .bashrc
root@overlay01:~# source .bashrc
root@overlay01:~# which docker
/root/docker/bundles/latest/binary/docker
```

```text:Dockerのバージョン確認
root@overlay01:~# docker --version
Docker version 1.9.0-dev, build 93bd57b, experimental
```

# Docker native overlay networkの検証

構築した検証環境で、Docker native overlay networkの検証を行う。

## consulクラスタの起動

まずはホスト1を起点としてconsulクラスタを構成する（起点はどのホストでも良い）。

### ホスト1

```text:consul起動
root@overlay01:~# rm -rf /tmp/consul
root@overlay01:~# nohup consul agent -server -bootstrap-expect 3 -data-dir=/tmp/consul -node=overlay01 -bind=10.121.212.207 &
```

### ホスト2

```text:consul起動とホスト1へのjoin
root@overlay02:~# rm -rf /tmp/consul
root@overlay02:~# nohup consul agent -server -data-dir=/tmp/consul -node=overlay02 -bind=10.121.212.217 &
root@overlay02:~# consul join 10.121.212.207
```

### ホスト3

```text:consul起動とホスト1へのjoin
root@overlay03:~# rm -rf /tmp/consul
root@overlay03:~# nohup consul agent -server -data-dir=/tmp/consul -node=overlay03 -bind=10.107.33.254 &
root@overlay03:~# consul join 10.121.212.207
```

```text:consulクラスタの確認
root@overlay03:~# consul members
Node       Address              Status  Type    Build  Protocol  DC
overlay03  10.107.33.254:8301   alive   server  0.5.2  2         dc1
overlay01  10.121.212.207:8301  alive   server  0.5.2  2         dc1
overlay02  10.121.212.217:8301  alive   server  0.5.2  2         dc1
```

## dockerデーモンの再起動

**重要：overlay networkの正式リリース時には、本記事とはオプションが異なっている可能性があることに注意**

overlay networkを利用するために、ホスト1を起点とするオプションを指定してDocker デーモンを起動する。

### ホスト1

```text:Dockerデーモン起動
root@overlay01:~# nohup docker daemon --kv-store=consul:localhost:8500 --label=com.docker.network.driver.overlay.bind_interface=eth0 &
```

### ホスト2

```text:dockerデーモン再起動
root@overlay02:~# nohup docker daemon --kv-store=consul:localhost:8500 --label=com.docker.network.driver.overlay.bind_interface=eth0 --label=com.docker.network.driver.overlay.neighbor_ip=10.121.212.207 &
```

### ホスト3

```text:dockerデーモン再起動
root@overlay03:~# nohup docker daemon --kv-store=consul:localhost:8500 --label=com.docker.network.driver.overlay.bind_interface=eth0 --label=com.docker.network.driver.overlay.neighbor_ip=10.121.212.207 &
```

# Docker native overlay networkの動作確認

ここまででDocker native overlay networkを利用する準備が整ったので、実際に動作させてみる。

## overlay networkの構成

どのホストでもかまわないので、Networkを構成する。今回はホスト1から `vn01` という名前のoverlay networkを構成した。`-d overlay` と明示的にドライバを指定しないとbridge driverが使われてしまうので注意。

```text:overlay_networkの構成
root@overlay01:~# docker network create -d overlay vn01
```

構成されたNetworkは、全てのホストで共有されている（bridge、host、noneドライバは最初から構成されているもの）。

```text:ホスト1でnetworkを確認
root@overlay01:~# docker network ls
NETWORK ID          NAME                TYPE
cdba3727e0eb        none                null                
4341bf67e59a        host                host                
e7620c692cb2        bridge              bridge              
1dd2898c340f        vn01                overlay                      
```

```text:ホスト2でnetworkを確認
root@overlay02:~# docker network ls
NETWORK ID          NAME                TYPE
c162794dbd38        bridge              bridge              
1dd2898c340f        vn01                overlay             
59ff56da5d84        none                null                
b0611c74ed57        host                host                              
```

```text:ホスト3でnetworkを確認
root@overlay03:~# docker network ls
NETWORK ID          NAME                TYPE
2a77c13efd4a        none                null                
b89fc8197c12        host                host                
d25d4b617992        bridge              bridge              
1dd2898c340f        vn01                overlay             
```

## Serviceの構成

Networkに対応付けられたEndpointを生成する。

```text:serviceの構成
root@overlay01:~# docker service publish ep01.vn01
```

EndpointとNetworkの組み合わせを意味するServiceも、全てのホストで共有される。

```text:ホスト1でserviceを確認
root@overlay01:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
343a63c0f2c9        ep01                vn01                               
```

```text:ホスト2でserviceを確認
root@overlay02:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
343a63c0f2c9        ep01                vn01                
```

```text:ホスト3でserviceを確認
root@overlay03:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
343a63c0f2c9        ep01                vn01                
```

## ホスト1でコンテナを起動してoverlay networkに接続

ホスト1でコンテナを起動し、作成したEndpointをattachする。

```text:起動したコンテナにEndpointをattach
root@overlay01:~# CID=$(docker run -itd --name=c01 --hostname=c01 ubuntu:14.04)
root@overlay01:~# docker service attach $CID ep01.vn01
```

この段階で、立ち上げたコンテナには「コンテナ起動時に差し込まれた、docker0のbridge networkに接続されたeth0（172.17.0.1/16）」と「serviceをattachした際に差し込まれた、overlay networkに接続されたeth1（172.21.0.1/16）」が存在する。

```text:コンテナのインタフェース
root@overlay01:~# docker exec $CID ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
13: eth0: <BROADCAST,MULTICAST,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.1/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
16: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:ac:15:00:01 brd ff:ff:ff:ff:ff:ff
    inet 172.21.0.1/16 scope global eth1
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe15:1/64 scope link 
       valid_lft forever preferred_lft forever
```

## ホスト2でコンテナを立ち上げ

上記の手順は煩雑なため、接続するNetworkやEndpointを指定してコンテナを直接起動することもできる。指定したNetworkが無ければ自動で作成し、存在すればそのNetworkにEndpointを参加させる。
この場合docker0には接続されず、overlay networkにのみ接続する。

```text:EndpointやNetworkを直接指定してコンテナを起動
root@overlay02:~# CID=$(docker run -itd --name=c02 --hostname=c02 --publish-service=ep02.vn01.overlay ubuntu:14.04)
```

```text:コンテナのインタフェース
root@overlay02:~# docker exec $CID ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
60: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 02:42:ac:15:00:02 brd ff:ff:ff:ff:ff:ff
    inet 172.21.0.2/16 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:acff:fe15:2/64 scope link 
       valid_lft forever preferred_lft forever
```

## ホスト3でコンテナを立ち上げ

ホスト3ではコンテナを２つ起動してみる。

```text:Endpointを直接指定してコンテナを起動
root@overlay03:~# CID1=$(docker run -itd --name=c03 --hostname=c03 --publish-service=ep03.vn01.overlay ubuntu:14.04)
root@overlay03:~# docker exec $CID1 ip addr show eth0 | grep 172.
    inet 172.21.0.3/16 scope global eth0

root@overlay03:~# CID2=$(docker run -itd --name=c04 --hostname=c04 --publish-service=ep04.vn01.overlay ubuntu:14.04)
root@overlay03:~# docker exec $CID2 ip addr show eth0 | grep 172.
    inet 172.21.0.4/16 scope global eth0
```
## serviceの状態確認

今回作成したEndpoint（ep01、ep02、ep03、ep04）が全て同じoverlay network（vn01）に所属していることがわかる。

```text:ホスト1でのserviceの状態
root@overlay01:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
48f088dc0a5e        c01                 bridge              d076a471f6d9
343a63c0f2c9        ep01                vn01                d076a471f6d9
811431a85a34        ep02                vn01                
30cca8a15a6e        ep03                vn01                
de7cffcff55e        ep04                vn01                
```

```text:ホスト2でのserviceの状態
root@overlay02:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
811431a85a34        ep02                vn01                0a8b69b789b3
30cca8a15a6e        ep03                vn01                
de7cffcff55e        ep04                vn01                
343a63c0f2c9        ep01                vn01                
```

```text:ホスト3でのserviceの状態
root@overlay03:~# docker service ls
SERVICE ID          NAME                NETWORK             CONTAINER
343a63c0f2c9        ep01                vn01                
811431a85a34        ep02                vn01                
30cca8a15a6e        ep03                vn01                240323344a8e
de7cffcff55e        ep04                vn01                1820e31ec320
```
## コンテナ間で疎通確認

ホスト1とホスト2は同一Subnet、ホスト3は異なるSubnetに所属している。しかしoverlay networkはホストのネットワーク状況に関わらず、全てのコンテナをL2で接続する。

```text:疎通確認
root@overlay01:~# docker attach $CID

root@c01:/# ip neigh
root@c01:/# ping 172.21.0.1 -c2
PING 172.21.0.1 (172.21.0.1) 56(84) bytes of data.
64 bytes from 172.21.0.1: icmp_seq=1 ttl=64 time=0.035 ms
64 bytes from 172.21.0.1: icmp_seq=2 ttl=64 time=0.036 ms

--- 172.21.0.1 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 999ms
rtt min/avg/max/mdev = 0.035/0.035/0.036/0.006 ms
root@c01:/# ping 172.21.0.2 -c2
PING 172.21.0.2 (172.21.0.2) 56(84) bytes of data.
64 bytes from 172.21.0.2: icmp_seq=1 ttl=64 time=0.657 ms
64 bytes from 172.21.0.2: icmp_seq=2 ttl=64 time=0.271 ms

--- 172.21.0.2 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1000ms
rtt min/avg/max/mdev = 0.271/0.464/0.657/0.193 ms
root@c01:/# ping 172.21.0.3 -c2
PING 172.21.0.3 (172.21.0.3) 56(84) bytes of data.
64 bytes from 172.21.0.3: icmp_seq=1 ttl=64 time=1.65 ms
64 bytes from 172.21.0.3: icmp_seq=2 ttl=64 time=1.66 ms

--- 172.21.0.3 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 1.651/1.657/1.663/0.006 ms
root@c01:/# ping 172.21.0.4 -c2
PING 172.21.0.4 (172.21.0.4) 56(84) bytes of data.
64 bytes from 172.21.0.4: icmp_seq=1 ttl=64 time=1.47 ms
64 bytes from 172.21.0.4: icmp_seq=2 ttl=64 time=1.24 ms

--- 172.21.0.4 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 1.244/1.359/1.474/0.115 ms
root@c01:/# ip neigh
172.21.0.4 dev eth1 lladdr 02:42:ac:15:00:04 REACHABLE
172.21.0.3 dev eth1 lladdr 02:42:ac:15:00:03 REACHABLE
172.21.0.2 dev eth1 lladdr 02:42:ac:15:00:02 REACHABLE
```

# Docker native overlay networkの状態

最後にホストからみたNetwork Namespaceの状態を確認する。
**重要：overlay networkの正式リリース時には、本記事とはネットワークアーキテクチャが異なっている可能性があることに注意**

## ホスト1のネットワーク

ホスト1の `docker0` には、コンテナ起動時に差し込まれたveth pair（コンテナにとってのeth0）の片割れ（ `veth6392365` ）が接続されている。
`docker0` も`veth6392365` も、ホストのネットワークから普通に確認できる（従来のdocker0と同様）。

```text:ホストのdocker0の状態
root@overlay01:~# ip link show docker0
4: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:a2:1e:01:c1 brd ff:ff:ff:ff:ff:ff
root@overlay01:~# brctl show docker0
bridge name	bridge id		STP enabled	interfaces
docker0		8000.0242a21e01c1	no		veth6392365
root@overlay01:~# ip link show veth6392365
14: veth6392365: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP mode DEFAULT group default 
    link/ether 62:bd:22:eb:aa:42 brd ff:ff:ff:ff:ff:ff
root@overlay01:~# ethtool -S veth6392365
NIC statistics:
     peer_ifindex: 13
```

```text:コンテナのeth0の状態
root@overlay01:~# docker exec $CID ip link show eth0
13: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
```

一方overlay networkの情報はSandboxとして隔離されているため、ホストのネットワークには出現しない。libnetworkが作成したNetwork Namespaceを `ip netns` で確認してみると、以下のような状態になっている。

```text:Sandboxの確認
root@overlay01:~# mkdir -p /var/run/netns
root@overlay01:~# ln -s /var/run/docker/netns/2-1dd2898c34 /var/run/netns/overlay
root@overlay01:~# ip netns exec overlay ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: br0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP group default 
    link/ether 3a:37:9d:10:64:38 brd ff:ff:ff:ff:ff:ff
    inet 172.21.255.254/16 scope global br0
       valid_lft forever preferred_lft forever
    inet6 fe80::4c2a:32ff:fecc:4fe4/64 scope link 
       valid_lft forever preferred_lft forever
15: vxlan1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br0 state UNKNOWN group default 
    link/ether 7e:f2:3c:87:de:b2 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::7cf2:3cff:fe87:deb2/64 scope link 
       valid_lft forever preferred_lft forever
17: veth2: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue master br0 state UP group default 
    link/ether 3a:37:9d:10:64:38 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::3837:9dff:fe10:6438/64 scope link 
       valid_lft forever preferred_lft forever
root@overlay01:~# ip netns exec overlay brctl show br0 
bridge name	bridge id		STP enabled	interfaces
br0		8000.3a379d106438	no		veth2
							vxlan1
root@overlay01:~# ip netns exec overlay ethtool -S veth2
NIC statistics:
     peer_ifindex: 16
```

```text:コンテナのeth1の状態
root@overlay01:~# docker exec $CID ip link show eth1
16: eth1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1450 qdisc noqueue state UP mode DEFAULT group default 
    link/ether 02:42:ac:15:00:01 brd ff:ff:ff:ff:ff:ff
```

Network Namespaceで隔離された `br0` には `vxlan1` と `veth2` が接続されており、この `veth2` はコンテナの `eth1` につながっている。
コンテナ間は、この `vxlan1` を経由してL2で接続される。

## ホスト2とホスト3のネットワーク

同様にホスト2とホスト3のSandbox内を確認すると、vxlanとコンテナに接続されるvethが確認できる。

```text:ホスト2のSandbox内のbridge
root@overlay02:~# ip netns exec overlay brctl show br0
bridge name	bridge id		STP enabled	interfaces
br0		8000.523a7d15ed52	no		veth2
							vxlan1
```

```text:ホスト3のSandbox内のbridge
root@overlay03:~# ip netns exec overlay brctl show br0
bridge name	bridge id		STP enabled	interfaces
br0		8000.1e9a6a141297	no		veth2
							veth3
							vxlan1
```

## 注意点

本記事で確認したoverlay driverの実装では、仮想ネットワークのネットワークアドレス（ `172.21.0.0/16` ）を任意に指定することはできない（と思われる）。またコンテナに与えられるIPアドレスも `172.21.0.1/16` からの昇順で、任意に指定する仕組みは準備されていない（と思われる）。

![docker_networking_5_01.png](https://qiita-image-store.s3.amazonaws.com/0/37648/807a38be-6a8a-380d-188a-c67b1c2215eb.png)

# まとめ

docker nativeのoverlay networkを動作させることができた。3rd partyのツールを利用せずともホストを跨ったコンテナ間で通信できるようになることは、今後のDockerの活用シーンをより広げることだろう。

ただし正式にリリースされた際には、指定するオプションやネットワークアーキテクチャが異なる可能性があることに注意が必要である。