GeekFactory

int128.hatenablog.com

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つの利点があります。

  1. 仮想ディスクを別のHDDに移動する時にVMゲストを止めずに済みます。無停止で論理ボリュームを移動できるLVMの機能です。
  2. 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
  1. VMゲストを物理マシンとして動かすことが容易になります。新しいHDDに論理ボリュームを移動し、ブートローダをインストールするだけです。

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とするか、hogeVMゲストへの経路情報を登録します。

宛先 ゲートウェイ
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

まとめ

駆け足での説明になりましたが、ちょっと構成を変えるだけで管理コストを大幅に改善できます。VMゲストの数が増えてきた場合は設計を見直すとよいでしょう。このエントリで書いた内容はマニアックな使い方に見えますが、広く使われている構成技術を組み合わせただけです。フリーでここまで遊び倒せるのが楽しい。

文章だけで説明するのは難しいですねー。パワポで書きたいです。