~nabeken/diary/

Gentoo Linux(6年くらい)とFreeBSD(1年くらい)とOpenBSD(新参者)を使う日々。


IHANet BGP peering overview

Debian (squeeze) + KVM + libvirt + iSCSIへ移行した

Posted on Sun Mar 20 19:56:08 +0900 2011 by nabeken

先日Xen 4.0へ移行した話を書きました。その後、バックアップの検証をしていると、 squeezeのXenカーネルではLVM snapshotが不安定という問題を発見してしまいました。 そこで、ついに(ようやく、か)KVMへの移行を行ないました。今回はその記録です。

LVMのsnapshotを取るとカーネル・パニック!

squeezeのXenカーネルでLVM snapshotを何度もcreate && destroyしていると以下のカーネルパニックが発生します。数回すると確実に再現できます。

[ 1500.617898] ------------[ cut here ]------------
[ 1500.617951] kernel BUG at /build/buildd-linux-2.6_2.6.32-30-amd64-d4MbNM/linux-2.6-2.6.32/debian/build/source_amd64_xen/arch/x86/xen/mmu.c:1649!
[ 1500.618021] invalid opcode: 0000 [#1] SMP
[ 1500.618144] last sysfs file: /sys/devices/virtual/bdi/253:4/uevent
[ 1500.618193] CPU 1
[ 1500.618267] Modules linked in: ext4 jbd2 crc16 reiserfs nf_conntrack_ipv4 nf_defrag_ipv4 xt_state nf_conntrack xt_physdev iptable_filter ip_tables x_tables bridge stp xen_evtchn xenfs ib_iser rdma_cm ib_cm iw_cm ib_sa ib_mad ib_core ib_addr dm_snapshot loop snd_hda_codec_realtek snd_hda_intel snd_hda_codec snd_hwdep snd_pcm snd_timer pl2303 snd i2c_nforce2 soundcore edac_core pcspkr usbserial k8temp snd_page_alloc edac_mce_amd i2c_core evdev parport_pc parport processor acpi_processor button ext3 jbd mbcache dm_mod raid1 raid0 md_mod crc32c iscsi_tcp libiscsi_tcp libiscsi scsi_transport_iscsi sd_mod crc_t10dif ata_generic usb_storage thermal sata_nv ohci_hcd floppy thermal_sys e1000e pata_amd forcedeth libata ehci_hcd scsi_mod usbcore nls_base [last unloaded: scsi_wait_scan]
[ 1500.620879] Pid: 11739, comm: dmsetup_env Tainted: G        W  2.6.32-5-xen-amd64 #1
[ 1500.620939] RIP: e030:[<ffffffff8100c694>]  [<ffffffff8100c694>] pin_pagetable_pfn+0x2d/0x36
[ 1500.621012] RSP: e02b:ffff8800b4cfbe08  EFLAGS: 00010282
[ 1500.621012] RAX: 00000000ffffffea RBX: 00000000000b2b13 RCX: 0000000000000001
[ 1500.621012] RDX: 0000000000000000 RSI: 0000000000000001 RDI: ffff8800b4cfbe08
[ 1500.621012] RBP: ffff880002180380 R08: 0000000000000898 R09: ffffea0002716c28
[ 1500.621012] R10: 0000000000007ff0 R11: ffff880000000e98 R12: ffff8800b5a3e518
[ 1500.621012] R13: ffff8800b5d58958 R14: ffff8800025b3170 R15: ffff8800b5a3e518
[ 1500.621012] FS:  00007f3994bd3700(0000) GS:ffff880003b1f000(0000) knlGS:0000000000000000
[ 1500.621012] CS:  e033 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 1500.621012] CR2: 00007f39946fd876 CR3: 00000000158ab000 CR4: 0000000000000660
[ 1500.621012] DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000
[ 1500.621012] DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400
[ 1500.621012] Process dmsetup_env (pid: 11739, threadinfo ffff8800b4cfa000, task ffff8800025b3170)
[ 1500.621012] Stack:
[ 1500.621012]  0000000000000000 0000000000042336 ffffea0002716c28 00000000000b2b13
[ 1500.621012] <0> ffff880002180380 ffffffff810cd4e2 ffff8800b3103730 00007f39946fd876
[ 1500.621012] <0> 00000000b3103000 ffffffff810cb394 ffff8800b5d58958 00007f39946fd876
[ 1500.622220] Call Trace:
[ 1500.622331]  [<ffffffff810cd4e2>] ? __pte_alloc+0x6b/0xc6
[ 1500.622331]  [<ffffffff810cb394>] ? pmd_alloc+0x28/0x5b
[ 1500.622331]  [<ffffffff810cd60b>] ? handle_mm_fault+0xce/0x80f
[ 1500.622331]  [<ffffffff8130ceb5>] ? page_fault+0x25/0x30
[ 1500.622331]  [<ffffffff8130d0ea>] ? error_exit+0x2a/0x60
[ 1500.622331]  [<ffffffff8101251d>] ? retint_restore_args+0x5/0x6
[ 1500.622331]  [<ffffffff8130f016>] ? do_page_fault+0x2e0/0x2fc
[ 1500.622331]  [<ffffffff8130ceb5>] ? page_fault+0x25/0x30
[ 1500.622331] Code: ec 28 89 3c 24 48 89 f7 e8 a2 fd ff ff 48 89 e7 48 89 44 24 08 be 01 00 00 00 31 d2 41 ba f0 7f 00 00 e8 b0 cc ff ff 85 c0 74 04 <0f> 0b eb fe 48 83 c4 28 c3 55 49 89 ca 48 89 d5 40 88 f1 48 89
[ 1500.622331] RIP  [<ffffffff8100c694>] pin_pagetable_pfn+0x2d/0x36
[ 1500.622331]  RSP <ffff8800b4cfbe08>
[ 1500.622331] ---[ end trace a7919e7f17c0a727 ]---

