Grenode utilise maintenant Ganeti pour gérer certains de ses hyperviseurs, notamment tillac.

Le backend de virtualisation utilisé est KVM, et on ne fait pas de DRDB pour le moment.

Documentation

La documentation officielle est assez complète : http://docs.ganeti.org/ganeti/2.15/html/

Quand on sait quoi chercher, les pages de manuel des différentes commandes (gnt-node, gnt-cluster, gnt-instance) sont la référence.

Installation et configuration de ganeti

Installation

On fait l'installation sous Jessie, mais on utilise la version de ganeti de jessie-backports pour avoir une version un peu récente (2.15 vs. 2.12).

sudo apt-get install --no-install-recommends -t jessie-backports ganeti ganeti-instance-debootstrap
sudo apt-get install --no-install-recommends qemu-kvm

Configuration du cluster

Il faut déjà créer un Volume Group LVM pour stocker les disques des VM.

Ensuite, Ganeti a besoin d'une IP "virtuelle" avec un nom DNS associé. C'est une IP qui va toujours pointer sur le serveur "master" lorsqu'on a plusieurs serveurs dans un cluster. Cette IP va être ajoutée par Ganeti sur l'interface qui sert à communiquer avec les autres serveurs Ganeti.

Chez nous, le nom du cluster est flotte.grenode.net, défini dans /etc/hosts, et l'interface est br-grenode.

Pour initialiser le cluster :

export mon_volumegroup="vms"
export mon_interface="br-grenode"
sudo gnt-cluster init --vg-name $mon_volumegroup --master-netdev $mon_interface --enabled-hypervisors kvm --hypervisor-parameters kvm:kernel_path="" --enabled-disk-templates plain,diskless --node-parameters ssh_port=51083 flotte.grenode.net

Le paramètre kernel_path="" force KVM à booter les VM avec un noyau propre (par défaut, c'est le noyau de l'hyperviseur qui est utilisé…).

Performance

Cf. https://code.google.com/p/ganeti/wiki/PerformanceTuning

Pour utiliser toutes les fonctionnalités du CPU (AES-NI, AVX, etc) dans les VM :

gnt-cluster modify -H kvm:cpu_type=host

Attention, ça peut poser des problèmes lorsqu'on migre des VM sur des machines physiques qui ont des CPU différents. On n'a pas ce problème pour l'instant.

Configuration de debootstrap

Ganeti sait utiliser debootstrap pour installer le système des VM. La configuration générale est dans /etc/default/ganeti-instance-debootstrap.

Pour comprendre comment ça marche, il est indispensable de lire /usr/share/doc/ganeti-instance-debootstrap/README.gz. Notamment, il y a un système de « variantes » assez bien fichu pour avoir plusieurs configurations debootstrap en parallèle, ça se passe dans /etc/ganeti/instance-bootstrap/.

Attention : bien penser à rajouter des paquets utiles à ceux que debootstrap installe ! Par exemple, debootstrap n'installe pas de noyau par défaut… Dans /etc/default/ganeti-instance-debootstrap ou la configuration d'une variante :

EXTRA_PKGS="acpi-support-base,udev,linux-image-amd64,openssh-server"

