Tech Sketch Bucket of Technical Chips by TIS Inc.

MidoNetで試すKuryr - Docker remote driver for OpenStack Neutron (1)

Pocket

2015年10月末に開催されたOpenStack Summitでは、ネットワークコンポーネントであるNeutron、すなわちSDN関連に非常に勢いがあり、また、OpenStackとコンテナ技術の関わりについてのセッションが目立っている様子が見受けられました。そして、2日目のKeynoteではコンテナ、VM、ベアメタルのネットワークに関するKuryr(読み方は、片仮名表記で近いものはクリル、クリア、などのようです)という新しいプロジェクトが発表され、Kuryrについて解説したセッションもありました。

今回の記事では、まずこのKuryrについてご紹介し、次回以降の記事にて、現時点で実際にKuryrとの連携動作が確認されているMidoNetのオープンソース版とOpenStackを連携し、Kuryrを実際に動かしてみるところまでを見ていきます。

前提

本記事は、OpenStack(特にNeutron)、およびDockerのネットワーキングについて、ある程度動作や原理等を理解していることを前提とした記述になっており、キーワードが説明なく出現する場合があります。全てをこの記事内で説明するとボリュームが膨大になってしまうため、適宜、記事下部の「参考」に記述する情報等をご覧頂ければと思います。

コンテナとOpenStackの関わり

1つのOS上でプロセスID、ネットワーク、ファイルノードといった様々なリソースを名前空間などを利用して隔離し、独立したものとして見せるコンテナ技術自体は、各所で言われるとおり、以前から存在するものです。 Linuxには、以前からシステムコンテナとして扱うことができるLXCが存在しましたが、2014年頃から画期的な環境構築・維持・配布方式などを持ったアプリケーションコンテナのプラットフォームであるDockerが現れ、非常に注目を集めています。 Dockerは「高速起動しイメージ配布も簡単な、新たな仮想化(コンテナ型仮想化)」「Infrastructure as CodeによるDevOps促進」など、技術者のレイヤによって注目される部分が異なっていますが、それだけ幅広い可能性を秘めたものであるということかもしれません。

そして、これらに対応するように、様々な仮想化基盤がコンテナへの対応に取り組み始めました。OpenStackでも、例えばMagnumプロジェクトなどによってDockerを扱い始めています。

現在、Dockerを始めとするコンテナは、VMとの棲み分けやその活用事例が具体的になり始めていると言えますが、コンテナのネットワークにはVMとは異なる思想や特徴があり、VMを中心に展開してきた仮想化基盤やクラウドOSでコンテナを扱う場合、ネットワーキングの壁を解決する事が必要になってくると考えられ、OpenStackも例外ではありません。

Kuryrの概要

kuryr logo

