KVMメモ

仮想化技術であるKVMを試してみようと調べたので、整理してみました。まだ実際に試してはいないので、技術的に深く踏み込んだ内容はあまりありません。そもそも仮想化とは何か、から始まりKVMの特徴、という流れで書いています。

仮想化について

仮想化とは

Wikipediaでは、

仮想化(英: Virtualization)とは、コンピュータにおいてリソースの抽象化を指す用語である。「リソースの物理的特性を、そのリソースと相互作用するシステム/アプリケーション/エンドユーザーから隠蔽する技法。単一の物理リソース(サーバ、OS、アプリケーション、補助記憶装置など)を複数の論理リソースに見せかけたり、複数の物理リソース(複数の補助記憶装置群やサーバ群)を単一の論理リソースに見せかけたりできる」という実用的定義がある[1]。また、単一の物理リソースを何らかの特性の異なる単一の論理リソースに見せかけることもできる。

仮想化 - Wikipedia

と記述されています。

しかし、ここではx86仮想化に限って以下続けます。

x86仮想化とは、x86ベースのゲストオペレーティングシステム (OS) を、別のx86ベースのホストOS上で、ほとんど(あるいは全く)ゲストOSを修正することなく動作させる手法である。

x86仮想化 - Wikipedia
なぜ仮想化か

では、仮想化のメリットは何か、という話です。ビューティフルアーキテクチャによると、柔軟性や性能上の隔離や資源の有効活用が仮想化のメリットです。

まず、柔軟性について。複数ユーザがOSを使うと言う観点で考えると、マルチタスクOSで十分ですが、管理者権限がないとソフトウェアのインストールができませんが、仮想化されたOSを1人1つ割り当てれば、限られた範囲で自由に使うことができます。

次に、性能上の隔離について。こちらもマルチタスクOSと比較すると、カーネルは複雑なので、ユーザごとに使用する資源の限度を設けるのは困難ですが、仮想化されたOSごとに資源の限度を設けることはできるので、他のユーザに迷惑をかけるようなことはできなくなります。

最後に、資源の有効活用について。CPUを使うアプリケーションやメモリを使うアプリケーションを別々の物理マシンにするのは資源の無駄ですが、同一OS上で実行すると1つの機能が別の機能を巻き込んだ障害を起こす可能性があります。仮想化されたOSを使うことで、独立した環境で資源を有効活用することができます。

その他に、機能ごとのマシンを増やすのが簡単というのもありますね。クラウドサービスとして考えると必要な時に必要な資源だけを利用できるというメリットも出てくるかと思います。

仮想化の種類

ハードウェアのエミュレーション方式から、次のように、完全仮想化と準仮想化に分けられます。

準仮想化 完全仮想化
ゲストOSのコード書き換え あり なし
エミュレーションのオーバーヘッド 小さい 大きい

準仮想化では、ゲストOSのカーネルがハードウェアと通信する命令はハイパバイザと通信するよう置き換えられ、ハイパバイザが代わりに実行する。そのため、ゲストOSの完全な互換性は失われるが、完全仮想化と比較して性能が良い。

一方、完全仮想化は、ハイパバイザが、ゲストOSのハードウェアと通信する命令を検出し、ハイパバイザを直接呼び出す命令に置き換える、という形でハードウェアを完全にエミュレートする。このエミュレーションのコストが大きいので準仮想化と比較して性能が低い。しかし、CPUの仮想化支援機能(Intel VTやAMD-V)やパラバーチャルドライバを使うことで性能は改善される。

また、ハイパバイザの動作方式から、Type1(ネイティブ方式)とType2(ホスト方式)に分けられます。

Type1 Type2
ハイパバイザの動作場所 ハードウェア上 ハードウェア上のホストOS上
メリット 性能が良い インストールが簡単

ハードウェア上でハイパバイザが直接動作している方式をType1の仮想化という。KVMのようにLinuxカーネルとして実装されているハイパバイザも含まれる。

一方、Type2の仮想化は、通常のOSの上に、通常のアプリケーションのようにハイパバイザがインストールされる方式のことをいう。インストールが簡単だが、ホストOSにスケジューリングされることやレイヤが厚いことなどから、Type1と比較して性能が低い。

KVMについて

KVMとは

KVM(Kernel-based Virutal Machine)は、x86ハードウェア上で、CPUの仮想化支援機能を使って完全仮想化を実現する技術です。開発したのはイスラエルのQumranet社です。

