Déplacer une VM KVM «à la main»

January 18, 2012 by nono
Catégories geekeries - Mots-clés KVM Linux LVM stockage virtualisation

Le contexte

J'ai une petite ferme de serveurs physiques sous Scientific Linux 6 qui hébergent des machines virtuelles KVM gérées par libvirt. J'utilise des volumes logiques LVM comme disques virtuels.

La plupart des VM ne sont pas critiques et supportent d'être arrêtées quelques minutes; par contre il vaut mieux ne pas les arrêter trop longtemps. Tout le problème est donc de recopier au moins le gros des données sans arrêter la VM.

Pour l'exemple, je déplacerai une VM vm1, dont le disque virtuel est sur /dev/vg00/vm1, de la machine physique host1 à sa soeur host2. On supposera pour l'exemple que les deux machines sont identiques; en tout cas il vaut mieux qu'elles disposent de la même version du paquet qemu-kvm. Et quand je dis la même version c'est la même version au patch près, sinon la VM risque de ne pas démarrer sur le nouvel hôte.

L'outil

Je sais faire la même manip avec des isolateurs à la place des VM: un coup de rsync et c'est marre. Ah, si rsync savait se débrouiller à peu près efficacement avec un périphérique bloc... Et ben ça existe, ça s'appelle lvmsync, c'est un script ruby qu'il suffit de poser sur les deux machines hôtes. En dehors de ça, vous aurez besoin de dmsetup (normalement il est installé, il fait partie du paquet device-mapper qui est lui-même une dépendance de libvirt) et root devra pouvoir se connecter en ssh sur host2 depuis host1.

La méthode

On commence par créer le volume logique sur host2:

lvcreate -l640 -nvm1 vg00

À adapter évidemment, il doit être identique à l'original qui se trouve sur host1.

Ensuite, sur host1, on prend un instantané du disque de la VM et on le copie sur host2:

lvcreate -L10G -s -nvm1-snap /dev/vg00/vm1
dd if=/dev/vg00/vm1-snap bs=10M | ssh root@host2 dd of=/dev/vg00/vm1 bs=10M

On peut maintenant éteindre la VM, puis synchroniser le disque. Ensuite on exporte la configuration de la VM.

virsh shutdown vm1
lvmsync /dev/vg00/vm1-snap host2:/dev/vg00/vm1
virsh dumpxml vm1 | ssh root@host2 'cat > /var/tmp/vm1.xml'

Reste plus, sur host2, qu'à importer et démarrer la VM:

virsh define /var/tmp/vm1.xml
virsh start vm1

Une fois que c'est fait, on peut faire le ménage sur host1:

virsh undefine vm1
lvremove /dev/vg00/vm1-snap
lvremove /dev/vg00/vm1

C'est prêt!

Et ça va quand même vachement plus vite comme ça. Maintenant, il va falloir écrire un bout de script pour emballer tout ça, on verra ça un autre jour. :-)