domUのバックアップはlvm snapshotに頼っていたためこれは無視できません。DebianのBTSにも同種の報告がありました。

カーネルに手を入れなければならないXen/dom0ならではの不具合です(最新ではmain lineにdom0がマージされていますが…)。 どのみち、XenのアプローチはKVMがメインになればなるほど不利になるのでこの機会に移行することにしました。

Xenともうひとつ、reiserfsも移行対象の1つでした。reiserfs + LVMの数年前まで鉄板でしたが、現在はext4がほぼ問題ない状況 なため全ファイルシステムをext4へ移行しました。

Xenで使っていたディスクはそのままKVMでは使えません。手で移行してやる必要があります。これは以前書いたのでそちらを参照してください。

移行の初期段階ではXenのディスク + KVM用の起動ディスク構成でした。 最終的にはホストマシンのディスクをすべて交換する必要があったため、一旦FreeBSD上のistgt (on zfs)上へすべて移行しました。 今回のメインのお話です。

まずはDebian + libvirt

まずはKVM環境を揃えます。 Debian Wikiの Kernel Based Virtual Machine (KVM) を参考にパッケージをインストールします。

# apt-get install qemu-kvm libvirt-bin virtinst

これでKVM + libvirt (virsh) と virt-install を使えるようになります。Xenカーネルの場合は手動で通常カーネルへ切り替える必要があります。 /etc/default/grubGRUB_DEFAULT 変数を再設定してください。

私の場合はこの環境は前回のiSCSI rootのままにしています。

あと、ネットワーク構成に応じてブリッジインターフェースを作成する必要があります。XenではXen側がこのあたり面倒を見てくれていました。 私はeth0の設定をそのままbr0として再設定しました。

virshでiSCSI poolを作成

virshでiSCSIなstorage poolを作ります。XMLで流し込む方法が主流ですが、コマンドでも可能です。今回はコマンドから作成します。 ドキュメントによっては引数の順番がおかしい場合があります(RHEL6のドキュメントとか…)。注意してください。コマンド例:

virsh# pool-define-as aoi-iscsi iscsi X.X.X.X - iqn.2010-12.org.example:libvirt - /dev/disk/by-path
第1引数はpool名、第2引数はstorage種別、第3引数はiscsi targetのIPアドレス、第4引数は未使用、第5引数はiqn名、第6引数は未使用、第7引数はホスト側のmount point

このコマンドを実行すると裏でiscsiadmが動き、/dev/disk/by-path以下にiSCSIデバイスが見えるようになります。 iSCSI target側でLUNを設定している場合はlibvirt側ではvolumeとして認識されています。

virsh# vol-list aoi-iscsi
Name                 Path
-----------------------------------------
8.0.0.0              /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-0
8.0.0.1              /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-1
8.0.0.2              /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-2
8.0.0.3              /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-3
8.0.0.4              /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-4

