Linux カーネル仮想マシンを探る

KVM のアーキテクチャーとその利点について学ぶ

Linux® と柔軟性は切り離せないものですが、仮想化のオプションにしてもそれは同じことです。しかし最近では、カーネル仮想マシン (KVM)の登場によって Linux 仮想化の全体像が変わってきています。KVM は主流の Linux カーネル (V2.6.20) に統合される初の仮想化ソリューションです。Linuxゲスト・オペレーティング・システムの仮想化をサポートする KVM は、Windows® でさえも仮想化を認識するハードウェアでサポートします。この記事で、LinuxKVM のアーキテクチャーについて、そして Linux KVM と Linux カーネルとの統合が Linux の使い方を変えるかもしれない理由について学んでください。

M. Tim Jones (mtj@mtjones.com), Consultant Engineer, Emulex

M. Tim JonesM. Tim Jones は組み込みソフトウェアのエンジニアであり、『GNU/Linux Application Programming』や『AI Application Programming』(現在、第 2 版)、それに『BSD Sockets Programming from a Multilanguage Perspective』などの著者でもあります。技術的な経歴は静止軌道衛星用のカーネル開発から、組み込みシステム・アーキテクチャーやネットワーク・プロトコル開発まで、広範にわたっています。また、コロラド州ロングモン所在のEmulex Corp. の顧問エンジニアでもあります。



2007年 4月 18日

はじめに

仮想化はかなり前からある概念で、手短に言えば、あるものを取り上げて別のように見せるというプロセスです。この概念をコンピューター・システムに適用すると、ユーザーによって1 つのシステムをさまざまに見せることができます (単一のコンピューターで Linux と Microsoft® Windows®を同時に実行するなど)。これは、一般的に完全仮想化と呼ばれる手法です。

KVM と kvm

この記事では、カーネル仮想マシンについて説明するときには KVM と呼び、ハイパーバイザー・ユーティリティー (新しい仮想マシンを開始するために使用)について説明するときには kvm と呼びます。

それよりも複雑な形の仮想化では、単一のコンピューターを複数のアーキテクチャーのように見せます (あるユーザーに対しては標準 x86 プラットフォーム、別のユーザーに対してはIBM Power PC® プラットフォームに見せるなど)。このような仮想化は、ハードウェア・エミュレーションとして一般に知られています。

そして仮想化の単純な形は、オペレーティング・システムの仮想化です。この場合、1 台のコンピューターが同じ種類のオペレーティング・システムを多数実行します。このような仮想化は、単一のオペレーティング・システム上で複数のサーバーに分離しているだけのことです(つまり、すべてのサーバーが同じ種類でかつ同じバージョンのオペレーティング・システムを使用しなければなりません)。仮想化の手段についての詳細は、「参考文献」を参照してください。


仮想化と疑似仮想化

仮想化で最もよく使われる手法は、完全仮想化と疑似仮想化の 2 つです。完全仮想化では、仮想化されたオペレーティング・システムとハードウェアとの間に、アクセスを調停する手段としてレイヤーが存在します。このレイヤーはハイパーバイザー、または仮想マシン・モニター(VMM) と呼ばれます。疑似仮想化もこれと同様ですが、ハイパーバイザーは完全仮想化の場合よりも、より連携的な動作をします。その理由は、それぞれのゲスト・オペレーティング・システムは、それぞれのゲスト・オペレーティング・システム自体が仮想化されていることを認識し、ハイパーバイザーと連携して基盤となるハードウェアを仮想化するからです。

完全仮想化の例には、市販の仮想化ソリューションである VMware、同じく市販の IBM zSeries® コンピューター対応 IBMSystem z9 Virtual Machine (z/VM) オペレーティング・システムがあります。一方、疑似仮想化を提供しているのは Xenおよび User-Mode-Linux (UML) です。KVM も完全仮想化ソリューションであると考えられますが、これについては後で取り上げます。


仮想化の仕組み

