QEMU/KVM の仮想環境(ゲスト)を止めずに別のホストに移す。
構成は以下ような感じ。
- ホスト環境 host1(192.168.1.11) で動作しているゲスト環境 guest(192.168.1.50)を別のホスト環境 host2(192.168.1.12) に live migration する。
- ホストOS は debian lenny
- ゲストOS も debian lenny
- ゲストOS は PXE boot して、ルートファイルシステムはkujira(192.168.1.10)のiSCSIターゲットをマウントする。
- qemu-kvm のバージョンは 0.12.3
- host1 のCPUは Intel Core2 Duo で host2 は AMD Opteron。
この際、別ホストから guest へのTCPコネクションがどうなるか。
と、guest 内で開きっぱなしのファイルがどうなるかを検証する。
rootfsの作成
iscsiターゲットのrootfsを作る。
debootstrapでお手軽サクサク。
パーティション切るとloopbackマウントがめんどいので切らない。
kujira:~# dd if=/dev/zero of=disk1.img seek=10G bs=1 count=0
kujira:~# mkfs.ext3 disk1.img
kujira:~# mkdir mnt
kujira:~# mount -t ext3 -o loop disk1.img mnt/
kujira:~# debootstrap lenny mnt/
kujira:~# echo guest > mnt/etc/hostname
kujira:~# umount mnt/
/etc/ietd.conf にこんな風に書く。
Target iqn.1999-05.net.hamano:dick1
Lun 0 Path=/path/to/disk1.img,Type=fileio
initramfsの作成
iSCSIイニシエータとして機能する initramfsを作る。
% mkidr initrd
% cd initrd
% zcat /boot/initrd.img-2.6.26-2-686 | cpio -iv
init スクリプトの root file system をマウントする直前に以下の5行を追加。
ipconfig -t 60 ${DEVICE}
modprobe iscsi_tcp
iscsid -f &
iscsiadm -m discovery -t sendtargets -p 192.168.1.10
iscsiadm -m node -T iqn.1999-05.net.hamano:dick1 -l
iSCSIターゲットをマウントするのに必要なファイルを配置、あと kernel module の libcrc32c.ko と crc32c.ko が必要。
% cp /usr/sbin/iscsid ./sbin/
% cp /usr/bin/iscsiadm ./bin/
% mkdir etc/iscsi/
% echo "InitiatorName=iqn.1999-05.net.hamano:hoge" > etc/iscsi/initiatorname.iscsi
% cp /lib/modules/2.6.26-2-686/kernel/lib/libcrc32c.ko lib/modules/2.6.26-2-686/kernel/lib
% mkdir lib/modules/2.6.26-2-686/kernel/crypto/
% cp /lib/modules/2.6.26-2-686/kernel/crypto/crc32c.ko lib/modules/2.6.26-2-686/kernel/crypto/
あと iscsid の中で getpwuid(3)呼んでいてユーザー名が root じゃなかったら蹴られてしまうので nss関連も適当に入れておく。
% cp /lib/libnsl.so.1 ./lib/
% cp /lib/libnss_files.so.2 ./lib/
% echo "root:x:0:0:root:/:/bin/sh" > etc/passwd
% echo "passwd: files" > etc/nsswitch.conf
この initrd に chroot して
# id
uid=0(root) gid=0
って帰ってくればひとまずOK
initramfsを固めて、tftpd サーバーに配置する。
% find ./ | cpio -o -H newc | gzip -9 > ../initrd.img-2.6.26-2-686
PXE boot の設定
pxelinux.cfg/default にこんな風に書く。パラメータに noresume を付けないと起動途中で止まってしまったので付けた。
default guest
label guest
kernel vmlinuz-2.6.26-2-686
append load initrd=initrd.img-2.6.26-2-686 root=/dev/sda noresume
qemu-kvmのネットワーク設定
host2, host1の両方のホストでtap50をブリッジする。 この辺りいつもは qemu-ifup scriptで自動化しているけど今回は手動で。
host2:~# tunctl -u hamano -t tap50
host2:~# brctl addif br0 tap50
host2:~# ip link set tap50 up
host2:~# brctl show br0
bridge name bridge id STP enabled interfaces
br0 8000.001e0bbc9da5 no eth0
tap50
qemu-kvmの実行
host2 側で待機する。
host2:~# qemu -enable-kvm -m 512 \
-net nic,macaddr=00:16:3E:00:FF:32,model=virtio \
-net tap,vlan=0,ifname=tap50,script=no,downscript=no \
-incoming tcp:0:4444
host1 側でゲストを起動する。
host1:~# qemu -enable-kvm -m 512 \
-net nic,macaddr=00:16:3E:00:FF:32,model=virtio \
-net tap,vlan=0,ifname=tap50,script=no,downscript=no -boot n
guest側でファイルをオープンしっぱなしにして、別のサーバーから guest にTCPコネクションを張っておく。
準備が整ったのでいざ Live Migration!
host1 のモニターコンソールから
(qemu) migrate -d tcp:host2:4444
live migration の進捗はこれで確認できる。
(qemu) info migrate
Migration status: active
transferred ram: 8000 kbytes
remaining ram: 533648 kbytes
total ram: 541056 kbytes
(qemu) info migrate
Migration status: completed
migrationはだいたい5秒くらいで完了した。
結果
TCPコネクションは切れていない、オープン中のファイルも問題なく読み書き出来た。
理論上出来ると解っていても実際に動かしてみるとなかなか感動。
補足事項
qemu-kvm 0.11.1 では nic の virtio を有効にして PXE boot 出来ない。
最初、host1 の kernel を 2.6.32.9、host2 の kernel を 2.6.26.8 で試すと以下のエラーメッセージが出て失敗した。
Unknown savevm section or instance ‘kvmclock’ 0 load of migration failed
kernel 2.6.31.5 < -> kernel 2.6.26.8 で試すと成功した。kvmのバージョンは出来るだけ揃えた方が無難。