KVM = Kernel-based Virtual Machine の中核は Linux カーネルのローダブルモジュールで、QEMU と協力してホストOS上で仮想マシンを実行することができる。Xen と異なるのは、Xen が Nemesis という異種OS をハイパーバイザとし、ホストOS はその上で動く特権ゲストと位置づけられるのに対して、KVM では Linux ホストOS 自体がハイパーバイザとなり、個々のゲストプラットフォームが各々ひとつのプロセスとして実行される点だ。また、Xen がフルバーチャライゼーション (完全仮想化) とパラバーチャライゼーション (準仮想化) の両方を提供しているのに対して、KVM はフルバーチャライゼーション専用。そのため、ゲストOS のカーネルを Xen 用に改変してハイパーバイザとの話し方を教えてやるというようなことが必要ない。完全仮想化によるオーバーヘッドは QEMU だけでは確かに無視できないレベルなのだが、KVM と併用する QEMU (qemu-kvm) は /dev/kvm デバイスを通じてハイパーバイザと遣り取りをするようチューンナップされたものなので、オーバーヘッドはかなり低減されている。このあたりの記事なら、IBM の `Discover the Linux Kernel Virtual Machine' (英語) / 「Linux カーネル仮想マシンを探る」(日本語) がよくまとまっている。
また、更に最近になって、virtio という仕組みが導入された。KVM ではこれまで、例えば NIC なら RTL8139 だったりドライブのバスなら IDE だったりと、実在する一般的なハードウェアをエミュレートしてゲストOS に提供し、ゲストOS はそれを仮想ハードウェアだとは知らずに使用していた。しかし、virtio では、ゲストOS に virtio ドライバをインストールすることによって、NIC やディスクなど一部のデバイスではあるが Xen の準仮想化のように高速なアクセスが可能となった。そうしたドライバのことを 準仮想化ドライバ (Para-virtualized Driver) と呼んでいるようだ。
ホストOS としての検証は、以下のディストリビューションで行なった:
ハイパーバイザとなるホストOS 及びハードウェアの要件などについて述べる。
KVM は CPU の備える仮想化構造 (x86仮想化) を利用しているため、マシンの CPU が x86仮想化機能を持ち、チップセット、BIOS ともそれを活用できるものでなければならない。搭載メモリ量は、ゲストに分け与える分を勘案すると最低 2GB、複数のゲストを載せるなら 4GB 以上を実用上の最低ラインと考えるべきだろう。
KVM + QEMU を実行するのに Xen カーネルのような特別なカーネルは必要ない。KVM コードの採用されたカーネルが動作していればOKだ。KVM のコードは Linux カーネル 2.6.20 からメインストリームにマージされた。ただし、RedHat 系では、2.6.18-x 台の途中から、KVM パッチを適用したカーネルパッケージが提供され始めている。Fedora Core 9 では元来 2.6.20 以降なので問題なし。RHEL 5/CentOS 5 では、後述の KVM パッケージのインストール時に依存関係がチェックされて、必要であれば KVM パッチ適用済みのカーネルもインストールされる。
ゲストへ virtio によるディスクやネットワークの提供を行ないたい場合には、Virtio のオフィシャルページによると、ホストOS にはカーネル 2.6.25 以降と KVM Ver.60 以降が必要とある。ただし、カーネルバージョンはそれ以前でも、RHEL/CentOS の 5.4 (kernel-2.6.18-164) 、Fedora 9 のいずれも、virtio の提供が可能だった。Fedora 10 は kernel-2.6.27 なので当然対応している。
ホストOS を 32ビット版にするか 64ビット版にするかは、載せるゲストをどちらにするかによって計画しておく必要がある。KVM 用でない素の QEMU の PC アーキテクチャ版実行プログラム (qemu-system-x86_64) は、基本的に 32ビットと 64ビットの区別がなく、32ビットホストの上で 64ビットのゲストプラットフォームを提供することも可能だが、KVM 用の QEMU (qemu-kvm) では、64ビットゲストは 64ビットホスト上でしか動かすことができない。また、物理メモリ量との兼ね合いから言えば、64ビットカーネルなら自ずと 4GB 以上の物理メモリを認識できるのに対して、32ビットでは PAE 版のカーネルが必要となることも忘れてはいけない。結論的には、x86仮想化機能を搭載した CPU はそのほとんどが 64ビットであることからして、ホストOS は 64ビット版にしておくほうが妥当だろう。
なお、ホストOS のインストール時に、筆者の好みでは 仮想化 パッケージグループは選択しない。今のところ、Xen のコンポーネントも一緒に根こそぎインストールされてしまうようだからだ。
ゲストに何をハードディスクとして提供するかは、Xen と同様に主に3つの方法がある。ひとつのディスクイメージファイルをひとつのディスクとしてエミュレートする方法、ディスクパーティションをディスクに見せる方法、LVM の LV をディスクに見せる方法だ。
イメージファイルを利用する場合は、/var/ 配下に格納するので、/var は別パーティションとして切り、サイズもたっぷりととる。
ディスクパーティションをゲストディスクとして使う場合は、インストール時にはそれらパーティションを切らずに、空き領域として残しておく。インストール時に切ってしまうとフォーマットさせられたりマウントされてしまったりと面倒だ。
LVM を利用して LV をゲストディスクとして見せる場合は、後で作る PV 用に、空き領域を残しておく。インストール中に PV と VolumeGroup だけ作成 (LV は作らない) しておくという手もある。
とりあえず、ホストOS を単独で使用する時と同様に設定しておく。少々解説が必要なので別項とした。
依存関係で悩まずにすむように、基本的に yum を使って追加インストールを行う。
パッケージ | コメント |
kvm | kvm カーネルモジュールと、kvm 用にコンパイルされた qemu (/usr/libexec/qemu-kvm) など。 |
virt-manager | ゲストOS のインストールや定義、削除、起動/停止などを行う GUI アプリケーション。yum でインストールすれば、libvirt, xen-libs, bridge-utils, qemu-img なども引きずられて入る。ディストリビューションによっては、kvm には必須でない qemu パッケージ (/usr/bin/qemu-system-x86_64 等) もインストールされる。 |
xen-runtime | Fedora Core にはあるが RHEL/CentOS 5.x には存在しない。シェルスクリプトなど、Xen を動かす時に使われるツール群で、Xen カーネルや xend デーモンは含まれない、いわば xen パッケージのミニセット。仮想ネットワーク (ブリッジ) をパートタイム的に使いたい場合には、/etc/xen/scripts/ 下のスクリプト群があると便利なのでインストールする。ブリッジを恒久的に作っておく方式なら不要だ。こうしたスクリプトは RHEL/CentOS 5 では xen 本体パッケージにしか含まれていない。 |
パッケージ | コメント |
tunctl | 後で出てくる TAP ネットワークデバイスを操作するユーティリティコマンド。実際には QEMU が内部的に面倒を見てくれるのでどうしても要るというわけではないが、研究のために入れておくとよい。 |
virtio-win | RHEL 5.4 にのみある。Windows ゲストのための virtio ドライバ集。2010/1/31 時点では、Windows Server 2003 と 2008 (ともに i386 及び amd64) のブロック(ディスク)ドライバとネットワークドライバが含まれている。Windows Server 2008 64ビット用のドライバはちゃんと署名されている。詳しくは後述。 |
virtio Windowsドライバ | ホストが CentOS や Fedora Core の場合は、KVM のサイトから最新の virtio ドライバを入手すべし。2010/1/31 現在、ブロックドライバは Vista/7/2003/2008 の x86 及び amd64 と、XP の x86。ネットワークドライバは Vista/7/XP/2003/2008 の x86 及び amd64 と、Windows 2000 用が含まれている。ただし、いずれのドライバも署名はされていない。これらと同じドライバを ISO イメージにまとめたものを、"/contrib/famzah" というサイトが提供してくれている。詳しくは後述。 |
上記のもの、特に kvm と libvirt をインストールしたら、次の作業に取りかかる前に、kvm カーネルモジュールをロードさせたり libvirtd を起動させるために、ホストOS を一度リブートさせる。
基本的には Xen で利用する仮想ネットワークと同じで、QEMU/KVM でも、ゲストの仮想ネットワークインターフェイスはホストOS のブリッジを介してホストや外界と通信を行なう。ただし、QEMU/KVM は、仮想プラットフォームの生成時に TAP デバイスというものを作成してブリッジにつなぎ込んでくる仕組みになっている (TAPの説明は TUN/TAP - Wikipedia, the free encyclopedia や kernel.orgのtuntap.txt 参照のこと)。
当ページでは、libvirt を併用するので、libvirtd によって作成される仮想スイッチと、ホストOS とも外部とも同サブネットで遣り取りできるブリッジの、どちらも利用できる。これも、Xen でやったのと同じだ。図式しておこう。
例として、ふたつのゲストOS があるとしよう。
図のゲスト#1 は libvirtd の仮想スイッチに接続させており、仮想スイッチ virbr0 の NAT 機能を介してマシン外界と通信ができる。ただしこちらの場合、ゲスト -> 外界方向のコネクションは成立するが、そのままでは外界からゲストに向かって接続をイニシエートすることはできない。ホストOS との通信は両方向ともできる。
ゲスト#2 では、物理デバイスへとつながる単純なブリッジをホストOS 上にあらかじめ作成しておき、ゲストをそこへ接続させている。この方法だと、ホスト上の eth0 ブリッジは単純なハブのように機能するので、ゲスト#2 からホストや外界へはもちろん、外界からゲストへのコネクションも簡単に成り立つ。左図で、ホストOS 側の物理デバイスが peth0、ブリッジが eth0 という名前になっているが、これらの名前は、xen-runtime パッケージの提供する network-bridge スクリプトを利用する (パートタイムなブリッジ) か、ネットワークインターフェイススクリプト (ifcfg-*) を使って恒久的なブリッジを作るかによって違ってくる 。
上記は RedHat 系の OS で提供されている仮想ネットワークのフレームワークを紹介しただけであり、例えばノード内だけで通信可能な閉鎖系 LAN を追加したり、いろいろと応用が利く。それらについては既出の内容と重複するので、Xen のページの「Xenネットワーク」や「Xenネットワーク クイックレシピ」の節を参照していただきたい。libvirtd の起動時に自動的に作られる virbrX 仮想スイッチについても、設定方法は Xen の時と変わらないので、そちらを見ていただこう。ここでは、ちょっと工夫の要る単純ブリッジの作成方法についてのみ述べる。
やり方としては、通常の eth0 などと同様に sysconfig/network-scripts/ifcfg-* を整備して恒久的なブリッジを作る方法と、使いたい時 (つまりゲストを起動したい時) だけブリッジを生成するパートタームな方法とがある。通常は前者の恒久的な方法がいいだろう。
RHEL/Centos 5.4 及び Fedora Core 10 の initscripts では、ブリッジの作成と、それへの実インターフェイスの組み込みが ifcfg-* ファイルでできる (RHEL/CeontOS 5.3 以前や FC9 以前では未検証)。ここでは、ブリッジ br0 を生成し、実インターフェイス eth0 とつなげる例を示す。やるべき事は、/etc/sysconfig/network-scripts/ ディレクトリ下の ifcfg-br0 の新規作成と、ifcfg-eth0 の修正のふたつだ。
# Bridge interface 0 DEVICE=br0 TYPE=Bridge ONBOOT=yes BOOTPROTO=static IPADDR=192.168.0.5 NETMASK=255.255.255.0 DELAY=0
DEVICE=eth0 HWADDR=00:1f:e2:0c:78:1b <--もともと書いてあったなら残したまま ONBOOT=yes BOOTPROTO=none #IPADDR=192.168.0.5 <--コメントアウトするか削除 #NETMASK=255.255.255.0 <--コメントアウトするか削除 BRIDGE=br0 <--接続するブリッジ
あとは `service network restart' すればインターフェイスが出来上がる。ただしひとつだけ注意がある -- この設定以後、ホストマシンのゲートウェイデバイスは eth0 ではなく br0 になるので、サーバデーモンなどの設定ファイルでインターフェイス名を指定してあるものは、eth0 を br0 に書き換えなくてはならない。
物理インターフェイス eth0 を出入り口とするブリッジを、必要な時にだけ手動で生成する方法について述べる。この方法だと、いつでもまた元の物理 eth0 の状態に戻すことができる。ただし、RHEL 5.4 ホスト上ではこの方法はうまくいかなかった。Fedora Core 9/10 では問題なく動いている。
既に何度か言及したが、この方法では、xen-runtime パッケージによって提供される /etc/xen/scripts/network-bridge スクリプトを活用する。このスクリプトについては Xen のページでさんざん述べたのでそちらも参照していただきたい(特に "Fedora Core 8 における仮想ネットワーク" という章)。RHEL/CentOS 5.x にはそういうパッケージはなく、同様のスクリプト群は xen パッケージ本体にしか含まれていない。どうしてもインストールしたければ xen パッケージをインストールし、依存関係で入る kernel-xen を `rpm -e --nodeps' でアンインストールし、xend サービスと xendomains サービスをスタートアップから外すという手順で配備は可能だが、どうやら、RHEL/CentOS 5.x の network-bridge は、ホスト上で Xen が稼働し vethX があらかじめ存在していないと機能しない仕様のようだ。
network-bridge は下記のようなことをやっている。Fedora Core 8 以降の新型network-bridge と、RHEL/CentOS 5.x の旧型network-bridge とでは動作が異なり、下記は新型の動き;
これを確実にコントロールするため、やはり Xen のページ (特に "Xenネットワーク クイックレシピ" の "単純ブリッジとLAN用L3スイッチ(非NAT)" の項) で述べた、ラッパースクリプトセットを使う。
最小限の準備としては、
下記に、network-bridge-custom の内容を示す。より詳しい解説は "単純ブリッジとLAN用L3スイッチ(非NAT)" を参照のこと。
#!/bin/bash # network-bridge-custom 0.3.0 # Use with network-bridge-util > 0.3.0 dir=$(dirname "$0") # Resolv symbolic link for $dir if [ -L $0 ]; then link=$(ls -l $0 |cut -d' ' -f10) if grep -q / <<<$link ; then linkdir=${link%/*} if [ -z "$linkdir" ]; then dir= elif [ x${linkdir%%/*} = x ]; then dir=$linkdir else dir=${dir}/$linkdir fi fi fi . ${dir}/network-bridge-util ## Auto-detect VirNet variables. set_virnet_vars function do_bridge () { ## This is the very heart of network-bridge script. ${dir}/network-bridge "$@" bridge=eth0 netdev=eth0 antispoof=no #${dir}/network-bridge "$@" bridge=eth1 netdev=eth1 antispoof=no } case "$1" in status) do_bridge "$@" exit ;; *) ;; esac ## Iptables optimization. optimize_ipt ## This is the very heart of network-bridge script. do_bridge "$@" ## Disable kernel IP forwarding if there is no NAT bridges. disable_ipfwd ## Additional routing configuration. set_route /etc/xen/route.conf #sysctl -w net.ipv4.conf.eth1.rp_filter=1 &>/dev/null
以上の準備が整ったら、Xen の場合に xend が起動時にやっていたコールを、手動で唱えてやる。
root# /etc/xen/scripts/network-bridge-custom start
これで、前出の図に示した ホスト側の構造が出来上がる。ただし、tapX デバイスは実際に QEMU/KVM ゲストを立ち上げる際に作られるのでまだない。
逆に、peth0 を本来の eth0 に戻したくなった時には、
root# /etc/xen/scripts/network-bridge-custom stop
と唱えてやればいい。また、
root# /etc/xen/scripts/network-bridge-custom status
とコールするとブリッジ関係のステータスが表示される。
"/etc/xen/scripts/network-bridge..." というのは度々手動でコマンドするには長すぎる...。私と同意見なら、上記 network-bridge-custom ファイルへのシンボリックリンクだけを、PATH の通った場所 (例えば /usr/local/bin) に作ればいい。シンボリックリンクの名前も実体と異なって構わない。
上記の network-bridge-custom を OSブート時に SysV Init から呼べないかと思い、起動スクリプトを書いてみた。
これを /etc/init.d/ にコピーして実行ビットを立て、`chkconfig --add bridgectl' で各runレベルに登録すれば、一応機能することは確認した。だたし、起動順が曲者。network-bridge-custom が完璧に機能するためには libvirtd よりも後に起動されなければならない。しかし libvirtd の元々の起動序列は 97 と遅く、終了序列は 03 とかなり早いのだ。この bridgectl スクリプトでは起動順 98、終了順 02 にしてあるが、本当は libvirtd の起動順をもう少し早く、終了をもう少し遅く調整すべきかもしれない。さらに、後述する virtdomains (ゲストドメイン自動起動/終了スクリプト) を装備する場合、bridgectl は virtdomains より先に起動していなくてはならず、順序的にかなりタイトになってしまう。