まず初めに、仮想化および関連する要素について簡単に説明しておきましょう。仮想化ソリューションの基盤にあるのは、仮想化対象のマシンです。このマシンは仮想化を直接サポートする場合もあればしない場合もあります。直接サポートしない場合は、ハイパーバイザーと呼ばれるその上のレイヤーによるサポートが必要です。ハイパーバイザー(すなわち VMM) は、プラットフォーム・ハードウェアとオペレーティング・システムとの間の抽象化レイヤーとして機能します。場合によってはハイパーバイザーがオペレーティング・システムであることもありますが、その場合はホスト・オペレーティング・システムと呼ばれます(図 1 を参照)。

図 1. 仮想化の抽象化レイヤー
図 1. 仮想化の抽象化レイヤー

ハイパーバイザーの上にあるのは、仮想マシン (VM) とも呼ばれるゲスト・オペレーティング・システムです。VM は分離されたオペレーティング・システムで、基盤にあるハードウェア・プラットフォームをVM に所属するものとして見ています。ただし実際には、ハイパーバイザーがこのように錯覚させているだけです。

プロセッサーによる仮想化サポート

プラットフォームを仮想化するメリットは誰もが認めるところなので、プロセッサーのベンダーは仮想化を直接サポートするようにシリコン・チップの設計を変更しています。そうすることで、プロセッサーはゲスト・オペレーティング・システムとは異なる方法でハイパーバイザーを直接サポートすることが可能になります。つまりプロセッサーの状態 (レジスターなど) が VMM と VM に対して別々に管理されるだけでなく、これらのプロセッサーは入出力と割り込みの仮想化もサポートします。詳しくは、「参考文献」を参照してください。

今日の仮想化ソリューションにおける問題は、すべてのハードウェアが仮想化を正しくサポートするわけではないという点です。以前の x86 プロセッサーは特定の命令に対して、実行するドメインによって異なる結果を出しますが、ハイパーバイザーは最も保護されたドメインでのみ実行すべきものなので、ドメインによって結果が異なると問題になります。このため、VMwareなどの仮想化ソリューションは実行対象のコードを事前にスキャンし、これらの命令をトラップ命令に置き換えてハイパーバイザーが適切に処理できるようにします。その一方、連携による仮想化の方法をサポートするXen は変更を必要としません。ゲスト・オペレーティング・システムが仮想化されていることをゲスト・オペレーティング・システム自体が認識して変更が行われるためです。KVMの場合はこの問題を単に無視し、仮想化を行う場合には最近のハードウェアで実行することを要件としています。

KVM のこの要件は最初、少々手荒い処置だと思うかもしれませんが、現在登場していきているマシンが (Intel® VT や AMDSVM のように) 仮想化をサポートすることを考えれば、例外というよりむしろ標準になる日が近いはずです。仮想化をサポートするプロセッサーについての詳細は、「参考文献」と囲み記事「プロセッサーによる仮想化サポート」を参照してください。


KVM ハイパーバイザー

仮想化手法の歴史から考えると、KVM はどちらかと言うと新参者です。現在、現役のオープン・ソースの仮想化手段としては Xen、Bochs、UML、Linux-VServer、coLinuxなどがありますが、KVM はそのなかでも驚くほどの話題を集めています。さらに、KVM 自体は完全な完全仮想化方式ではなく、むしろそれより規模の大きいソリューションの一部です。

KVM で採用している手法は、カーネル・モジュールを単にロードするだけで Linux カーネルをハイパーバイザーに変換するというものです。カーネル・モジュールがエクスポートする/dev/kvm というデバイスによって、(従来のカーネル・モードとユーザー・モードに加えて) ゲスト・モードのカーネルが有効になります。/dev/kvmでは、VM がカーネルや実行中の他の VM が持つアドレス空間とは別の独自のアドレス空間を持ちます。デバイス・ツリー (/dev) 内のデバイスは、すべてのユーザー空間プロセスに共通しますが、/dev/kvmは、このデバイスをオープンする各プロセスが異なるマップを参照するという点で他のデバイスとは異なります (これは、VM の分離をサポートするためです)。

Linux カーネル内の KVM ソース

