Tech Sketch Bucket of Technical Chips by TIS Inc.

マルチホストDockerネットワーキング(2) pipework+GRE

Pocket

Dockerネットワーキングの第二回です。前回はDockerのネットワーク周りを概観し、Dockerをコンテナ型仮想化エンジンとして見た場合のネットワーク周りの問題点について解説しました。今回からは、仮想ネットワーキング技術を用いて複数ホスト上で稼働するコンテナを接続し、Dockerをコンテナ型仮想化エンジンとして使いやすくするDockerネットワーク拡張ツールについて解説します。今回はjpetazzo/pipeworkを取り上げます。

Docker

Dockerをコンテナ型仮想化エンジンとして見た場合に必要なネットワーク機能

Dockerをコンテナ型仮想化エンジンとして使い、コンテナを「仮想マシン」のような単独で動作するサーバとして利用したい場合、以下のような機能を持ったネットワークがあれば便利になります。

  1. L2及びL3で接続された複数ホスト上で稼働するコンテナ間を接続できる
  2. 任意のIPアドレスをコンテナに割り当てられる
  3. コンテナに与えられたIPアドレスで、コンテナ間だけではなくコンテナ外部からも接続できる
  4. DNSやDHCP、あるいはセキュリティグループといった、高度なネットワーク機能をネットワークレイヤが提供できる

世間にはこのようなDockerネットワークの拡張に興味を持っている人は多いようで、jpetazzo/pipeworkcoreos/flannelweaveworksranchersocketplane...と様々なツールが公開されています。

jpetazzo/pipeworkとは

jpetazzo/pipeworkは、様々なDockerネットワーク拡張ツールの中でも最も初期から存在するツールです。以下のような特徴を持っています。

  • Dockerのネットワーク拡張ツールとしてはかなり初期から開発されている(最初のコミットは2013/07)
  • シェルスクリプト一つだけで実現されており、至極シンプル
    • Linuxブリッジもしくはopen vswitchを用いて仮想ブリッジを作成し、network namespaceを用いて任意のIPアドレスをコンテナに割り当てるだけ

ただしjpetazzo/pipeworkは、単一ホスト上で動作することが前提のツールです。複数のホスト上で動作するコンテナを接続したい場合、VXLANやGREなどを用いてパケットをトンネリングして、jpetazzo/pipeworkが作成した仮想ネットワークを他のホストへ延伸する工夫が必要となります。

jpetazzo/pipework + GREでマルチホストDockerネットワーク構築

それでは実際に、jpetazzo/pipework + GREでマルチホストDockerネットワークを動作させてみましょう。 今回は、同じL2セグメント上にある2台のホスト、及びルータを跨いだ異なるL2セグメント上にある1台のホストの、合計3台のホストへ以下の環境を構築して動作検証を行いました。

  • ホストのネットワーク環境
ホストホスト名ネットワークIPアドレス
ホスト1pipework0110.142.51.192/2610.142.51.197
ホスト2pipework0210.142.51.196
ホスト3pipework0310.106.242.0/2610.106.242.2
  • OSとミドルウェアのバージョン
distributionUbuntu 14.04.2 LTS
kernel3.13.0-51-generic
docker1.6.2
pipeworkcommit: 5a1ff19977df4e40f6b82c7b1b86a8d6633a5af9

ホスト間にGREトンネルを作成

まずはGREでパケットのトンネリングを設定します。GRE(Generic Routing Encapsulation)はトンネリングプロトコルの一種で、RFC1701RFC2784で定義されています。

GREのカーネルモジュールのロード

現在のLinuxカーネルは、最初からGREが利用できるようになっています。便利ですね。全てのホストで以下のコマンドを実行し、GREモジュールをロードします。

仮想ブリッジとGREトンネルの作成

今回はMACアドレスなどを含んだイーサネットフレーム全体をカプセル化し、物理的なネットワークを経由して別のホストに届けることで、ホスト間に仮想的なL2セグメントを延伸します。

ただし3台のホスト全てをPeer-to-PeerでGRE接続するとパケットがループしてしまうため、今回はホスト1を中心点としてスター型にトンネルを設定します。

今回作成する仮想ネットワークは192.168.99.0/24とします。 各ホストで生成する仮想ブリッジに与える仮想IPアドレスは、重複しないように注意して設定してください。今回は以下のように設定しました。

ホストホスト名仮想ブリッジに与える仮想IPアドレス
ホスト1pipework01192.168.99.251/24
ホスト2pipework02192.168.99.252/24
ホスト3pipework03192.168.99.253/24
ホスト1で仮想ブリッジとGREトンネル作成
ホスト2で仮想ブリッジとGREトンネル作成
ホスト3で仮想ブリッジとGREトンネル作成

ここまでで、各ホストからGREトンネル経由で仮想ブリッジ全てに通信ができるようになりました。各ホストから192.168.99.251, 192.168.99.252, 192.168.99.253にpingを打ち、仮想ネットワークが動作していることを確認してください。

docker_networking_2_01

Dockerコンテナの起動と仮想IPアドレス付与

それでは以下のように疎通確認用のコンテナを立ち上げます。

ホストコンテナ名仮想IPアドレス
ホスト1server192.168.99.10/24
client1192.168.99.11/24
ホスト2client2192.168.99.21/24
ホスト3client3192.168.99.31/24

Dockerコンテナ起動

以下のコマンドで、serverコンテナとclient1コンテナを起動し、jpetazzo/pipeworkを用いてそれぞれ仮想IPアドレスを付与します。

ホスト1

同様に、ホスト2とホスト3でもclientコンテナを起動して仮想IPアドレスを付与します。

ホスト2

仮想ネットワークの状態

jpetazzo/pipeworkは内部的にveth pairを生成し、一方を指定された仮想ブリッジ(br0)に接続し、他方を指定したコンテナに接続して仮想IPアドレスを割り当てます。このveth pairとGREの働きにより、コンテナ間に仮想ネットワークが敷設されることになります。

※veth pairとは:仮想的なネットワークインタフェースのペアであり、それらがクロスケーブルで接続されているかのように振る舞う。そのため一方のvethに投げ込まれたパケットは、組となっている他方のvethから出てくる。

例えばホスト2では、以下のようなveth pairが生成され、一方(veth1pl3151)がbr0に、他方(eth1)がclient2コンテナに接続されました。

ここまでで、以下のような仮想ネットワークが構築されました。

docker_networking_2_02

疎通確認

では最後に、netcatを用いてTCPの疎通を確認します。

ホストからコンテナへの通信

自ホスト上で動作するコンテナだけでなく、他のホスト上で動作するコンテナへも通信することができます。

コンテナ間の通信

ホストを跨っても、コンテナ間で問題なく通信できます。

コンテナからホストへの通信

各コンテナから、他のホスト上のnetcatサーバに接続することもできます。

まとめ

このようにjpetazzo/pipework + GREを用いることで、マルチホストDockerネットワークが構築できました。この手法はシンプルで、Dockerネットワークがどのように動作しているか目に見えてわかるところが良いのですが、いささか手続きが煩雑であることは否めなせん。

そこで次回は、よりシンプルな手順でマルチホストDockerネットワークを構築できるWeaveworksweaveworks/weaveを取り上げてみます。

エンジニア採用中!私たちと一緒に働いてみませんか?