Blog
OpenStack Heat で Resource Plugin を自作してみる
こんにちは。
Central Infrastructure Agency の青山真也です。
今回は OpenStack Heat で自作の Resource Plugin を作ってみたお話です。
弊社では昨今のコンテナの需要拡大に伴い、プロダクション環境向けに Kubernetes (& Docker Swarm) on OpenStack を実現する GKE like なコンテナ基盤を構築しました。
コンテナ基盤を作るにあたって、Heat でプロビジョニングする部分があり、
OS::Heat::AutoScalingGroup / OS::Heat::ResourceGroupを利用しています。
また、クラスタメンバに対する負荷分散では物理のロードバランサを使っているため、
現状ですとクラスタメンバの増減に伴いロードバランサの Pool Member を入れ替えてあげる必要があります。
方法としては、
- Heat の API を一定間隔でポーリングして、クラスタメンバに変更があった場合に LB の変更処理を行う
- Heat Resource として定義し、 Scale In/Out イベントをトラップして LB の変更処理を行う
の2つがあると思います。
1つ目の方法では、下記のような問題が存在しています。
- 無駄な API アクセスが多い、反映までに遅延がある
- 自前でポーリングサーバを用意してあげる必要がある
- 追加や削除などの進行情報の管理を作り込む必要がある
2つ目の方法では、これらの問題が解決されるだけではなく、
Heat のテンプレートとしてコード化もされるため、管理がしやすいといった特徴もあります。
Heat で Plugin を自作する際には、heat.engine.resource.Resource
のサブクラスとして定義し、
下記のメソッドを用意してあげる形になります。
- handle_create()
- handle_update()
- handle_delete()
- check_create_complete()
- check_update_complete()
- check_delete_complete()
最初の 3 つの handle_*() メソッドは、作成・更新・削除それぞれの処理を記述します。
Heat で扱う Nova Instance や Neutron Router などの OpenStack Resource は
作成する際に handle_*() 内で各 client library を使って非同期で実行します。
そのため、最後の 3 つの check_*_compute() メソッド内では、同様に各 client library を使って
それぞれの動作が完了したかをチェックする枠組みを提供しています。
このように Heat では Plugin を作るときにの枠組みとして、ライフサイクルを提供しているため、
“追加や削除などの進行情報の管理を作り込む必要がある” という点を解決することが可能です。
また、Heat の Resource として定義することで、Scale In/Out 時に handle_create() / handle_delete() が呼び出されます。
その際に、LB の Pool Member への追加や削除を行うといったようにイベントドリブンな処理が行われることとなり
“無駄な API アクセスが多い、反映までに遅延がある”、”自前でポーリングサーバを用意してあげる必要がある”という点も解決します。
弊社では “APIでネットワークを自動化するAXC” にあるようにすでにネットワーク機器の自動化の枠組みは導入されており、
Python ライブラリ化もされていたため、このあたりのつなぎ込みは容易でした。
さらに Heat には Constraint という枠組みも用意されており、各 Property の値などをチェックすることが可能です。
例えば、LB に追加する Pool Member の値が正しい IP Address の形式かどうかや、
nova に登録されているインスタンスかなどをチェックさせることも可能です。
ビルドインの Custom Constraint は Heat Orchestration Template (HOT) specification にあるほか、
簡単に自作の Custom Constraint を作成することも可能です。
また、依存関係を定義する際に利用する {get_resource: XXX } や {get_attr: XXX} などでリソースから値を取得できるようにするには、
_show_resource() を実装したり、heat.engine.attributes を インポートし、ATTRIBUTES を定義してあげることで実現可能です。
最後にこちらが完成した自作の Heat Resource です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# Top level の Heat template に定義 resources: sample_pool: type: ADTECH::AXC::BIGIPPool properties: axcauthtoken: XXXXXXXXXXXXXXXXXXXX poolname: SamplePoolName mode: round-robin monitor: /Common/gateway_icmp sample_vs: type: ADTECH::AXC::BIGIPVS properties: axcauthtoken: XXXXXXXXXXXXXXXXXXXX vsname: SampleVSName ipaddr: 10.10.10.10 poolname: SamplePoolName port: 80 # Top Level の Heat Template から呼び出される Auto scaling group の template に定義 resources: sample_poolmember: type: ADTECH::AXC::BIGIPPoolMember properties: axcauthtoken: XXXXXXXXXXXXXXXXXXXX poolname: {get_resource: sample_pool} ipaddr: {get_attr: [autoscale_server_eth0, fixed_ips, 0, ip_address]} port: 0 ratio: 1 |
なお、OpenStack 系の Resource では、python-keystoneclient などの python client library を利用しているため、
client library を用意してResource Plugin から呼び出す形のほうがお作法的にはいいかもしれませんね。
ココらへんは興味がある方は OpenStack Heat のソースコードを読んでみてください。
Author