KVM のソースは ./linux/drivers/kvm にあります (V2.6.20 以降の場合)。このディレクトリーには、KVM のソース・ファイルと、Intelおよび AMD 拡張用のプロセッサー・サポート・ファイルが含まれます。

kvm カーネル・モジュールをインストールすると、KVM は Linux カーネルをハイパーバイザーに変換します。ハイパーバイザーである標準Linux カーネルは、標準カーネルに対する変更 (メモリー・サポート、スケジューラーなど) を利用します。これらの Linux コンポーネントの最適化(2.6 カーネルでの新規 O(1) スケジューラーなど) は、ハイパーバイザー (ホスト・オペレーティング・システム) と Linux ゲスト・オペレーティング・システムの両方にとってメリットがありますが、このような方法を用いるのはKVM が初めてではありません。UML でも以前から Linux カーネルをハイパーバイザーに変換していました。カーネルをハイパーバイザーとして機能させることで、別のLinux カーネルや Windows などの他のオペレーティング・システムを起動することができるのです。


KVM

KVM がインストールされると、ユーザー空間でゲスト・オペレーティング・システムを起動できるようになります。それぞれのゲスト・オペレーティング・システムは、ホスト・オペレーティング・システム(ハイパーバイザー) の単一のプロセスとして動作します。図 2 は、KVM による仮想化の概略図です。基盤にあるのは、仮想化に対応可能なハードウェア・プラットフォーム (現在は、Intel VT またはAMD-SVM プロセッサーのいずれか) で、そのハードウェア上で直接実行するのはハイパーバイザー (KVM モジュールを備えた Linuxカーネル) です。通常の Linux カーネルとまったく同じように見えるこのハイパーバイザーでは、その他すべてのアプリケーションを実行できますが、さらにkvmユーティリティーによってロードされたゲスト・オペレーティング・システムをもサポートすることができます。ゲスト・オペレーティング・システムがサポートできるアプリケーションは、ホスト・オペレーティング・システムがサポートできるアプリケーションと同じアプリケーションです。

図 2. KVM による仮想化のコンポーネント
図 2. KVM による仮想化のコンポーネント

前述したように、KVM は仮想化ソリューションの一部となっています。このソリューションでは、プロセッサーが仮想化を直接サポートします (複数のオペレーティング・システム用にプロセッサーを仮想化することが可能)。メモリーはkvm によって仮想化され (これについては、次のセクションで説明します)、入出力は多少変更された QEMU プロセスによって仮想化されます(この QEMU プロセスのコピーはそれぞれのゲスト・オペレーティング・システムのプロセスを使って実行します)。

KVM では既存のカーネル・モードとユーザー・モードに加え、ゲストという新しいプロセス・モードを Linux に導入しています。その名前からわかるように、ゲスト・モードはゲスト・オペレーティング・システムのコード(あるいは少なくともその一部) を実行する際に使用されます。カーネル・モードはコード実行に対する特権モードのことを表しており、ユーザー・モードは特権のないモード(カーネルの外側で実行されるプログラム用) を表しているということを思い出してください。つまり、実行のモードは、実行する内容と目的に基づいてそれぞれの用途が定義されるということです。ゲスト・モードは、ゲスト・オペレーティング・システムのコードを実行するためのモードですが、実行対象となるのは入出力以外のコードです。ゲスト・モード内には標準の2 つのモードが含まれるので、ゲスト・オペレーティング・システムはゲスト・モードで実行されていても、そのカーネルとユーザー空間のアプリケーションに対しては標準カーネルとユーザー・モードをサポートします。ゲスト・オペレーティング・システムのユーザー・モードは、単独で管理される入出力の実行を目的とします。

ゲスト・オペレーティング・システムからの入出力の実行は、QEMU によって行われます。QEMU は、PC 環境全体 (ディスク、グラフィック・アダプター、ネットワーク・デバイスを含む)の仮想化を実現するプラットフォーム仮想化ソリューションです。ゲスト・オペレーティング・システムによる入出力要求はすべてインターセプトされ、ユーザー・モードにルーティングされて、QEMUプロセスによってエミュレートされます。