(https://github.com/openstack/kuryrより引用)

Kuryrは、Dockerのネットワーク機能であるlibnetworkについて、プラグイン形式で機能を拡張できるremote network driverを実装したものであり、libnetworkのネットワーク操作を、OpenStack NeutronのAPI呼び出しにマッピングするものです。Neutron API自体はベンダ非依存であるため、libnetworkから一旦Neutronを通し、モデルのすり合わせと、インタフェースの紐付け(VIF Binding)をKuryrが担うことによって、様々な既存のNeutronプラグインをDockerネットワーキングのバックエンドとして利用することが可能になります。このように、libnetworkのContainer Networking Model(CNM)とNeutronのネットワークモデルの間の通訳係として働き、コンテナ、VM、ベアメタル間について、隔てのない接続を提供することが期待されているようです。

また、例えばMagnumで作成されたコンテナのネットワークは現在、Neutronの管理下にあるわけではなく、OpenStack上で起動しているVMとは互いに通信することが困難です。Kuryrは、こうしたギャップを埋めるためのものとして活躍する事も期待されていると考えられます。

libnetworkとNeutronのモデルの対応

簡単に2つのモデルの比較し、Kuryrによるマッピングを見てみましょう。

Neutronのネットワークモデル

Neutronのネットワークモデルは、主に以下のように定義されています。

kuryr1

  • Network
    • NetworkはNeutron APIの主要なエンティティである
    • Networkは仮想的に隔離されたL2ブロードキャストドメインを指す
    • 明示的に"共有"と設定しない限り、作成したTenantに属す
    • Tenantは、Tenantあたりの上限Network数まで、複数のNetworkを作ることができる
    • PortとSubnetは必ずNetworkに紐付く
  • Subnet
    • SubnetはVMに付与するIPが所属すするIPアドレスブロックを表現する
    • 各Subnetは必ずCIDRを持ち、Networkに関連付けられている必要がある
    • IPアドレスはSubnetのCIDRから選択されるか、ユーザの指定する"allocation pools"から割り当てられる
    • SubnetはGateway(gateway_ip)、DNSサーバ(dns_servers)、ホストのRoute(host_routes)を持ち得る
  • Port
    • Portは、仮想スイッチ上のスイッチポートを表現する
    • VMは、自身のNICをそのポートと接続する
    • Portは、そのPortに接続するNICに関連付けられるMACアドレスとIPアドレスも定義する
    • Portは、暗にSubnetに関連付き、IPアドレスはSubnetのallocation poolから取得される

Neutronを扱う場合、この他にもRouter等、沢山のリソースが出現しているように見えますが、実際には、それらは全てリソースを拡張する「Extension」で表現されています。

Container Networking Model

Container Networking Modelは、主に以下のように定義されています。

Container Networking Model (https://blog.docker.com/より引用)

  • Sandbox (Network Sandbox)
    • Dockerコンテナのネットワークスタックやインタフェースを隔離する環境を指す
    • Dockerにおける解りやすい例は、SandBox=Network Namespace
    • Sandboxは複数のNetworkに繋がる複数のEndpointを持ち得る
  • Endpoint
    • 特定ネットワークで通信するためのインタフェースを指す
    • Endpointは1つのNetworkに参加する
    • Dockerにおける解りやすい例は、Endpoint=veth
  • Network
    • 一意に識別できる、お互いが通信できるEndpointの集合を指す
    • 例えばFrontendやBackendといったネットワークを作ることができ、それはお互い完全に隔離される
    • Dockerにおける解りやすい例は、Network=bridge等

Container Networking Modelでは、Networkとコンテナの間において以下を約束事とします。

  • 同じNetworkの全てのコンテナは、お互いが自由に通信できる
  • 複数Networkはコンテナ間のトラフィックを分ける手段であり、全てのドライバでサポートされるべきである
  • コンテナ毎の複数Endpointは、コンテナが複数のNetworkに所属するための手段である
  • Endpointは、そのEndpointへの接続性提供のためにNetwork Sandboxに追加される

Kuryrが行うモデルの対応付けとVIF Binding

Kuryrは、上記2つのモデルの要素を以下のように対応付けします。

libnetwork Neutron
Network Network
Sandbox Subnet, Port, netns
Endpoint Port

(http://docs.openstack.org/より引用)

ここで、APIの呼び出しを変換するのは良いとして、実際にコンテナのインタフェースを作成したり、そこから出力されるパケットをうまく望みのネットワークに流すための処理はどこで行うのか?またその点について、様々なNeutronプラグインにどうやって対応するのか?という疑問が湧いてきます。

現状のKuryrのアーキテクチャでは、この部分について、利用しているNeutronのプラグイン、具体的にはNeutronのポートタイプに応じて紐付け処理を呼び分ける仕組みがあります。これはVIF Bindingと呼ばれており、紐付け処理の実体はdatapathにインタフェースを紐付けするといった小さなプログラムです。この紐付けとは、例えば、過去のMidoNetの記事で説明した、「作成したportに実際のインタフェースをbind」に該当する操作です。元々OpenStackでは、インタフェースの作成や、それをdatapathに紐付けるといった動作はNovaのVIF Driverが担っているものですが、Dockerを起点にコンテナを立ち上げる今回のケースでは、nova-computeは利用されないため、VIF Bindingによってこの部分を補う形になっているものと考えられます。

図にすると、以下のような対応となります。

kuryr2

一度コンテナが起動し、インタフェースが紐付けされた後は、VMかコンテナかどうかに関係なく、通常のNeutronへの操作でネットワークを操作する事ができます。

次にやること

Kuryrは、ミドクラ社のエンジニア達が中心となって開発が進められており、Kuryrのリポジトリにも現在MidoNet用のVIF Bindingが準備されているため、MidoNetと連携してKuryrを動作させる事が出来ます。

今回に全て記載してしまうと非常に長くなってしまうため、まずKuryrが何者であり、どういったことを目的にしているかを紹介しました。 次回の記事では、冒頭で述べたように、前回までのMidoNetの記事では単体で動作させていたMidoNetをOpenStackのバックエンドとして連携し、Kuryrを使用して起動したDockerコンテナと、OpenStackで起動したVMを同一ネットワークに所属させ、お互いが通信できることを確認してみます。

参考情報

Neutronのネットワークモデルについて、より詳しくはOpenStackのWiki、Container Networking Model(CNM)については、Dockerのgithubリポジトリ中にあるデザインに関するドキュメントや、Dockerのblogの情報に記述があります。

また、本記事執筆時点で最新のDocker1.9以降のネットワーキングそのものについては、弊社エンジニアによる記事「Docker1.9のマルチホストネットワーク」にて詳しく記載されていますので、こちらも合わせて参照下さい。

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