Neutron サービスプラグインの作り方

はじめに

 こんにちは、インフラ本部の大山裕泰です。今回は OpenStack をより柔軟な環境に拡張できる小ネタをご紹介致します。
 前回のエントリでも述べましたが Neutron ではコンピュートノードのエージェントを制御したり、独自の拡張機能を本体の機能と連携させたりといった事がプラグイン機構によって実現できます。
 今回は、Neutron のプラグイン機構についてと、ルータに対する各種操作に同期する Neutron L3 プラグインの仕組みと実装について見てゆきます。
 また、今回紹介する手法を応用するこよによって、以下のようなことが出来るようになると思います。

  • Floating-IP 割当/削除時における DNS との連携
  • テナントネットワーク、及び Flaoting-IP の作成/更新/削除に伴う課金システムとの連携

 まずは Neutron のプラグイン機構について少し詳しく見てゆきます。

Neutron プラグイン機構

「コアプラグイン」と「サービスプラグイン」

 冒頭で述べたように Neutorn では、コントロールプレーンを実現する「コアプラグイン」に加えて、ネットワークに関する様々な機能を「サービスプラグイン」という形で OpenStack Networking のメインプロセスである neutron-server から切り離して使える設計になっています。
 Neutron は、今回紹介する、ルータや Floating-IP の管理などの L3 機能に加え、VPN や LB、FW などといった機能毎に「サービスタイプ」を規程しており、ユーザはサービスタイプ毎にそれぞれの環境が必要としている要件を満たすプラグインの実装を一つ選択して利用できます。
 以下が OpenStack Juno 版における各サービスタイプの一覧になります。

サービスタイプ プラグインの種別
LOADBALANCER LBaaS のプラグイン
FIREWALL FWaaS のプラグイン
VPN VPNaaS のプラグイン
METERING トラフィック流量計測機能 (Neutron Metering) のプラグイン
L3_ROUTER_NAT ルータ (L3) 関連機能のプラグイン

 また、コアプラグインとサービスプラグインはそれぞれ Neutorn の設定ファイル (/etc/neutron/neutron.conf) の core_plugin と service_plugins で指定します。以下は neutron.conf における両パラメータの抜粋になります。

 
 コアプラグインのパラメータ (core_plugin) では一つの値 (neutron.plugins.ml2.plugin.Ml2Plugin) だけが設定されていますが、サービスプラグインのパラメータ (service_plugins) にはリスト形式で複数の値が設定されています。
 先に述べたように、サービスプラグインは各サービスタイプ毎に一つしか指定されるため、ここで指定されている値はそれぞれサービスタイプ毎のサービスプラグインを表しています。どのプラグインがどのサービスタイプのものかはプラグインの実装側で指定されています。これについては後で L3 プラグインを実際に作成する際に見てゆきます。

拡張 (Extension) 機能

 Neutron のプラグイン機構の設計でもう一つ重要な仕組みが 拡張 (Extension) 機能 になります。これは、各種プラグインを経由して Neutron 本体の API や機能の拡張を行うための仕組みで、プラグインは一つ以上の拡張機能を利用することで、当該拡張機能が提供する API コールをハンドリングし独自の実装を加えることができます。後述する L3 プラグインでは router 拡張機能 を実際に使い、Floating IP アドレスの作成 / 削除の処理をハンドリングしています。

L3 プラグインを作ってみた

 では実際に L3_ROUTER サービスプラグインを作ってみたいと思います。
 今回作成した L3 プラグイン (L3GREEPlugin) では router 拡張機能 を用いて、Neutron の L3 関連オブジェクト (ルータ, Floating IP アドレス) の 作成, 更新, 取得, 削除処理をハンドリングすることができます。実際には例として、Floating-IP の作成/削除に同期してログを出力する処理を実装しています(その他の処理についても同様にして実装することができると思います)。以下がソースコードの全文になります。

 まず L3GREEPlugin が継承している親クラス (13行目) ですが、一つ目の親クラスとして指定されている CommonDbMixin は、コア/サービスプラグイン共通で利用されるユーティリティメソッドが定義されたクラスになります。そして二つ目の親クラス L3_NAT_db_mixin は、各種 L3 関連オブジェクト (ルータ, Floating-IP, ポートなど) の DB モデルに対する処理を規程したクラスになります。
 またクラス変数 supported_extension_aliases によって、プラグインが利用する拡張機能を選択します(16行目)。ここでは "router" 拡張機能を選択し、L3 関連オブジェクト (ルータ、及び Flaoting IP アドレス) のリソースを Neutron 本体から扱えるようにしています。
 続いて get_plugin_type メソッド (21行目) によってプラグインのサービスタイプを指定し、get_plugin_description メソッド (24行目) によって当該プラグインがどんなものかを指定しています。このメソッドは、サービスマネージャーがプラグインをロードする際に呼び出し、結果をデバッグログに出力するだけなので動作としてはとくに影響はありませんが、これを宣言しないとサービスマネージャー側でメソッドコールに失敗し neutron-server プロセスが停止します。
 そして最後に、Floating IP アドレスの割当/解放処理をハンドリングする create_floatingip / delete_floatingip メソッド (27行目/33行目) を宣言しています。これらは router 拡張機能 (extensions/l3.py) でテンプレートが定義され、L3GREEPlugin の親クラス (L3_NAT_db_mixin) で実装が書かれています。ここでは、これらのメソッドをオーバーライドし、呼び出されたタイミングでログメッセージを書き出した後、通常の処理を実行しています。尚、router 拡張機能で定義されているテンプレートメソッドの一覧は RouterPluginbase クラスの定義 から確認できます。

動かしてみた

 以上で述べた Neutron の独自プラグイン (L3GREEPlugin) を実際に動かしてみようと思います。

 まずはサービスタイプ "L3_ROUTER_NAT" のサービスプラグインとして、作成したサービスプラグインを指定するようにコントローラノードの neutron.conf を修正します。以下は、先ほど示した内容との差分になります。

 
 次に neutron-server プロセスを再起動させ、horizon から Floating IP アドレスの割当/解放を実施して、期待通りに動作するか確認してみます。

 

 Floating IP アドレスを割り当てると、以下のログが neutron-server のログに出力されました。

 続いて、割り当てた Floating IP アドレスを削除してみます。

 

 同様に以下のログが出力されました。

まとめ

 いかがだったでしょうか。ここではごく簡単な例しか示しませんでしたが、ここで紹介したテクニックを応用することで冒頭で述べたように他のシステムとの連携であったり、独自処理の追加といった事ができるようになり OpenStack をより柔軟に運用してゆく事ができるようになると思います。