この出力からわかるように、libvirtのiSCSIなストレージプールは単にiscsiadmのラッパとして見えます(virsh的な名前と対応するデバイス名を持っているだけ)。 このままでは再起動時にpoolが自動で構成されません。pool-autstartコマンドで自動起動するようにしておきます。

virsh# pool-autostart aoi-iscsi
virsh# pool-list
Name                 State      Autostart
-----------------------------------------
aoi-iscsi            active     yes

Xenのディスクからコピー

こまで来れば/dev/disk/by-path以下に通常のブロックデバイスとしてiSCSIが見えています。 fdiskcfdisk でパーティションを切ります。

# cfdisk /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-0

切り終えたらホスト側でXenのものと今作成したパーティションをフォーマット、mountして rsync などを使ってファイルをコピーします。 iSCSI側のパーティションは /dev/disk/by-path/ip-X.X.X.X:3260-iscsi-iqn.2010-12.org.example:libvirt-lun-0-partX として見えます。

VMの作成

VMの作成は virt-install コマンドが便利です。複数台の場合は最初の1台をこのコマンドで作り、あとはXMLをコピーして修正するほうが早いと思います。 virt-install の使い方は 10分で始めるKVM が参考になります(virsh, libvirt使い必読)。iSCSIなストレージを使うポイントは --disk への引数です。

Provisioning KVM virtual machines on iSCSI the hard way (Part 2 of 2) が参考になります。つまり、 --disk vol=pool-name/vol-name と指定します。 今回の例だと --disk vol=aoi-iscsi/8.0.0.0 のようになるでしょう。

iSCSI側へ予めコピーが完了したとします。 virt-install コマンドでVMを作成し、grubインストール用に SystemRescueCd で起動します。

$ virt-install --name base-gentoo --connect qemu:///system --ram=512 --vcpus=2 --os-variant=virtio26 --hvm --virt-type=kvm --vnc \
  --cdrom /home/nabeken/tmp/systemrescuecd-x86-2.0.1.iso --network bridge=br0 --arch=x86_64 --disk vol=aoi-iscsi/8.0.0.5

VNC経由で接続すると SystemRescueCd の画面が見えるはずです。 /dev/vda として先程XenのディスクからコピーしたiSCSI領域が見えているはずです。

通常の grub では /dev/vda を認識できないのでデバイスの対応を /boot/grub/device.map へ記述します。 今回は vda1/bootvda2/ になります。

# cat /boot/grub/device.map
(fd0)     /dev/fd0
(hd0)     /dev/vda

grub をMBRへインストールします。

# grub --device-map=/boot/grub/device.map
grub# root (hd0,0)
grub# setup (hd0)

インストールできたら menu.lst を編集します。

# mount /dev/vda1 /mnt/gentoo
# vi /mnt/gentoo/grub/menu.lst

root= を適切なルートパーティションに設定します。最後に fstab を修正します。

# umount /mnt/gentoo
# mount /dev/vda2 /mnt/gentoo
# vi /mnt/gentoo/etc/fstab
# umount /mnt/gentoo

(他にもinittabを編集している場合も修正が必要です。hvc0をtty1へ修正します。)

SystemRescueCd での作業は以上です。シャットダウンします。virshで今回インストールしたVMが見えていることを確認します。

virsh# list --all

起動します。

virsh# start XXX
virsh# vncdisplay XXX

出てきたディスプレイ番号 + 5900 番ポートでVNCにアクセスできます。GRUBが立ち上がって起動することを確認してください。忘れないうちにautostartも仕込みます。

virsh# autostart XXX

お疲れ様でした。

LUNを増やしたら

iSCSI target側でLUNを追加してrestartしただけではiscsi initiatorには反映されません。libvirt側でrefreshが必要です。

virsh# pool-refresh aoi-iscsi

その後、 vol-list コマンドを実行すると新しいLUNが追加されているのが確認できます。

最後に

libvirt + virshのおかげで kvm を直に触る必要がなくなり大変管理が楽になっています。virshはssh経由でも操作できます。

$ virsh -c qemu+ssh://hoge.example.com/sysytem

現在5台のVMがiSCSi上で動いています。やはり標準カーネルで動くのは安心できます。

更新履歴

  • 初稿 (Sun, 20 Mar 2011 19:56:08 +0900)