KVM は、/dev/kvm デバイスによってメモリーを仮想化します。それぞれのゲスト・オペレーティング・システムは、インスタンス化されるときに独自のアドレス空間がマッピングされます。つまり、ゲスト・オペレーティング・システム用にマッピングされる物理メモリーは、実際にはこのプロセスにマッピングされた仮想メモリーということになります。また、一連のシャドー・ページ・テーブルが維持されて、ゲストの物理アドレスからホストの物理アドレスへの変換がサポートされます。プロセッサーは、マッピングされていないメモリー位置がアクセスされた場合にはハイパーバイザー(ホスト・カーネル) を活用することで、メモリーの変換プロセスもサポートします。


新規ゲストのインスタンス化

新しいゲスト・オペレーティング・システムをインスタンス化するのは、kvm と呼ばれるユーティリティーです。kvm モジュールと連動するこのユーティリティーは、/dev/kvm を使用してゲストをロードし、仮想ディスク (ホスト・オペレーティング・システム内の通常のファイル)を関連付けてからブートします。

制御をサポートするのは、/dev/kvm デバイス上で実行される一連の ioctl です。まず特殊なファイルがオープンされ、仮想 CPU と関連付けられたVM オブジェクトが新規に作成されます。新規 VM オブジェクトが作成されると、ioctl による仮想 CPU の作成、kvm バージョンのチェック、メモリー領域の作成、そして仮想 CPU の起動が可能になります。これらの操作には kvm コマンドを使用するわけですが、以降のセクションでこのコマンドについて説明し、サポートされる ioctl の例をいくつか紹介します。


KVM の使用方法

ハードウェアが KVM をサポートしていれば、KVM は極めて簡単に使用できます。そこで必要となるのが、仮想化をサポートするプロセッサーです。システムが仮想化をサポートするかどうかを判断するには、/proc/cpuinfoを調べてください。このファイルに、vmx (Intel) または svm (AMD) 拡張がサポートされるかどうかが指定されています。

次に必要なのは、Linux カーネルの KVM サポートを有効にすることです。それには Device Drivers > Virtualizationのカーネル構成を操作します。使用している環境に対応するプロセッサー・サポートも有効にしてください。さらに、kvm および qemu のユーザー空間アプリケーションも必要です。詳細は、「参考文献」を参照してください。

次のステップは、仮想化サポートを有効にしてブートしたカーネルを使用して、ゲスト・オペレーティング・システムのディスク・イメージを作成することです。このステップには、以下に示すqeumu-img を使います。イメージのサイズは 4 GB となっていますが、QEMU のコピー・オン・ライト・フォーマット (qcow) を使うと、ファイルは4 GB いっぱいを使用するのではなく、必要に応じて大きくなります。

  $ qemu-img create -f qcow vm-disk.img 4G

仮想ディスクを作成したら、そこにゲスト・オペレーティング・システムをロードします。以下の例では、ゲスト・オペレーティング・システムが CD-ROM上にあるという前提になっています。仮想ディスクに CD-ROM ISO イメージを入力したら、そのイメージをブートしてください。

$ kvm -no-acpi -m 384 -cdrom guestos.iso -hda vm-disk.img -boot d

Ari Kivity が、完全なデバイス・モデルを使わずに KVM をテストする一連のテスト・ツールを作成しています。以下のコード・スニペット(kvm-12/user/main.c からの抜粋) を見ると、VM 起動の概要がわかります (リスト 1 を参照)。制御機能は、カーネル内の ioctl によって提供されます (具体的には、./linux-2.6.20/drivers/kvm/kvm_main.cファイル内)。

kvm_init を呼び出すことで /dev/kvm デバイスをオープンし、(KVM カーネル・モジュールによってエクスポートされた) バージョン番号をチェックしてからKVM コンテキスト・オブジェクトを割り当て、いくつかのコールバック関数に入力します。kvm_create 関数は、2 つのメモリー領域を設定してマッピングし、ioctl (KVM_CREATE_VCPU) を使って仮想 CPU (VCPU) を作成します。