特徴は、

  • 完全仮想化
  • Linuxカーネルのモジュールとして実装されている
    • Linuxの既存の機能を利用できる
  • ハードウェアのエミュレーションにQemuを使っている
    • KVM自体は新しい実装だが、実績あるQemuを使っているので、比較的安定している
  • CPUの仮想化支援機能を使うことで高速化を実現している
  • Virtioというパラバーチャルドライバで性能を向上させている(参照)

です。

KVMの歴史
  • 2006/10: アナウンスされる
  • 2006/12: Linux Kernelにマージされる
  • 2007/02/04: KVMが標準搭載されたLinux2.6.20がリリースされる(参照)
  • 2008/09/04: Red HatがQumranetを買収した(参照)

Evernote APIを使うiPhoneアプリの作りかた

EvernoteのiPhoneアプリをよく使っています。アップロードはいいのですが、参照する方の機能がいまひとつに感じていたので、試しに作ってみようかと始めてみたら結構苦労したので書いておきます。

Evernoteのフォーラムを見るとhttp://digitalpericope.net/?p=1http://digitalpericope.net/?p=27チュートリアルのような位置づけぽいので、ここに沿って、iPhoneアプリ開発環境で、Evernote APIを使って、Notebookの一覧を取得するところまでの流れです。

API Keyを取得する

http://www.evernote.com/about/developer/api/から要求します。

数日後に、cunsumer keyとconsumer secretが送られてきて、sandboxを使えるようになります。僕の場合は、3日かかりました。

Xcodeで新規プロジェクトの作成

適当な名前で作成します。

Thriftをダウンロード

http://incubator.apache.org/thrift/download/からダウンロードする。最新が0.2.0だったのでthrift-0.2.0を使います。

それから、thrift-0.2.0/lib/cocoa/src/をEvernoteViewer/Classes/thrift-cocoaとしてコピーします

Evernote APIをダウンロード

https://www.evernote.com/about/developer/api/Evernote API(ZIP)というリンクからダウンロードします。最新が1.14だったので、evernote-api-1.14を使います。

それから、evernote-api-1.14/src/cocoa/をEvernoteViewer/Classes/evernote-cocoaとしてコピーします。

プロジェクトにThriftとEvernote APIを追加

Xcodeに戻り、'3rdParty'というグループを作成し、その下に'Evernote'というグループを作成する。

3rdPartyを右クリック→追加→既存のファイル...、と選択して、コピーした'thrift-cocoa'を選択する。
同じように、3rdParty/Evernoteを右クリック→追加→既存のファイル...、と選択して、コピーした'evernote-cocoa'を選択する。

ここでビルドすると大量のエラーがでるので、これを直していきます。

プロジェクト→プロジェクト設定を編集、でプロジェクトの情報ウィンドウを開き、ヘッダ検索パスに(headerで検索すると見つけやすいです)、'./Classes/thrift-cocoa'を設定し再帰的にチェックを入れる。

'3rdParty/Evernote/evernote-cocoa/thrift'を右クリック→削除、で参照を削除をクリック。

これで、ビルドに成功します。参考にした記事では、使用していないThriftのファイルの参照を削除していますが、そのままにしています。

Notebookを取得する

https://www.evernote.com/about/developer/api/evernote-api.htmの「7.Local Client API Usage Example」にJavaのサンプルがあるので、これをObjective-Cで書けばいいのですが、http://digitalpericope.net/?p=27を参考にしました。

ヘッダーを追加します。

#import "THTTPClient.h"
#import "TBinaryProtocol.h"
#import "UserStore.h"
#import "NoteStore.h"

適当な場所(例えばapplicationDidFinishLaunching)で以下のようにするとNotebookが出力されることを確認できます。USERNAME, PASSWORD, CONSUMER KEY, CONSUMER SECRETはアカウント情報と、送られてきたAPI Keyに直して下さい。

NSURL *userStoreURL = [NSURL URLWithString:@"https://sandbox.evernote.com/edam/user"];
NSString *noteStoreURLBase = @"http://sandbox.evernote.com/edam/note/";

THTTPClient *userStoreHTTPClient = [[[THTTPClient alloc] initWithURL:userStoreURL] autorelease];
TBinaryProtocol *userStoreProtocol = [[[TBinaryProtocol alloc] initWithTransport:userStoreHTTPClient] autorelease];
EDAMUserStoreClient *userStore = [[[EDAMUserStoreClient alloc] initWithProtocol:userStoreProtocol] autorelease];
	
