Docker multi host ネットワーク
今までDocker の--link
機能を使うことで、同一ホスト内のコンテナの名前解決をして同一ネットワークのコンテナに対してアクセスすることは可能でしたが、それが複数の異なるDocker ホストになると--link
機能では実現することができませんでした。
そこでDocker のmulti ホストネットワーク及びDocker overlay ネットワークの機能を使用することで異なるホスト上にあるコンテナに対して、あたかも同じネットワーク上に存在しているコンテナのように、便利にアクセスすることができるようになります。
この機能を使うことにより今まで以上に大規模なDocker コンテナ環境を構築することができるようになります。
また、今回構築するDocker multi ホストネットワーク環境では、overlay network 及びDocker ホストのディスカバリにkey value ストアを使用するため、Docker ホストが異なるL3 ネットワーク上及び異なる拠点やデータセンタにある場合でも、それぞれのDocker ホスト上のコンテナは同じネットワーク上に存在するものとして容易にアクセスすることができるようになります。
ネットワークの構成
今回構築するDocker multi host ネットワーク環境は次のようになります。
今回はそれぞれのDocker ホストが同じネットワーク上(192.168.1.0/24) にありますが、もちろんこれらは異なるネットワーク上に属していても問題ありません。
- Docker マルチホスト構成
ホスト名 Docker ホスト側のIP OS Docker ホストのDocker version 備考 client 192.168.1.121 Ubuntu 15.10 - Docker 管理用ワークステーション(兼Swarm マネージャ) consul01 192.168.1.140 Debian strech 1.10.1 Docker クラスタの管理情報を扱うkey value ストア swmgr01 192.168.1.121 Debian strech 1.10.1 Docker Swarm cluster のマネージャ(兼管理用ワークステーション) swagt01 192.168.1.141 Debian strech 1.10.1 Docker Swarm cluster のエージェント1 号機 swagt02 192.168.1.142 Debian strech 1.10.1 Docker Swarm cluster のエージェント2 号機 swagt03 192.168.1.143 Debian strech 1.10.1 Docker Swarm cluster のエージェント3 号機
Key-value ストア(consul)の作成
Docker ホストのメタ情報を格納する格納するために、key-value データストアのconsul を準備します。
このkey-value データストアにはディスカバリ情報、エンドポイント、IP アドレスなどの情報が格納され、クラスタに参加しているDocker ホストが同じクラスタ内の他Docker ホストを検索するのに利用されます。
Docker ではConsul, Etcd, ZooKeeper といったkey-value データストアをサポートしていますが、今回はConsul を使用していきます。
Consul はDocker イメージが幾つか既に用意されているので、その中の一つであるprogrium/consul
利用することにします。
consul01~# docker run -d -p 8500:8500 --name consul01 -h consul01 progrium/consul -server -bootstrap
上記コマンドを実行することで、consul が8500 番ポートでListen するようになります。
docker ps
コマンドでconsul コンテナが起動していることを確認します。
consul01~# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
463ad77b47ce progrium/consul "/bin/start -server -" 11 minutes ago Up 11 minutes 53/tcp, 53/udp, 8300-8302/tcp, 8400/tcp, 8301-8302/udp, 0.0.0.0:8500->8500/tcp consul01
Swarm cluster を構築する
次に、Docker Swarm manager コンテナをswmgr01 ホストに作成します。
ここではmanager を作成するときにディスカバリサービスとしてconsul を使うように指定します。
consul をディスカバリサービスとして指定するには、swarm コンテナを起動するときにconsul://<consul ip>:8500
と指定するようにします。
$ docker run -d -p 2375:2375 --name swmgr01 swarm manage consul://192.168.1.140:8500/my_cluster
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
ff1fe5e04017 swarm "/swarm manage consul" 3 seconds ago Up 2 seconds 0.0.0.0:2375->2375/tcp swmgr01
Docker Swarm agent のDocker daemon の設定
各agent のDocker daemon が外部からのDocker コマンドを受け付けるようにするために、daemon 起動時に-H
オプションでtcp://0.0.0.0:2375
を指定するようにします。
また--cluster-store
でconsul を指定し、--cluster-advertise
でagent のDocker daemon のInterface (もしくはIP) とport を指定します。
起動時のオプションを変更するには/lib/systemd/system/docker.service
ファイルを編集します。
ExecStart=/usr/bin/docker daemon -H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock --cluster-store=consul://192.168.1.140:8500/my_cluster --cluster-advertise=eno16777736:2375
systemctl ファイルを書き換えたら、daemon-reload
を実行して修正を反映し、Docker daemon を再起動させます。
# systemctl daemon-reload
# systemctl restart docker
Docker Swarm agent をクラスタに参加させる
Docker Swarm manager を構築したら、次にDocker Swarm agent をクラスタに参加させて行きます。
こちらもDocker Swarm manager コンテナを起動した時と同様にディスカバリサービスとしてconsul
を使うように指定します。
swagt01~# docker run --name swagt01 -d swarm join --addr=192.168.1.141:2375 consul://192.168.1.140:8500/my_cluster
swagt02~# docker run --name swagt02 -d swarm join --addr=192.168.1.142:2375 consul://192.168.1.140:8500/my_cluster
swagt03~# docker run --name swagt03 -d swarm join --addr=192.168.1.143:2375 consul://192.168.1.140:8500/my_cluster
Docker ID が重複することによるエラー
今回、Swarm agent の各ノードを、VM のコピー/クローンを使って作成した場合、Docker Swarm manager コンテナに次のようなエラーが出ることがあります。
time="2016-02-06T06:00:15Z" level=error msg="ID duplicated. XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXX:XXXXshared by 192.168.1.141:2375 and 192.168.1.142:2375"
Docker daemon は初回起動時にID を作成しますが、そのID が他のDocker daemon のID と重複しまうことによるエラーです。
もしこのようなエラーが出てしまった場合は、それぞれのDocker ID ファイル(~/.docker/key.json もしくは/root/.docker/key.json もしくは/etc/docker/key.json)を削除してからDocker daemon を再起動するようにしてください。
# rm -f /etc/docker/key.json
# systemctl restart docker
# docker info
...
ID: YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY:YYYY
...
cluster ノードの検索
各agent をDocker Swarm cluster へ参加させたら、consul
から各Docker Swarm agent が検索できることを確認してみましょう。
swmgr01~$ docker run --rm swarm list consul://192.168.1.140:8500/my_cluster
192.168.1.141:2375
192.168.1.142:2375
192.168.1.143:2375
次にDocker Swarm manager コンテナにdocker info
コマンドを実行してDocker Swarm agent がcluster に参加しているコンテナを確認します。
docker info
コマンドを実行するときは、-H
オプションの接続先としてDocker Swarm manager を指定するようにします。
$ docker -H tcp://192.168.1.121:2375 info
...
Nodes: 3
swagt01: 192.168.1.141:2375
└ Status: Healthy
└ Containers: 1
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 2.038 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.3.0-1-amd64, operatingsystem=Debian GNU/Linux stretch/sid (containerized), storagedriver=devicemapper
swagt02: 192.168.1.142:2375
└ Status: Healthy
└ Containers: 1
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 2.038 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.3.0-1-amd64, operatingsystem=Debian GNU/Linux stretch/sid (containerized), storagedriver=devicemapper
swagt03: 192.168.1.143:2375
└ Status: Healthy
└ Containers: 1
└ Reserved CPUs: 0 / 2
└ Reserved Memory: 0 B / 2.038 GiB
└ Labels: executiondriver=native-0.2, kernelversion=4.3.0-1-amd64, operatingsystem=Debian GNU/Linux stretch/sid (containerized), storagedriver=devicemapper
...
上記のように検索できれば成功です。
overlay network の作成
docker network
コマンドを使ってswmgr01 コンテナにoverlay ネットワークを作成します。
overlay ネットワークを作成するコンテナは、cluster に参加しているいずれか1 つののコンテナで構いません。
今回は、manager コンテナにoverlay network を作成します。
$ docker -H tcp://192.168.1.121:2375 network create --driver overlay --subnet=10.0.9.0/24 my_network
Docker overlay network を作成したら、docker network ls
コマンドを使ってクラスタ上のネットワークドライバの一覧を確認してみましょう。
$ docker -H tcp://192.168.1.121:2375 network ls
NETWORK ID NAME DRIVER
474350b5f95f swagt01/bridge bridge
f018be332b12 swagt02/none null
2279a690f4e6 swagt02/host host
4bebe4cbca4a swagt03/host host
c93572ec1940 swagt03/bridge bridge
7aa32976023f swagt01/host host
5ec158206a76 swagt01/none null
0050af5c7580 my_network overlay
139094363b1e swagt02/bridge bridge
d3f2a409061e swagt03/none null
出力された結果を見ると、全agent 上のネットワークドライバが表示されます。
しかしoverlay network については全cluster 上で1 つのみ存在していることが確認できます。
次にそれぞれのagent に個々に接続してdocker network ls
コマンドを実行してみましょう。
$ docker -H tcp://192.168.1.141:2375 network ls
NETWORK ID NAME DRIVER
0050af5c7580 my_network overlay
9e68da7fa173 bridge bridge
97d2a09b9fbb none null
22c27ff26d8b host host
$ docker -H tcp://192.168.1.142:2375 network ls
NETWORK ID NAME DRIVER
0050af5c7580 my_network overlay
33276c8c59b6 bridge bridge
1d54daad8fce none null
90768ae10d86 host host
$ docker -H tcp://192.168.1.143:2375 network ls
NETWORK ID NAME DRIVER
0050af5c7580 my_network overlay
2e5fff12a678 host host
80caae61efdd bridge bridge
6e5b95a64480 none null
そうするとそれぞれのagent にoverlay network が同じID 表示されることが確認できるはずです
このような状態になっていればoverlay network の作成は成功です。
以上でDocker multi host networking 環境の構築は完了です。
--subnet でサブネットを指定する必要性について
--subnet
オプションでoverlay network のネットワークアドレスを指定していますが、この指定を無くすとDocker daemon が自動的にネットワークアドレスを割り当ててくれます。
しかし、これは場合によってはDocker によって管理されていないネットワークアドレスをoverlay network に割り当てることもあるので、特に理由がない限りは明示的に安全なネットワークアドレスを指定するようにしてください。
動作確認
では実際にcluster 上にコンテナを作成し、異なるDocker host 上のコンテナにコンテナ名を指定することでアクセスできることを確認してみましょう。
コンテナを起動するときは、--net
オプションでoverlay network ドライバmy_network
を指定する点に注意してください。
まずは1 つ目のコンテナを作成してみます。
$ docker -H tcp://192.168.1.121:2375 run --name=busybox01 --net=my_network -d -ti busybox /bin/sh
1 つ目のコンテナを作成したらどのDocker ホスト上で作成されたかを確認してみましょう。
$ docker -H tcp://192.168.1.121:2375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
be748478527d busybox "/bin/sh" 4 seconds ago Up 2 seconds swagt02/busybox01
1 つ目のコンテナはswagt02
上に作成されました。
それでは2 つ目のコンテナをcluster 上に作成してみましょう。
$ docker -H tcp://192.168.1.121:2375 run --name=busybox02 --net=my_network -d -ti busybox /bin/sh
$ docker -H tcp://192.168.1.121:2375 ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
03c2ff579a90 busybox "/bin/sh" 3 seconds ago Up 2 seconds swagt03/busybox02
be748478527d busybox "/bin/sh" 52 seconds ago Up 50 seconds swagt02/busybox01
2 つ目のコンテナはswagt03
上に作成されました。
次にbusybox02(on swagt03)
にattach してbusybox01(on swagt02)
を名前解決できてアクセスできることを確認してみましょう。
$ docker -H tcp://192.168.1.121:2375 attach busybox02
/ # ping busybox01
PING busybox01 (10.0.9.2): 56 data bytes
64 bytes from 10.0.9.2: seq=0 ttl=64 time=0.526 ms
64 bytes from 10.0.9.2: seq=1 ttl=64 time=0.792 ms
64 bytes from 10.0.9.2: seq=2 ttl=64 time=0.801 ms
^C
--- busybox01 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.526/0.706/0.801 ms
ping コマンドを実行するとbusybox01
が名前解決されて異なるDocker ホスト上にあるコンテナから応答があることがわかります。
参考
- Get started with multi-host networking
- https://docs.docker.com/engine/userguide/networking/get-started-overlay/
- マルチホストDockerネットワーキング(native overlay)
- http://qiita.com/nmatsui/items/3ed2f21f7ee61d0827ea
- Virtual Ethernet Tunnel (veth) の組を知りたい
- http://thatsdone-j.blogspot.jp/2013/05/linux-veth-pairs.html
- Linux Switching – Interconnecting Namespaces
- http://www.opencloudblog.com/?p=66
- Docker Swarm Discovery
- https://docs.docker.com/swarm/discovery/
- Build a Swarm cluster for production
- https://docs.docker.com/swarm/install-manual/
- Swarm Manager errors seen #380
- https://github.com/docker/swarm/issues/380
- Failed to create the network with overlay driver type #17647
- https://github.com/docker/docker/issues/17647