次に load_file 関数によって、指定された VM のアドレス空間にこのイメージがロードされます。この VM は、 kvm_run の呼び出し (ioctl KVM_RUN を使用) によって実行されます。このプロセスは単純ですが、これを見ると KVM で新規ゲスト・オペレーティング・システムをインスタンス化する方法がわかります。

リスト 1. KVM ハイパーバイザーをテストするアプリケーションのスニペット
int main()
{
        void *vm_mem;

        kvm = kvm_init(&test_callbacks, 0);
        if (!kvm) {
            fprintf(stderr, "kvm_init failed\n");
            return 1;
        }
        if (kvm_create(kvm, 128 * 1024 * 1024, &vm_mem) < 0) {
            kvm_finalize(kvm);
            fprintf(stderr, "kvm_create failed\n");
            return 1;
        }
        if (ac > 1)
            if (strcmp(av[1], "-32") != 0)
                load_file(vm_mem + 0xf0000, av[1]);
            else
                enter_32(kvm);
        if (ac > 2)
            load_file(vm_mem + 0x100000, av[2]);
        kvm_show_regs(kvm, 0);

        kvm_run(kvm, 0);

        return 0;
}

最終的な考察

KVM は仮想化の問題に対する興味深いソリューションですが、カーネルに統合されたソリューションとしては初めてのものなので、サーバーの仮想化としての支持をすぐに得られるであろうことを思い描かずにはいられません。他の手法も長いことカーネルへの統合をめぐって競争してきましたが(UML や Xen など)、KVM には必要な変更がほとんどないこと、そして標準カーネルをハイパーバイザーに変換可能なことから、この KVMが選ばれた理由は明らかです。

KVM にはもう 1 つのメリットもあります。それは、KVM 自体がカーネルの一部であるため、カーネルの最適化と進歩を利用できるという点です。このメリットが、他の独立したハイパーバイザー・ソリューションに勝る将来の保証をKVM に与えています。一方、KVM の最大の欠点は、仮想化に対応するより新しいプロセッサーが必要なこと、そしてユーザー空間の QEMU プロセスが入出力の仮想化を行わなければならないことの2 点です。ですが良し悪しは別として、KVM がカーネルに組み込まれているということが、KVM を大きく飛躍させ、既存のソリューションを大きく引き離しています。

参考文献

学ぶために

  • さまざまな仮想化の方法について学ぶには、記事「仮想 Linux」(developerWorks、2006年12月) を読んでください。
  • IBMIntelAMDをはじめとする各社が仮想化ハードウェアを提供しています。詳細については、それぞれのサイトを調べてください。
  • KVM に関する最新情報は、Qumranet が提供する KVM wiki で調べてください。
  • KVM が登場してからまだ日は浅いものの、そのパフォーマンスをいくつかの分野で検討した記事はいろいろとあります。なかでも、 PhoronixKernelNewbiesにそれぞれ興味深い記事が記載されています。
  • KernelNewbies には、仮想化方法 (KVM を含む) を比較した、優れた記事も記載されています。
  • Ingo Molnar によって作成された V2.6 Linux スケジューラーは O(1) スケジューリングを実現します。 「Linux スケジューラーの内側」(M. Tim Jones著、developerWorks、2006年6月) では、このスケジューラーについて詳しく説明しています。
  • 連携仮想化手法である coLinuxでは、Linux を Windows で実行できます。
  • オープン・ソースのプロセッサー・エミュレーターであるQEMUも、KVM に合わせた PC 環境仮想化機能を提供します。
  • developerWorks Linux ゾーンには、Linux 開発者用の資料が豊富に揃っています。
  • developerWorks technical events and Webcastsで最新情報を入手してください。

製品や技術を入手するために

  • KVM に必要なアプリケーションをダウンロードするには、 Debianを調べてください。
  • developerWorks から直接ダウンロードできる IBM トライアル・ソフトウェアを使用して、Linux で次の開発プロジェクトを構築してください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=Linux, Open source
ArticleID=245805
ArticleTitle=Linux カーネル仮想マシンを探る
publish-date=04182007