ここがヘンだよ Cinder


Cinder って皆さんご存知でしょうか?
正しくは「OpenStack Block Storage」と言います。Amazon Web Service (AWS)における EBS とほぼ同じ、IaaS 用の付加的なディスク(ボリューム)サービスです。詳しくはこちらを参照して下さい。

さて、この Cinder、他に類を見ないユニークな OSS ではありますが、ソースコードを見たり、実際に動かしているとイマイチな部分があります。

全体

ボリュームが複数の VM から共有できない

Cinder の前身である nova-compute の時代から今に至るまで、1つのボリュームは複数の VM から同時に利用できないようになっています。

ところが、Cinder で利用できるストレージには、同時に1つのボリュームを複数の VM から利用可能なものが少なくありません。同時に利用できるのであれば、VM 群で共有ファイルシステムを利用したり、アクティブ・スタンバイ型クラスタを構成したりと色々便利な事が出来る筈です。

今後の開発項目案の1つにはなっていますが、すぐには実現されそうにありません。

API 関連

RESTful API のバリデーションがザル

多くの OpenStack コンポーネントで言える事ですが、Cinder の API バリデーションも本当にザルです。未チェックのパラメータが多数あり、API を通り抜けた不正な値によって中間部やストレージ部でエラーになる事があります。

ボリュームの状態遷移のチェックがザル

ボリューム予約やアタッチ完了、デタッチ開始やデタッチ完了等の操作において、リクエスト時点でのボリュームの状態を確認していない操作が多々あります。

ボリュームの状態遷移で元の状態が分からなくなる

状態が error のボリュームでも、ボリューム予約+ボリューム予約解除を行うと、ボリュームの状態が available に戻ってしまいます。

ドライバ関連

全ドライバの基底クラスが全然基底になっていない

Cinder のドライバは全て、cinder.volume.driver.VolumeDriver クラスを継承しています。このドライバはいわゆる基底クラスであり、API を規定するのが本来あるべき姿です。

ところが、実際には VolumeDiver クラスは Linux の LVM2 を管理するドライバであるため、LVM2 に依存する ISCSIDriver 以外の全ドライバには明らかに不要なコードを含んでいます。このため、VolumeDriver を継承した別ドライバで実装していないメソッドがある場合、期待しない動作をする可能性があります。

ボリュームの作成とボリュームの公開が別作業

Cinder に「ボリュームの作成」を指示すると、ドライバでは create_volume() と create_export() という2種類のメソッドが呼ばれます。これは ISCSIDriver や今は亡き AOEDriver において、create_volume() は親クラスの VolumeDriver、create_export() は各ドライバのメソッドが使用されていたからです。

ところが、多くのドライバでは create_export() に大した処理を書いていません。通常、ボリュームの公開作業はボリュームアタッチ時に行えば良いものであり、ボリューム作成時に行う必要がないからです。ISCSIDriver においても、create_volume() に相当する部分は親クラスのプライベートメソッドをコールすれば良い話で、create_export() は全く不要なメソッドと言えます。

ボリューム削除時にデータを0クリアする

ISCSIDriver を使っている場合、ボリュームの削除に長い時間がかかる事があります。これはボリューム削除時にボリューム全体のデータをクリアする為の書き込みを行なっているからです。

ところが、例えばスナップショットの領域は 0 クリアできません。多くのストレージ装置で言える事ですが、スナップショット領域上のデータのみ狙い撃ちで上書きする事が基本的には無理だからです。では、元々スナップショット領域だった部分を使って新規ボリュームが作成されたらどうなるでしょうか?元々のデータが見えてしまい、情報漏えいに繋がる危険性があります。

この問題を回避する為には、ボリュームの削除時ではなく作成時にボリューム全体のデータを0クリアするしかありません。ボリューム作成には時間がかかる事になりますが、例えば Glance イメージからのボリューム作成やスナップショットからのボリューム作成では新規ボリューム上の大半に書き込みが発生します。同じ時間がかかるのであれば気にする事はありません。

ファイルベースのボリュームサービスが整備されていない

Cinder では NFS ベースのドライバが幾つかありますが、コードが共用化されていません。また、例えば GFS2、OCFS2、Ceph、GlusterFS といった共有ファイルシステム上でボリュームサービスを行う場合、基本的には VM ホストマシンがマウントした共有ファイルシステム上にボリュームサービス用の仮想ディスクイメージを作成するだけになりますので、共通のドライバが1つあれば良い事になります。NFS でも同様の筈です。

1ファイルに多数のドライバクラスが混在してぐちゃぐちゃ

cinder/volume/driver.py や cinder/volume/san.py には複数のドライバクラスが存在して非常にごちゃごちゃしています。Python のコーディング規約では推奨される1ファイル中の行数の上限もありますし、ユニットテストを行う際にはテストのカバー率(カバレッジ)の計算結果がファイル単位で出力されますので、こうした混在環境は各ドライバ毎のカバレッジ計算を困難にします。

幸い、次期バージョンの開発項目の1つでドライバの分離作業が進められています。

初期化時に大したチェックや初期化処理をしていないドライバが多い

多くのドライバは cinder-volume が実行される OS 上のコマンドを実行します。この際、構築時のミスで必要なコマンドがインストールされていなかったり、使える状態にないケースが想定されます。これらの問題は実際に Cinder でボリューム作成やスナップショット作成等の操作を行わないと発見できない事がほとんどです。

この問題は、cinder-volume の起動時に各ドライバで実行される check_for_setup_error() でコマンドの実行可否を確認する事で、サービス運用前に確認する事ができるようになります。