BOOL versionOK = [userStore checkVersion:@"EDMATest" :[EDAMUserStoreConstants EDAM_VERSION_MAJOR] :[EDAMUserStoreConstants EDAM_VERSION_MINOR]];
if(versionOK == YES) {
	@try {
		EDAMAuthenticationResult *authResult = [userStore authenticate:@"USERNAME" :@"PASSWORD" :@"CONSUMER KEY" :@"CONSUMER SECRET"];
		EDAMUser *user = [authResult user];
		NSString *authToken = [authResult authenticationToken];
		
		NSURL *noteStoreURL = [NSURL URLWithString:[NSString stringWithFormat:@"%@%@", noteStoreURLBase, [user shardId]]];
		
		THTTPClient *noteStoreHTTPClient = [[[THTTPClient alloc] initWithURL:noteStoreURL] autorelease];
		TBinaryProtocol *noteStoreProtocol = [[[TBinaryProtocol alloc] initWithTransport:noteStoreHTTPClient] autorelease];
		EDAMNoteStoreClient *noteStore = [[[EDAMNoteStoreClient alloc] initWithProtocol:noteStoreProtocol] autorelease];
		
		NSArray *notebooks = [noteStore listNotebooks:authToken];
		for(int i = 0; i < [notebooks count]; i++) {
			EDAMNotebook *notebook = (EDAMNotebook*)[notebooks objectAtIndex:i];
			NSLog([notebook name]);
		}
	}
	@catch (NSException * e) {
		NSLog(@"Caught %@: %@", [e name], [e reason]);
	}
	@finally {
		NSLog(@"finally");
	}
}
else {
	NSLog(@"NO");
}

Thriftについて

Thriftは、facebookが開発したクロス言語RPCフレームワークで、サーバ間のデータのやりとりに使えます。データの定義があれば、各言語用のライブラリを生成してくれるので、サーバ・クライアントともに言語を問いません。

Evernote APIの例だと、Evernote側でデータを保持し、Thriftのライブラリを配布しているので、今回のようにObjective-Cだけでなく、JavaRubyなどで同じように実装することが可能になります。

http://incubator.apache.org/thrift/about/によると、facebookEvernoteだけではなく、last.fmなどが使っていたり、Vimeoで使えるエンジニアを募集していたりしていました。

Responsibilities
(中略)
・Develop internal application services (Beanstalk, Thrift, Solr, stats)

参考

techlifeライトニングトークでPuppetの発表をしました

先週、クックパッドオフィスで開催されたtechlifeライトニングトークの第二回目でPuppetについて話しました。

参加者は、mizzyさんn0tsさんという豪華な顔ぶれです。どちらもPuppetを導入する際に(勝手に)お世話になっていたので、恐れ多い気分でしたが、発表が終わった後の懇親会はアットホームな雰囲気でした。ご参加頂きありがとうざいました。

さて、Puppetですが、僕の方は、今年の夏頃からさわり始め、ちょうど今本格的に使っているところなので、導入事例みたいなお話をさせて頂きました。少しずつではありますが、インフラの作業が自動化し始めています。

n0tsさんの発表は、Puppetとcobblerを組み合わせて、サーバを開放してから設定を終えるまで、Tipsを挟みながらとても実用的なお話でした。Kickstartの%postの使い方などは参考になりました。

n0tsさんはVelocityで行われたPuppetワークショップの日本語訳GitHubでPuppetモジュールの公開もしています。特にワークショップの日本語訳はPuppetをちょっと触ってみたい人に良い資料ですね。

mizzyさんの発表は、「Puppet Best Practices?」と題され、クラスの分け方や変数定義時のTipsなど、こちらも実用的なお話でした。ブログの方で、このスライドに肉付けする形でパペウィキの方に書いて行きたいとありましたが、ノウハウをまとめる試みはとてもいいですね。僕も貢献したいです。

それにしても、お二人と話していて共通して言われたのは、ノード管理はLDAPを使わないのがセオリーぽいことです。puppetrunを使うためにLDAPを使うのがベターなのかと思っていましたが、別にLDAPを使わなくてもやろうと思えばできるということでした。このあたりはよく分かっていないので、これから試してみます。

それから、発表でも分かるようにcobblerとの組み合わせが便利なようです。

刺激的で楽しい会でした。

カカクコム&クックパッド共催・勉強会で発表しました

10月17日(金)にクックパッドで開催された勉強会で発表しました。
スライドはクックパッド開発者ブログに置いてあります。

というか、発表でここのブログを紹介しておきながら全然更新していなかったので、久しぶりに更新してみました。

ところで、wordpressslideshareにアップロードしたスライドを貼付けるのに苦労したのでメモ。

苦労したところは二つあります。