【Dockerの最新機能を使ってみよう】マルチホストネットワークで複数ホスト間を繋ぐ仮想ネットワークを作る

 新たなサーバー環境構築ツールとして普及が始まっているDockerは、その開発も積極的に行われている。そこで本連載記事では、4回に渡って最近Dockerに実装された新機能について紹介していく。まず第1回となる今回は、Dockerのネットワーク周りの新機能について紹介する。

進化しているDockerのネットワーク機能

 DockerはLinuxカーネルが持つ名前空間(namespace)機構を使い、プロセスやリソースを隔離するツールとして開発が始められた。そのような背景もあってか、開発当初はネットワーク関連機能としては仮想ブリッジとiptablesを使ったパケットルーティング程度の機能しか備えられていなかった。そのため、Dockerを使ってコンテナを動かすマシン(Dockerホスト)を複数台用意して動かすような環境の場合、別途仮想ネットワーク構築ツールを用意する必要があった。

 この状況が変わり始めたのが、2015年6月16日にリリースされたバージョン1.7からである。バージョン1.7ではネットワークスタックがリライトされて「libnetwork」という別モジュールに分離されると同時に、異なるDockerホストをまたぐ仮想ネットワークの構築機能の実験的実装がDockerに追加された。2015年11月3日にリリースされたバージョン1.9ではこの仮想ネットワーク機能が正式な機能となり、ついにDocker単独での仮想ネットワーク構築が可能となった。2016年2月4日にリリースされたDocker 1.10では従来はbridgeネットワークでのみ利用できたリンク機能がほかのネットワークでも利用可能になり、また外部ネットワークと通信できない「内部ネットワーク」を作成できるようになるなど、ネットワーク関連機能が強化されている。

Dockerのネットワーク機能の基本

 このように機能強化が進められているDockerのネットワーク機構であるが、その基本となるのはブリッジを使った仮想ネットワークだ。まずはこのブリッジによる仮想ネットワークについて、そのデフォルトの動作を簡単に説明しておこう。

 DockerではDockerホスト上に仮想ブリッジを利用してネットワークの端点を作り、それをコンテナの仮想ネットワークインターフェイスに仮想的に接続することで、コンテナとのネットワーク通信を可能にしている(図1)。

図1 仮想ブリッジを使用したコンテナネットワーク
図1 仮想ブリッジを使用したコンテナネットワーク

 Dockerホスト上で作成されているネットワークブリッジは、brctlコマンドで確認できる。

# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02429125675e       no
docker_gwbridge         8000.0242ef401d36       no

 これらネットワークブリッジにはそれぞれIPアドレスが割り当てられており、これを経由してコンテナとの通信が行われる。先の例では、以下のように「docker0」ブリッジには172.17.0.1/16、「docker_gwbridge」には172.18.0.1/16というIPアドレスが割り当てられていることが確認できる。

# ip a
  
  
3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:91:25:67:5e brd ff:ff:ff:ff:ff:ff
    inet 172.17.0.1/16 scope global docker0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:91ff:fe25:675e/64 scope link
       valid_lft forever preferred_lft forever
70: docker_gwbridge: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default
    link/ether 02:42:ef:40:1d:36 brd ff:ff:ff:ff:ff:ff
    inet 172.18.0.1/16 scope global docker_gwbridge
       valid_lft forever preferred_lft forever
    inet6 fe80::42:efff:fe40:1d36/64 scope link
       valid_lft forever preferred_lft forever

 この環境で新たに仮想マシンを作成すると、新たにdocker0ブリッジに接続された仮想ネットワークインターフェイスが作成される。この仮想ネットワークインターフェイスはコンテナの仮想ネットワークインターフェイスに対応付けられており、コンテナへのパケットの出入りはこの仮想ネットワークインターフェイスを経由して行われる。

 たとえば、次のようにして新たなコンテナを作成してみよう。なおここで作成している「busybox」コンテナは、最小限のシェル環境を備えるコンテナだ。

# docker run -ti --rm busybox

 すると、Dockerホスト上では次のような仮想ネットワークインターフェイスが新たに作成される。

# ip a
  
  
180: veth7044735@if179: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master docker0 state UP group default
    link/ether ae:9a:34:77:96:e9 brd ff:ff:ff:ff:ff:ff link-netnsid 13
    inet6 fe80::ac9a:34ff:fe77:96e9/64 scope link
       valid_lft forever preferred_lft forever

 brctlコマンドで確認すると、この仮想ネットワークインターフェイスがdocker0ブリッジに接続されていることが分かる。

# brctl show
bridge name     bridge id               STP enabled     interfaces
docker0         8000.02429125675e       no              veth7044735
docker_gwbridge         8000.0242ef401d36       no

 コンテナ内でネットワークインターフェイスに割り当てられたIPアドレスを確認すると、docker0ブリッジと同じネットワークに属する172.17.0.2/16というIPアドレスが割り当てられていることが分かる。

/ # ip a
  
  
179: eth0@if180: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue
    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

 Dockerホスト上で複数のコンテナを起動した場合、これと同様にそのコンテナに対応する仮想ネットワークインターフェイスが作成され、それがdocker0ブリッジに接続される。この場合、すべてのコンテナは同一の仮想ネットワーク内に存在するため、コンテナ同士はこの仮想ネットワークを通じて通信でき、さらにコンテナ-ホスト間の通信も可能となる。しかし、Dockerホストが複数存在する場合、デフォルトでは各Dockerホスト上に構築された仮想ネットワーク同士は接続されていないため、異なるDockerホスト上にあるコンテナはそのままではお互いに通信は行えない(図2)。

図2 ブリッジネットワークの場合、異なるDockerホスト上にあるコンテナ同士はそのままでは通信できない
図2 ブリッジネットワークの場合、異なるDockerホスト上にあるコンテナ同士はそのままでは通信できない

 そのため、異なるDockerホスト上にあるコンテナ間で通信を行いたい場合はコンテナの起動時に「-p」オプションを使用してDockerホストからのポートフォワーディングを利用するか、flannelなどの仮想ネットワーク構築ソフトウェアを使って別途複数のDockerホストにまたがる仮想ネットワークを構築する必要があった。

Docker 1.9で導入されたマルチホストネットワーク機能

 Docker 1.9ではネットワーク機能が刷新され、新たに複数のDockerホストにまたがる仮想ネットワークを構築・管理する機構であるマルチホストネットワーク機能が導入された。マルチホストネットワーク機能は「ドライバ」と呼ばれるプラグイン形式で実装されており、さらに仮想ネットワーク技術であるVXLANベースでマルチホストネットワークを実現するドライバも標準で提供されるようになった。これによって、従来は別途用意する必要があったDockerホスト間を繋ぐ仮想ネットワークをDocker単体で実現できるようになったのである(図3)。

図3 VXLANベースの仮想ネットワークを構築することで、異なるDockerホスト上にある仮想ネットワークを接続されているように扱える
図3 VXLANベースの仮想ネットワークを構築することで、異なるDockerホスト上にある仮想ネットワークを接続されているように扱える

 なお、Docker標準のマルチホストネットワークドライバ(「overlay」ドライバ)以外のドライバを利用することも可能だ。これらのうちいくつかはDocker公式ドキュメントのプラグインページに掲載されているが、Dockerクラスタ構築支援ツールを提供するWeaveによるものや、ポリシーベースのコンテナ向けネットワーク/ストレージを提供するContivが提供するもの、IaaS型クラウド構築ソフトウェア「OpenStack」の仮想ネットワーク管理機構を利用する「Kuryr」などがすでにリリースされている。