Edited at

Docker : マルチホスト間での仮想ネットワーク

More than 3 years have passed since last update.


概要

Docker 1.9 で正式版になったマルチホストネットワーク機能を使ってみたのでまとめます。

この機能では、複数のホストにまたがる仮想ネットワークを構築でき、コンテナはどこのホスト上で動いているかに関わらず、仮想ネットワークを経由して他のコンテナと通信することができます。

今回は下図のように、2台のホスト上のコンテナが仮想ネットワークを通じて通信できるようにしました。

DockerNetwork.png

マルチホストネットワークの要件


  • マルチホストネットワークを使うには、複数のホストにまたがる Key/Value ストアが必要になりますが(図の Consul がそれに相当)、これについては後述します

  • ホストの Linux Kernel は 3.16 かそれ以降が必要になります

今回の検証環境


  • Host: Ubuntu 15.10 (Kernel 4.2.0)

  • Docker Version: 1.9.0


手順


Docker 1.9 のインストール

2台のホスト上で、それぞれ以下を実行します。


Host1&Host2

# Docker Engine の最新版をインストール

$ curl -sSL https://test.docker.com/ | sh

# Docker デーモンが動いていたら停止しておく。後で、デフォルトとは異なるパラメータを付けて開始するため。
$ sudo service docker stop

# docker コマンドを実行するたびに sudo を打つのが面倒なので、以下のコマンドを実行して再ログインする。
$ sudo usermod -aG docker <username>



Consul のインストールと起動

複数のホストにまたがる仮想ネットワークを作成する場合は、ホスト間でネットワークの情報を共有するために 分散Key/Value ストアのクラスターが必要になります。

Docker 1.9 では Consul, etcd, ZooKeeper が利用できるようですが、今回は Consul を使いました。Consul は、Vagrant や Packer を開発している HashiCorp が提供している Key/Value ストアです。

まずは、両方のホストで consul をダウンロード。


Host1&Host2

# ダウンロード

$ wget https://releases.hashicorp.com/consul/0.5.2/consul_0.5.2_linux_amd64.zip

# もし unzip コマンドが入ってなければインストールしておく
$ sudo apt-get install unzip

# consul を解凍してコピー
$ unzip consul_0.5.2_linux_amd64.zip
$ sudo cp consul /usr/local/bin/


Host1 側で consul をサーバーとして起動。


Host1

consul agent -server -bootstrap -data-dir=/tmp/consul -bind=100.74.14.78


Host2 側の consul をクラスターに参加させる。


Host2

consul agent -data-dir=/tmp/consul -bind=100.74.120.62 -join=100.74.14.78


別のターミナルから両ホストにSSH接続して、以下のコマンドを実行。クラスタが形成されたか確認しておきます。


Host1&Host2

$ consul members

Node Address Status Type Build Protocol DC
Ubuntu1 100.74.14.78:8301 alive server 0.5.2 2 dc1
Ubuntu2 100.74.120.62:8301 alive client 0.5.2 2 dc1


Docker デーモンの起動

Key/Value ストアのクラスターが構成できたので、それを指定して Docker デーモンを起動します。引数は以下になります。


  • --cluster-store : Key/Value のクラスタ

  • --cluster-advertise : 自分自身の IP/Port を指定します。


Host1

$ sudo docker daemon --cluster-store=consul://localhost:8500 --cluster-advertise=100.74.14.78:2376



Host2

$ sudo docker daemon --cluster-store=consul://localhost:8500 --cluster-advertise=100.74.120.62:2376



ネットワークの作成

また新しいターミナルを起動して、まずはデフォルトで作成されているネットワークを確認します。どちらも、bridge, null, host の3つのネットワークがあることが分かります。


Host1

$ docker network ls

NETWORK ID NAME DRIVER
3db3635076e3 bridge bridge
1f616c6c3c34 none null
e459697f7cb8 host host


Host2

$ docker network ls

NETWORK ID NAME DRIVER
a629ccb5fbba bridge bridge
2802d9ae3067 none null
42b1f2f3d2bd host host

ここで、Host1 側だけで 新しいネットワークを作成します。


Host1

$ docker network create -d overlay TestNetwork

60231ea6adf2c36cafe68ddc5ee0548fbae034a812b988c3e018b41b1cc66278

