複数のホストに配置されたコンテナ間のネットワーク通信についてまとめてみる。
(更新: 2015/11/08)
Docker 1.9 では、複数ホストにまたがる仮想ネットワーク機能が正式版としてリリースされました。今後は、この記事で書かれている方法より、そちらの機能を使うほうが主流になるかもしれません。
Docker : マルチホスト間での仮想ネットワーク
マルチホストにおける Docker のネットワークの課題
以下の図で、ホスト1上のContainer1からホスト2上のContainer2(httpdが動作)に接続したいとする。
Container2 が次のように起動している場合、
docker run -d -p 80:80 <イメージ名>
Containe1 からは、「ホスト2のアドレス」を使って 10.0.0.2:80 にアクセスすれば Container2 の httpd と通信ができる。
これはとても単純な方法だがいつくか課題がある。
1. 接続先のコンテナが別のホストで起動された場合、接続先のアドレスが変わってしまう
仮想マシン(VM)の場合は VM自体に割り当てられたIPアドレスに接続するため、VM 別のホストに移動しても接続先のアドレスは変わらない。しかし、上記のコンテナの接続方法では、ホストが変わる度に接続先のアドレスが変わり、接続元コンテナの設定を変えたりコンテナの再起動が必要になる。これは実用に耐えない。
2. コンテナ名で接続できない
同一ホスト間のコンテ間通信であれば Link の機能を使いコンテナ名で接続をすることができたが、マルチホストではIP/ポートの指定が必要になってしまう。
解決方法
かなり多くの手法があるようで把握できてないが、例えば次ようなものがあるらしい。
- 別ホストへ接続するための専用コンテナを介して接続をする
- Ambassador パターン (Static)
- Ambassador パターン (Dynamic)
- コンテナに DHCP や Static IP で IP アドレスを割り当てる
- コンテナ間を接続する仮想ネットワークを構築する
Ambassador パターン(Static) ~ 概要
ここでは、Docker の公式ドキュメントでも紹介されている基本パターンの Ambassador パターンをまとめる。 これは、他のホストと接続する Proxy の役割をするコンテナ(Ambassasdor と呼ばれる)を立てて、それを介して通信する。
Ambassadorは接続先(ホストのIPとポート)を知っており、http client コンテナは Ambassador と Link 接続して、Ambassador に HTTPリクエストを送るとそれが接続先に転送される。
これにより、例えば http client コンテナは接続先を知らなくてもよくなり、また、Ambassador のコンテナ名を使ってHTTPリクエストを送れるようになる。 しかし、Ambassador が接続先ホストを知っている必要がある(Static に紐付けられている)ため、Ambassador だけ再起動すれば済むようにはなったが依然として問題は残る。
いちおう、Ambassador パターンを試す手順を以下にまとめておく。
Ambassador パターン(Static) ~ 手順
事前準備
接続先(ホスト2)で、テスト用イメージ(Webサーバー)を作成。
Dockerfile を作る。
FROM centos:6.6
MAINTAINER arturias <arturias@example.com>
RUN yum install httpd -y
EXPOSE 80
ENTRYPOINT /usr/sbin/apachectl -DFOREGROUND
イメージをビルド。
$ docker build -t arturias/httpd .
接続先(ホスト2)でのコンテナ起動
作成したWeb サーバーのイメージから、コンテナを起動。
※ -p や -P は指定してないことに注意。
$ docker run -d --name web arturias/httpd
次に、Ambassador を起動。Ambassador として動作するイメージ(svendowideit/ambassador)が公開されているのでそれを使っている。
※ なお、ここでは -p でポート80を公開する。
$ docker run -d --link web:web -p 80:80 --name web_amb svendowideit/ambassador
接続元(ホスト1)でのコンテナ起動
Ambassador を起動。--export でHTTPクライアントに公開するポート、-e で接続先の Ambassador を指定。
$ docker run -d --name web_amb --expose 80 -e WEB_PORT_80_TCP=tcp://10.0.0.2:80 svendowideit/ambassador
HTTPクライアントとなるコンテナを起動して接続する。
$ docker run -it --link web_amb:web centos /bin/bash
LINK 機能により環境変数がセットされるため、それを使って Ambassador にリクエストを送る。
[root@2778fe65cd9b /]# env
WEB_PORT=tcp://172.17.0.3:80
WEB_PORT_80_TCP=tcp://172.17.0.3:80
WEB_PORT_80_TCP_ADDR=172.17.0.3
WEB_PORT_80_TCP_PORT=80
(略)
[root@2778fe65cd9b /]# curl http://${WEB_PORT_80_TCP_ADDR}:${WEB_PORT_80_TCP_PORT}