Docker1.9のマルチホストネットワーク
Dockerとはそもそも、dotCloud社(現Docker社)が自社のPaaSを構成するパーツのうち、アプリケーション実行環境をイメージとして標準化し、そのイメージから実際の実行環境を素早く提供するための仕組みをOSS化したものだ。そのため、現在Docker Engineと呼ばれている「アプリケーションの実行環境を、Dockerイメージから素早くコンテナとして立ち上げるDockerのコア機能」には独特のクセがあり、初学者を悩ませる。今回は、代表的な悩みの一つであるDockerのネットワークについて、最新リリース(1.9)で導入されたマルチホストネットワーク機能についても触れながら掘り下げる。
従来のDockerのネットワーク
まずは、従来から利用されているDockerのネットワークを見ていこう。
Dockerネットワーク(bridgeモード)の実装
Dockerがデフォルトで利用するbridgeネットワークは、次のような手順で動作している。
- Dockerデーモン起動
ホストOSのネットワークスタックにdocker0という仮想ブリッジを作成
docker0に接続したコンテナから外部ネットワークへ出ていけるように、ホストOSのNetfilterにIPマスカレードルールを追加 - Dockerコンテナ起動
Dockerコンテナ専用のNetwork Namespaceを作成
vethペアを作成し、一方をdocker0へ、もう一方をDockerコンテナに割り当てられたNetwork Namespaceへ接続 - Dockerコンテナに割り当てられた仮想NICへ、Dockerデーモンが既存のDockerコンテナと重複しないIPアドレスを付与(現在の実装ではDHCPなどは用いず、単なる昇順でIPアドレスを割り当てている)
- Dockerコンテナ起動時にオプションとして指定されていれば、外部ネットワークからDockerコンテナの特定ポートに接続できるように、ホストOSのNetfilterにDNATルールを追加
※vethペア:Linuxカーネルに搭載された機能で、一対の仮想的なイーサネットインターフェース(仮想NIC)を仮想的なクロスケーブルで接続したものとして働く。vethペアの一方の仮想NICに投入されパケットは、もう一方の仮想NICから出てくる。
※仮想ブリッジ:Linuxカーネルに搭載された、ホストOS内に仮想的なL2スイッチを作成する機能。同じ仮想ブリッジに接続された仮想NICや物理NICは、仮想ブリッジを経由してお互いにパケットを交換できる。
※Network Namespace:Linuxカーネルに搭載された機能で、ホストOSのネットワークから隔離された独立したネットワークスタックを構成するもの。あるNetwork Namespace内に作られた仮想NICや仮想ブリッジは、ホストOSや他のNetwork Namespaceからは見えなくなる。
※Netfilter:Linuxカーネルに実装された、設定したルールに従ってパケットフィルタリングやネットワークアドレス変換機能を実現するフレームワーク。iptablesコマンドを用いて制御する。
なおDockerコンテナ起動時に「--net」オプションで明示的に指定すれば、仮想ブリッジやNetwork Namespaceを使わずホストOSのネットワークスタックをそのまま利用したり(hostモード)、他のDockerコンテナに割り当てられているネットワークスタックに相乗りしたり(containerモード)することもできるが、本稿では詳細な解説は割愛する。
同一ホスト内でのDockerコンテナ連携(bridgeモード)
上記のような手順で、Dockerコンテナは仮想ブリッジdocker0に接続され、付与されたIPアドレスを用いてDockerコンテナ間の通信が可能になる。
ただしdocker0が利用するネットワークアドレスを指定することはできるが、どのようなIPアドレスをDockerコンテナに付与するかは、Dockerデーモンに一任されている。
そのため、利用者はDockerコンテナに付与されるであろうIPアドレスを事前に知ることはできないし、DHCPサーバがDockerコンテナへIPアドレスを割り当てることも、利用者が静的にIPアドレスを指定することもできない。これはDockerの初学者をよく悩ませるポイントの一つである。
実はDockerコンテナ起動時に「--link」オプションで他のコンテナを指定すると、そのDockerコンテナのIPアドレスや公開ポート等の情報が「/etc/hosts」や環境変数に埋め込まれた状態で、Dockerコンテナが立ち上がる。また「--publish(もしくは-p)」オプションを用いれば、起動したDockerコンテナの特定ポートをホストOSのネットワークに公開することもできる。
これらの機能を用いれば、個々のDockerコンテナのIPアドレスを意識することなくアプリケーション実行環境を立ち上げられる。しかしDockerの初学者にとって、「--link」や「--publish」といったDockerネットワーク特有の流儀を学び適切に利用するのは、ハードルが高いのは確かである。
複数ホストをまたがったDockerコンテナ連携
ここまで説明したDockerのネットワークの仕組みは、単一サーバ上にアプリケーション実行環境を立ち上げて利用する上で必要十分な機能を持っている。しかし、複数のホストを束ねてDockerの可用性向上や負荷分散を図る場合、複数ホストに分散したDockerコンテナ間を、以下のような機能を持った何らかの仕組みで接続できるようにしなければならない。
- 複数ホスト間で適切なサブネットを持ち、重複しないIPアドレスを割り当てる機能
- 複数のホスト上に分散するコンテナ間の通信をトンネルし、適切なホストにルーティングする機能
- ホスト間のネットワークがセキュアでない場合、外部ネットワークを通るパケットを暗号化する機能
このような複数ホストを接続する仮想ネットワーク機能は、従来Docker単体では利用できなかった。そのため、以下に挙げたような様々なサードパーティ製のツールが利用されてきた。
flannel:CoreOS社が公開しているOSSで、Kubernetesのバックエンドネットワークの構成にもよく利用される
rancher:Rancher Labs社が公開しているプライベートなコンテナサービスプラットフォームを構成するためのOSSで、WebUIからホストの登録やコンテナ起動が実施できる
weave net:Weaveworks社が公開しているOSSで、複数ホストを跨いでコンテナ間の仮想ネットワークを構成する機能に特化している
しかし2015/11/04にリリースされたDocker 1.9では、とうとうDocker自身に「overlayモード」と呼ばれるマルチホストネットワーク機能が搭載された。ここからは、従来のbridgeモードのネットワークと見比べながら、overlayモードの実装について見ていこう。
Docker 1.9で新たに採用されたマルチホストネットワーク機能「overlayモード」
実は二世代前のDocker 1.7から、Dockerはネットワーク関係の機能をコア機能から切り離し、Container Network Model(CNM)というコンセプトを持つdocker/libnetworkというライブラリに再編成している。
Container Network Model(CNM)とは
DockerのContainer Network Model(CNM)は、Sandbox、Endpoint、Networkの3つのコンポーネントから構成される(詳細はlibnetworkのdesignドキュメントを参照して欲しい)。
- Sandbox
- コンテナのネットワークスタックの設定(インターフェースやルーティングテーブル、DNS設定等)を隠蔽するもの
- LinuxであればNetwork Namespace、FreeBSDであればJail等を用いて実装される
- 一つのSandboxが複数のEndpointを持っていても良い
- Endpoint
- SandboxをNetworkに参加させるもの
- Endpointはveth pairやOpen vSwitch internal port等を用いて実装される
- Endpointは一つのNetwork、一つのSandboxに所属する
- Network
- お互い直接通信できるEndpointの集合を表すもの
- NetworkはLinux bridgeやVLAN等を用いて実装される
- Networkは複数のEndpointを持つ
libnetworkは、これら3つのコンポーネントとAPIのエンドポイントとなるNetworkControllerを実装している。具体的なNetworkの実装はDriverとして切り出されており、Dockerコンテナ起動時にNetworkController経由で望みのNetwork実装を選択できるようになっている。
libnetworkに実装されているDriver
Docker 1.9のlibnetworkには、以下の5種類のDriverが実装されている。従来の「--net=none, bridge, host」に相当するDriverに加え、Overlay DriverとRemote Driverが追加されている(「--net=container」は、他コンテナのネットワークスタックに相乗りするため、専用のDriverはない)。
ドライバ | 備考 |
---|---|
Null | driverが備えるべきAPIの空実装。ネットワークが不要なコンテナの場合に利用する(従来の「--net=none」に相当) |
Bridge | 仮想ブリッジとNetfilterを用いたネットワーク。 仮想ブリッジを作り、Endpointと仮想ブリッジ間をvethペアで接続する(従来からデフォルトで利用されるbridgeネットワーク「--net=bridge」に相当) |
Host | ホストOSのネットワークスタックをそのまま利用する(従来の「--net=host」に相当) |
Overlay | VXLANでカプセリングしたオーバーレイネットワークを、複数ホスト間に延伸する |
Remote | 動的に登録されるDriverの接続ポイントとなる。Remoteパッケージ自体はDriverの実装を持たず、libnetworkのpluginとして動作するdriverプロセスへのプロキシを提供する |
上記以外にもwindows.goなるソースコードもあるが、現時点では「TODO Windows. This is a placeholder for now」とコメントされているだけで、中身はnull driverとほぼ同じでしかない。
Overlay Driverの準備
では実際にOverlay Driverを動作させ、Docker 1.9のマルチホストネットワーク機能を検証してみよう。まずはOverlay Driverを利用できるように環境を整える。
Overlay Driverを動作させる前提条件
いきなりハードルが高いことに、Overlay Driverを動作させるためには、以下の環境が必要となる。
- 3.16以上のLinux kernel
- Ubuntu 14.04 LTSのカーネルは3.13のため、カーネルアップデートが必要
- CentOS 7.1のカーネルは3.10のため、カーネルを自力でビルドして入れ替えが必要
- 分散KVS
- libnetworkのoverlay Driverは、NetworkやEndpoint等のメタデータを保持するためにlibkvを用いる
- libkvは現時点で次の分散KVSをサポートしている
- consul >= 0.5.1
- etcd >= 2.0
- zookeeper >= 3.4.5
本稿の検証は、以下の環境で行った。
バージョン | |
---|---|
distribution | Ubuntu 14.04.3 LTS |
kerne | 3.19.0-33-generic |
consul | 0.5.2 |
docker | 1.9.0, build 76d6bc9 |
consulクラスタの起動
まずは「consul agent -server」コマンドを用い、Dockerデーモンを動作させる全てのホストが参加するconsulクラスタを起動しておく(consulの詳細については本稿の範囲を超えるため、サービス・ディスカバリのためのConsul入門などを参照のこと)。
Dockerが公開しているGet started with multi-host networkingでは、consul専用のDockerコンテナを一つ起動し、全てのDockerデーモンはそのDockerコンテナのconsulを参照するという手順を紹介している。しかしこの手順では、Dockerデーモンが「consulが起動しているIPアドレス」を事前に知っている必要があるため、Dockerデーモンの起動オプションを静的に定義するには不都合だ。そこで本稿では、全てのホストでconsulを起動してクラスタを組み、Dockerデーモンはlocalhostのconsulを参照するような手順を取る。
Dockerデーモンの起動オプションの変更
Overlay Driverを利用するためには、Dockerデーモン起動時にlibkvが用いる分散KVSを指定しなければならない。そのためDockerデーモンの起動設定ファイル(UbuntuにaptからDockerをインストールした場合は「/etc/default/docker」)に次のオプションを追加する。
【/etc/default/dockerに起動オプションを設定】 root@docker01:~# echo 'DOCKER_OPTS="--cluster-store=consul://localhost:8500 --cluster-advertise=eth0:2376"' >> /etc/default/docker
Dockerデーモン間の通信を行うNIC名がeth0以外の場合、「--cluster-advertise」オプションを適切に変更すること。
Dockerデーモンの再起動
consulクラスタが起動していることを確認した後、Dockerデーモンを再起動してオプション設定を反映させる。
【Dockerデーモン再起動】 root@docker01:~# service docker restart
連載バックナンバー
Think ITメルマガ会員登録受付中
全文検索エンジンによるおすすめ記事
- Oracle Cloud Hangout Cafe Season 4 #2「Kubernetesのネットワーク」(2021年5月12日開催)
- コンテナ関連技術の現状を確認しておく
- Neutron最新動向: 活発なサブプロジェクトに注目
- Project Calicoのアーキテクチャを見てみよう
- Dockerコンテナ環境のバックアップツール「Convoy」を使う
- コンテナとKubernetes作成・運用に関するセキュリティ
- OpenStackの自動構築
- サービス・ディスカバリのためのConsul入門
- Dockerコンテナのオーケストレーション機能を実現するOpenStack Magnumを触ってみた
- CentOS 7のネットワーク管理基礎(後編)