Après avoir modifié cette variable, il faut supprimer le cache debootstrap (/var/cache/ganeti-instance-debootstrap/*) pour que ce soit pris en compte à la prochaine création de VM.

Création d'une nouvelle VM

Documentation : http://docs.ganeti.org/ganeti/2.15/html/admin.html#instance-management

Avec debootstrap

En supposant qu'une variante "jessie" ait été créée précédemment, la commande gnt-instance add permet de créer une VM, ici avec 10 GB de disque et 500 MB de RAM, et une interface réseau ajoutée à$mon_bridge :

gnt-instance add -o debootstrap+jessie -t plain -s 10G -B memory=500M --net=0:link=$mon_bridge --no-name-check --no-ip-check --no-start $ma_vm

La première fois, ça va prendre quelques minutes (debootstrap). Ensuite, il y a un cache du système de fichiers créé par debootstrap, donc la création prend quelques secondes.

Pour le premier boot uniquement, on utilise une copie du kernel de l'hôte et un initrd "custom" sans cryptroot → cf. doc ARN https://wiki.arn-fai.net/technique:ganeti#creation_de_la_premiere_vm

gnt-instance start -H kernel_path=/tmp/ganeti-install-vmlinuz-$ma_vm,initrd_path=/var/lib/ganeti/custom-initrd $ma_vm

La VM boot, installe grub, et s'éteint. (lire hooks/grub) La VM peut ensuite être démarrée avec son propre kernel.

gnt-instance start $ma_vm

Manuellement (debian-installer)

Une installation manuelle avec le debian-installer peut être utile si on veut chiffrer le disque de sa VM.

gnt-instance add -o noop -t plain -s 10G -B memory=500M --net=0:link=$mon_bridge --no-name-check --no-ip-check --no-start $ma_vm
gnt-instance start -H boot_order=cdrom,cdrom_image_path=$iso_path

Sur tillac, les ISO sont dans /srv/iso.

On se connecte ensuite en VNC via SSH (cf. ci-dessous) pour installer l'OS.

Gestion et accès aux VM

Démarrage et arrêt d'une VM

gnt-instance startup $ma_vm
gnt-instance shutdown $ma_vm
gnt-instance reboot $ma_vm

Note : Ganeti envoie un signal ACPI pour éteindre la VM, donc il faut que ce signal soit pris en compte. Sous Debian, le paquet à installer est acpi-support-base.

Lister les disques des VM

La commande suivante permet de lister les VM avec leur disque :

gnt-node volumes

C'est pratique pour avoir la correspondance volume LVM - machine, parce que les noms des volumes LVM ne sont pas humainement compréhensibles...

Modification ou ajout d'interface réseau à une VM

Ajout d'une interface réseau à une VM, ici connecté au bridge br-foo :

gnt-instance modify --net add:link=br-foo $ma_vm

Changement de bridge pour une interface réseau (ici, changement pour la première interface, numérotée 0, et ajout de cette interface au bridge br-foo) :

gnt-instance modify --net 0:modify,link=br-foo $ma_vm

Suppression d'une interface réseau, ici la deuxième interface de la VM (eth1) :

gnt-instance modify --net 1:remove $ma_vm

Note : il n'est pas possible de supprimer la NIC 0 d'une VM. Du coup, il existe un bridge br-devnull dans lequel on peut mettre la VM, qui n'est relié à rien.

Agrandir le disque d'une VM

Pour ajouter 10 GB de disque à une VM :

gnt-instance grow-disk $ma_vm 0 10g

"0" est l'identifiant du disque. Attention, regarder le numéro adéquat avec par exemple :

gnt-instance list -o name,os,status,oper_ram,disk.count,disk.size/0,disk.size/1

Après un reboot (reboot depuis l'hyperviseur pas depuis l'intérieur de la VM), on peut agrandir le système de fichiers dans la VM :

fsadm resize /dev/vda1

Si il y a une table de partition dans la VM, il faut d'abord agrandir la partition correspondante, par exemple avec cfdisk. Une méthode "barbare" consiste à supprimer la partition et à la recréer avec la nouvelle taille, en s'assurant qu'elle commence bien au même endroit et qu'elle a le même type...

Cas d'un serveur avec LUKS+LVM

Exemple Ilico

Si vous avez suivi l'install par défaut d'une Debian Jessie avec LUKS+LVM, la procédure est un peu différente.

# lsblk -f /dev/vda
NAME                   FSTYPE      LABEL UUID                                   MOUNTPOINT
vda
├─vda1                 ext2              xxxxxxxxxxxxxxxxxxxxxxxx               /boot
├─vda2
└─vda5                 crypto_LUKS       xxxxxxxxxxxxxxxxxxxxxxxx
  └─vda5_crypt         LVM2_member       xxxxxxxxxxxxxxxxxxxxxxxx
    └─tourton--vg-root ext4              xxxxxxxxxxxxxxxxxxxxxxxx               /

Il faut d'abord étendre vda2, puis vda5, puis vda5_crypt puis le fs en ext4.

parted /dev/vda

(parted) resizepart 2
End? [160GB]? <entrez la taille désirée>

On effectue la même opération pour la partition vda5 :

parted /dev/vda

(parted) resizepart 5
End? [160GB]? <entrez la taille désirée>

Il faut maintenant étendre au niveau LUKS avec cryptsetup, puis le PV et enfin le LV :

cryptsetup resize vda5_crypt
pvresize /dev/mapper/vda5_crypt
pvchange -x y /dev/mapper/vda5_crypt
lvresize -l +100%FREE /dev/tourton-vg/root
pvchange -x n /dev/mapper/vda5_crypt

Enfin, on s'occupe du FS :

resize2fs -p /dev/mapper/tourton--vg-root

Et voilà, un redémarrage pour s'assurer que tout est OK et l'affaire est jouée.

Exemple Grésille

Une fois le disque agrandi sur l'hyperviseur, on va :

  1. changer la table de partition dans la VM (avec fdisk /dev/vdb) :
    • supprimer la partition puis
    • créer la partition en utilisant tout l'espace
  2. agrandir le disque chiffré (cryptsetup resize /dev/mapper/xvdb1_crypt)
  3. agrandir le PV (pvresize /dev/mapper/xvdb1_crypt)
  4. agrandir le LV (lvresize -L +35G -r /dev/coccinelle/web)

Réduire un disque

Ganeti ne supporte pas de base la réduction de disque. À Grésille, nous avons cependant eu le cas d'un disque agrandi par erreur, que nous avons réduit ensuite (le filesystem derrière n'ayant pas été agrandi).

On a fait comme ça, des fois que ça puisse (re)servir :

gnt-instance info <la machine>
# noter l'ID du disque dur (sans se tromper cette fois)
# et le chemin (/dev/vms/<ID>.diskX)
service ganeti stop
lvresize -L -<la taille> /dev/vms/<ID>.diskX
# faire une copie de sauvegarde de /var/lib/ganeti/config.data
cp /var/lib/ganeti/config.data  /root/backup-config.data

Ensuite, on édite /var/lib/ganeti/config.data pour modifier la taille du disque (en blocs de 1M). Il faut d'abord chercher l'id du disque, puis la size juste après. Ce qui donne par exemple :

{"logical_id":["vms","7e640c14-a5f6-476d-9cda-b767003cff33.disk0"],"dev_type":"plain","children":[],"nodes":["39395a09-dad8-43c5-aa82-a69da30e0702"],"iv_name":"disk/0","size":52224,"mode":"rw","params":{},"uuid":"4cc375b9-1c56-4240-af00-7514abcfc61a","serial_no":2,"ctime":1.474889243565636e9,"mtime":1.5117963326473444e9}

devient

{"logical_id":["vms","7e640c14-a5f6-476d-9cda-b767003cff33.disk0"],"dev_type":"plain","children":[],"nodes":["39395a09-dad8-43c5-aa82-a69da30e0702"],"iv_name":"disk/0","size":1024,"mode":"rw","params":{},"uuid":"4cc375b9-1c56-4240-af00-7514abcfc61a","serial_no":2,"ctime":1.474889243565636e9,"mtime":1.5117963326473444e9}

On redémarre ganeti :

service ganeti start

Enfin, on reboote la vm (pas un reboot dans la vm, shutdown puis démarrage depuis ganeti), et tout roule.

Accès en VNC

Pour chaque VM, qemu configure un accès VNC sur un port TCP dédié, qui écoute sur localhost. Pour connaître ce port :

gnt-instance list -o +network_port

Il faut donc faire un tunnel SSH vers ce port pour se connecter en VNC :

ssh -v -N -L 4444:127.0.0.1:110XX $hyperviseur

Ensuite, diriger son client VNC vers localhost, port 4444.

Si on n'aime pas VNC, il est possible de désactiver l'accès VNC pour une VM :

gnt-instance modify -H vnc_bind_address="" $ma_vm
gnt-instance reboot $ma_vm

Si jamais on veut le réactiver par la suite :

gnt-instance modify -H vnc_bind_address="127.0.0.1" $ma_vm
gnt-instance reboot $ma_vm

Accès par port série

Il peut aussi être pratique d'avoir accès à une VM via un port série depuis l'hôte.

Pour une VM sous Debian wheezy, il faut installer le paquet console-tools.

Pour une VM utilisant systemd (Debian jessie ou supérieur), la console est gérée par systemd :

systemctl enable serial-getty@ttyS0.service
systemctl start serial-getty@ttyS0.service

Ensuite, pour accéder au port série depuis l'hôte :

gnt-instance console $ma_vm

Si on veut aussi avoir grub sur le port série, il faut changer la configuration de grub dans /etc/default/grub :

GRUB_TERMINAL="console serial"

De même, pour avoir les messages du noyau sur le port série, c'est également dans /etc/default/grub :

GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0"

Ne pas oublier de lancer update-grub dans la VM après avoir modifié ce fichier.

Import d'une VM existante

Le but est de migrer une VM depuis rouf (qui tourne donc avec Xen) vers tillac.

Avant la migration

D'abord, il est nécessaire de créer les bridges sur tillac et s'assurer que les VLAN fonctionnent comme il faut.

Ensuite, installer les paquets suivants dans la VM pour le support console série et ACPI (jessie a déjà le support de la console série de base) :

apt-get install acpi-support-base               # Pour jessie
apt-get install acpi-support-base console-tools # Pour wheezy

Enfin, sur la VM, s'assurer que Grub est bien installé et configuré :

update-grub
grub-install /dev/vda # à adapter

Si grub est mal installé, la VM ne démarrera pas sur le nouvel hyperviseur et prendra 100% de CPU.

Migration

Un script de migration est disponible sur tillac : migrate vm from xen.sh

Ce script copie le disque d'une VM Xen via SSH, et l'utilise pour créer une VM Ganeti. La VM est éteinte le temps de la migration (il faut environ 7 minutes pour copier 10 GB de rouf à tillac).

Améliorations possibles

1) gérer plusieurs disques (nécessaire pour les VM chiffrées avec un /boot séparé)

2) ne pas éteindre la VM pendant la migration (utile pour les VM avec un gros disque). Il est sûrement possible d'utiliser un snapshot LVM et https://github.com/mpalmer/lvmsync pour transférer uniquement ce qui a changé depuis le snapshot.

Usage du script

usage: ./migrate_vm_from_xen.sh [--dry-run] <vm_name> <memory> <nb_CPU> <bridge1> [bridge2 [bridge3 ...]]
Migrate a VM from a Xen host to the local Ganeti host.
The named VM must exist and be running on the old Xen host.
A list of bridges can be passed: for each bridge, one network interface will be created in the VM.

This script does the following:
1/ Create a local LVM volume, with the same size as the old VM
2/ Shutdown the VM on the old (Xen) hypervisor
3/ Copy the VM disk through SSH (which can take time!)
4/ Create a local Ganeti VM with the same name as the old one, and the specified memory & CPU
5/ Start the new VM

To see what would happen without performing the dangerous steps, use --dry-run.

Utilisation de lvmsync

Installation

Il faut installer lvmsync sur le serveur source & destination.

Sur Debian, le plus simple est d'installer la version lvmsync de Memset (pour des questions de dépendances ruby)

git clone https://github.com/Memset/lvmsync lvmsync
cd lvmsync
git checkout debian-package
gem build lvmsync.gemspec
gem install lvmsync-$version-.gem

lvmsync utilise rsync via ssh. Il faut donc aussi s'assurer que le serveur source est capable de se connecter en ssh sur le compte root du serveur de destination.

Procédure

Il faut créer un snapshot lvm sur le serveur source (rouf)

lvcreate -n coccinelle-disk-snapshot -L 20G -s /dev/domU/coccinelle-disk

Sur le serveur destination (tillac), il faut créer le volume logique lvm de destination

lvcreate -n coccinelle-disk -L 250G vms

Pendant que la vm est en cours de fonctionnement on peut donc copier les données du snapshot. Depuis le serveur de destination (tillac) :

ssh root@rouf.grenode.net dd if=/dev/domU/coccinelle-disk-snapshot bs=1M | pv --size 250G | dd of=/dev/vms/coccinelle-disk bs=1M

On peut répéter cela pour chacun des volumes disques de la vm. Une fois tous les volumes copiés, on éteint la vm et on termine la migration des données.

Depuis le serveur source (rouf) :

lvmsync /dev/domU/coccinelle-disk-snapshot  tillac.grenode.net:/dev/vms/coccinelle-disk

Une fois la copie des volumes disques finie, on peut continue sur la création de l'instance ganeti.

Après la migration

  • Il est possible que la console ne fonctionne pas. Vérifier alors dans la configuration de grub qu'il n'y ait pas de console=hvc0 dans les options de linux et penser à configurer la console serie (cf. plus haut).