KVMとlibvirtによるサーバ仮想化の4つのポイント
Linuxの仮想化技術であるKVMが広まりつつあります。昨年の今頃はWindowsゲストが起動しただけで感動してましたが、今や多くのディストリビューションで動くようになりました。
デスクトップ内の開発環境として使う場合はオールインワンですぐ使えることが大事ですが、サーバとして使う場合は事前によく考えて設計します。止まらないサーバとして運用していくためには、後で手間を掛けないよう環境を設計することが大事です。
ここでは、KVMで仮想化環境を構築する時のポイントを紹介します。
1. ログ管理や認証の共通化
Webサーバ、プライベートWebサーバ、DBサーバというようにVMゲストが増えていくと、それらを管理する手間が半端なくなります。うちでは下記の項目を共通サーバで集中管理しています。
項目 | VMゲスト | 共通サーバ |
---|---|---|
認証 | LDAP認証(nss_ldap) | LDAPサーバ(OpenLDAP) |
ログ管理 | syslog送信(syslog-ng) | syslog受信(syslog-ng) |
ファイル共有 | NFSクライアント(automount/nfs4) | NFSサーバ(nfs4) |
メール送信 | ssmtp | Postfix |
DNS | DNSクライアント | DNSサーバ(dnsmasq) |
NTP | NTPクライアント | NTPサーバ |
2. libvirtによる構成の共通化
VMゲストを作成する時に手間が掛からないよう、libvirt XMLのテンプレを作成しておきます。
<domain type='kvm'> <name><!--名前--></name> <uuid><!--uuidgenで生成--></uuid> <memory>524288</memory> <currentMemory>524288</currentMemory> <vcpu>1</vcpu> <os> <type>hvm</type> <kernel>/boot/kvm.current/vmlinuz</kernel> <cmdline>root=/dev/vda</cmdline> </os> <features> <acpi/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/bin/kvm</emulator> <disk type='block' device='disk'> <source dev='/dev/vg/##.root'/> <target dev='vda' bus='virtio'/> </disk> <disk type='block' device='disk'> <source dev='/dev/vg/##.var'/> <target dev='vdb' bus='virtio'/> </disk> <disk type='block' device='disk'> <source dev='/dev/vg/##.swap'/> <target dev='vdc' bus='virtio'/> </disk> <interface type='ethernet'> <mac address='52:54:00:61:##:01'/> <script path='/etc/kvm/tun-start'/> <downscript path='/etc/kvm/tun-stop'/> <target dev='tun##'/> <model type='virtio'/> </interface> <graphics type='vnc' port='59##' autoport='no'/> <console type='pty'> <source path='/dev/pts/##'/> <target port='0'/> </console> </devices> </domain>
上記のXMLは ## を埋めるだけで動きます。VMゲスト毎にVMIDを割り当てておくと管理が楽になります。例えば、VMID=65のVMゲストpublicでは下記になります。
項目 | 決め方 | 例 |
---|---|---|
カーネル | すべて同じものを使用。 | /boot/kvm.current/vmlinuz |
ディスク | LVMの論理ボリュームを使用。 | /dev/vg/public.root |
ネットワーク | VMゲストのサブネットを分割して割り当てる。 | 172.16.65.0/24 |
インタフェース | VMIDを付加する。 | tun65 |
VNCポート | VMIDを付加する。 | 5965 |
QEMUコンソール | VMIDを付加する。 | /dev/pts/65 |
カーネルはVMホストであらかじめ用意したイメージを指定します。QEMUの引数にはカーネルイメージのパスを渡すこともできるので、VMゲストにブートローダを入れなくても起動します。
VMホストが起動した時、必要なVMゲストが自動的に起動するようにしておきましょう。virsh autostartコマンドで設定できます。
3. 論理ボリュームを使う
仮想ディスクはイメージファイル(VMwareいうところのvmdk)でも良いですが、ファイルシステムのオーバーヘッドを考えるとrawデバイスの方が良いでしょう。実測していないので差は分かりませんが。
LVMを使うと3つの利点があります。
- 仮想ディスクを別のHDDに移動する時にVMゲストを止めずに済みます。無停止で論理ボリュームを移動できるLVMの機能です。
- iostatで別のデバイスとして表示されるのでボトルネック調査が容易になります。例えば下記のように、DBサーバが他よりI/O帯域を食っているといったことが分かります。
# iostat -kN 3 Linux 2.6.30-gentoo-r4 (management) 10/27/09 _x86_64_ (2 CPU) avg-cpu: %user %nice %system %iowait %steal %idle 1.50 0.01 0.76 0.30 0.00 97.42 Device: tps kB_read/s kB_wrtn/s kB_read kB_wrtn sda 7.41 20.41 81.74 40356551 161598758 sdb 7.34 22.43 81.74 44349475 161598762 md2 25.19 42.84 78.88 84687436 155947070 vg-aj.home 0.46 15.98 5.70 31601540 11276952 vg-public.root 0.12 0.65 0.15 1289338 303211 vg-private.root 1.50 5.57 0.41 11008628 815908 vg-db.root 7.48 0.06 29.85 114855 59016789
4. iptablesによる共通ファイアウォール
VMゲストとVMホストはブリッジで接続するのが一般的と思いますが、VMゲスト間の通信を制御できないというデメリットがあります。VMゲストとVMホストをルータで接続すると、VMホスト間の通信をiptablesで制御できるようになります。
ブリッジではVMホストの属するサブネットからIPアドレスを1つ割り当てる方法を採っていましたが、ルータでは別のサブネットを割り当てます。例えば、VMゲストに172.16.65.0/24を割り当てるとすると、下記の構成を取ります。
IPアドレス | インタフェース |
---|---|
172.16.65.1 | VMゲストのeth0 |
172.16.65.254 | VMホストのtun65 |
192.168.100.1 | VMホストのeth0 |
192.168.100.2 | 別マシン(hoge)のeth0 |
hogeからvmguestにpingを送る経路は以下のようになります:
- 192.168.100.2 → 192.168.100.1 → 172.16.65.254 → 172.16.65.1
気付いた方もいると思いますが、hogeに経路情報を教えてあげないと届きません。hogeのデフォルトゲートウェイを192.168.100.1とするか、hogeにVMゲストへの経路情報を登録します。
宛先 | ゲートウェイ |
---|---|
172.16.65.0/24 | 192.168.100.1 |
VMホストではiptableでIPパケットの流れを制御します。複数のNICを差した時と同じように設定します。うちでは下記のようなポリシーを設定しています。
source | destination | protocol | policy |
---|---|---|---|
ホームLAN | VMゲストセグメント | ssh/22 | accept |
ホームLAN | VMゲストセグメント | rdp/3389 | accept |
監視サーバ | VMゲストセグメント | snmp/161 | accept |
VMゲストセグメント | 共通サーバ | syslog/514 | accept |
VMゲストセグメント | 共通サーバ | ldap/389 | accept |
VMゲストセグメント | 共通サーバ | nfs4/2049 | accept |
VMゲストセグメント | 共通サーバ | smtp/25 | accept |