すると、Host1 と Host2 の両方で、今作成した TestNetwork というネットワークが見えます。


Host1

$ docker network ls

NETWORK ID NAME DRIVER
60231ea6adf2 TestNetwork overlay
3db3635076e3 bridge bridge
1f616c6c3c34 none null
e459697f7cb8 host host


Host2

$ docker network ls

NETWORK ID NAME DRIVER
60231ea6adf2 TestNetwork overlay
a629ccb5fbba bridge bridge
2802d9ae3067 none null
42b1f2f3d2bd host host


コンテナの作成とコンテナ間の通信

仮想ネットワークが作成できたので、いよいよネットワーク上にコンテナを作成します。


Host1

# コンテナを起動

$ docker run -it --net=TestNetwork --name=Container1 ubuntu /bin/bash

# コンテナの中で ifconfig を実行してIPアドレスを確認
root@27f699b0d97c:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:0a:00:00:02
inet addr:10.0.0.2 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::42:aff:fe00:2/64 Scope:Link
(中略)

eth1 Link encap:Ethernet HWaddr 02:42:ac:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
(中略)



Host2

# コンテナを起動

$ docker run -it --net=TestNetwork --name=Container2 ubuntu /bin/bash

# コンテナの中で ifconfig を実行してIPアドレスを確認
root@6b4baee6e4d0:/# ifconfig
eth0 Link encap:Ethernet HWaddr 02:42:0a:00:00:03
inet addr:10.0.0.3 Bcast:0.0.0.0 Mask:255.255.255.0
inet6 addr: fe80::42:aff:fe00:3/64 Scope:Link
(中略)

eth1 Link encap:Ethernet HWaddr 02:42:ac:12:00:02
inet addr:172.18.0.2 Bcast:0.0.0.0 Mask:255.255.0.0
inet6 addr: fe80::42:acff:fe12:2/64 Scope:Link
(中略)


どちらのコンテナにも 172.18.0.2 という IP のほかに、10.0.0.x という IP が割り当たっています。この 10.0.0.x が、仮想ネットワークに接続されている IP アドレスになります。


ping での通信

では、Container1(10.0.0.2) から Container2(10.0.0.3) に通信してみます。IP でもコンテナ名でも Ping が送れることが分かります。


Container1

# IP で ping を送る

root@27f699b0d97c:/# ping 10.0.0.3
PING 10.0.0.3 (10.0.0.3) 56(84) bytes of data.
64 bytes from 10.0.0.3: icmp_seq=1 ttl=64 time=1.11 ms
64 bytes from 10.0.0.3: icmp_seq=2 ttl=64 time=0.806 ms
・・・

# コンテナ名で ping を送る
root@27f699b0d97c:/# ping Container2
PING Container2 (10.0.0.3) 56(84) bytes of data.
64 bytes from Container2 (10.0.0.3): icmp_seq=1 ttl=64 time=0.661 ms
64 bytes from Container2 (10.0.0.3): icmp_seq=2 ttl=64 time=1.61 ms
・・・

# コンテナ名.ネットワーク名 で ping を送る
root@27f699b0d97c:/# ping Container2.TestNetwork
PING Container2.TestNetwork (10.0.0.3) 56(84) bytes of data.
64 bytes from Container2 (10.0.0.3): icmp_seq=1 ttl=64 time=1.00 ms
64 bytes from Container2 (10.0.0.3): icmp_seq=2 ttl=64 time=0.767 ms
・・・



HTTP での通信

次に HTTP で通信してみます。

まず、Container1 内に HTTP サーバーを入れます。


Container1

# apache のインストールと開始

root@27f699b0d97c:/# apt-get install apache2
root@27f699b0d97c:/# service apache2 start

# HTML ファイルの作成しておく
root@27f699b0d97c:/# echo "Hello, I'm Container1." > /var/www/html/test.html


Container2 から HTTP サーバーにアクセスすると、ちゃんと応答が返ってきます。


Container2

# コンテナ名で HTTP リクエストを送る

root@6b4baee6e4d0:/# curl http://Container1/test.html
Hello, I'm Container1.

マルチホストネットワーク機能を使わない場合は、docker run コマンドの -p, -P オプションでポートの公開をする必要がありましたが、マルチホストネットワークではそれも不要のようです。


参考サイト