Evolution infrastructure serveur perso – KVM/Libvirt/DRBD
On parle souvent du cordonnier mal chaussé. J’ai décidé de faire mentir le proverbe 😀
Depuis ma première infra. perso décrite sur http://sdubois.evolix.net/blog/2011/08/08/gerer-sa-propre-infra-perso-sans-trop-de-frais/, j’avais déjà fait des évolutions.
En juin 2013, passage sur une offre serveur spéciale avec RAID hard (HP DL120G7 Corei3 2100 2C/4T 4Go ram ECC + 2x1To + Raid hard + KVMIP) et utilisation de la virtualisation avec par simplicité (apparente) Proxmox (avec KVM)
En novembre 2014, ajout d’un second serveur dédié externe pour service de backup et VM dédiée pour agenda perso (et d’autres tests) et bascule vers KVM+libvirt *sans* Proxmox (sans trop de problématique en conservant mes machines .qcow2 créé avec Proxmox)
Il était temps en 2016 de mettre à l’oeuvre un Cloud privé (cf http://sdubois.evolix.net/blog/2015/11/13/hebergement-nouvelle-offre-de-cloud-prive-par-evolix/)
Voici comment j’ai procédé :
Cible serveur : Deux serveurs low cost XC2016 [Intel® C2750 (Avoton) 8 C / 8T @2,4 Ghz // 16 Go DDR3 // 1 To SATA]
Voici les grosses étapes et astuces utilisées / bug rencontrés :
Install des hyperviseurs en Debian 8 (mode Online) en mode cloud privé LVM+DRBD
Je ne vais pas détailler ces étapes mais à noter du fait d’une limitation de l’interface de partitionnement Online, la contrainte de partir sur 4 partitions primaires et retoucher les choses ensuite
##config partition
/boot 1024
/ 19000
swap 1024
/srv le reste !
Les indispensables :
apt update; apt upgrade; apt install vim lvm2 qemu kvm uml-utilities bridge-utils libvirt-bin screen virt-manager netcat-openbsd linux-headers-amd64 drbd-utils ocfs2-tools
modprobe drbd
Puis :
umount /srv
Création volume LVM dans l’espace laissé par /srv demonté
/srv correspond à /dev/sda4 dans mon cas
On créé le Volume groupe (VG) qui ensuite accueillera des Logical Volume (LV) (cf http://trac.evolix.net/infogerance/wiki/HowtoLVM)
root@hyperviseur1:~# pvcreate /dev/sda4
Physical volume "/dev/sda4" successfully created
root@hyperviseur1:~# vgcreate vg0 /dev/sda4
/proc/devices: No entry for device-mapper found
Volume group "vg0" successfully created
Idem sur hyperviseur2
puis création d’un premier volume (LV) pour mon serveur d’agenda (serveur1)
lvcreate -n serveur1 -L 20g vg0
On doit créer le même volume (LV) sur l’autre hyperviseur et pour faire cela on prend la taille précise grâce à :
root@hyperviseur1:~# lvdisplay --units B /dev/mapper/vg0-serveur1
--- Logical volume ---
LV Path /dev/vg0/serveur1
LV Name serveur1
VG Name vg0
LV UUID hGuVnd-FmnX-Rjjc-puaE-DSgn-f2T3-Ha1ECW
LV Write Access read/write
LV Creation host, time hyperviseur1, 2016-04-20 16:30:16 +0200
LV Status available
# open 0
LV Size 21474836480 B
Current LE 2560
Segments 1
Allocation inherit
Read ahead sectors auto
- currently set to 256
Block device 254:0
Ce qui permet sur le second hyperviseur :
root@hyperviseur2:~# lvcreate -L 21474836480B -n serveur1 vg0
Logical volume “serveur1” created
On a ainsi des périphériques de stockage utilisables (accessibles via /dev/mapper/vg-lv ou /dev/vg/lv) que l’on peut formater
On voit bien l’arborescence :
root@hyperviseur1:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 931.5G 0 disk
├─sda1 8:1 0 190M 0 part /boot
├─sda2 8:2 0 17.7G 0 part /
├─sda3 8:3 0 977M 0 part [SWAP]
└─sda4 8:4 0 912.7G 0 part
└─vg0-serveur1 254:0 0 10G 0 lvm
Configuration réseau Hyperviseurs
Une des forces des serveurs lowcost XC2016 est d’avoir un RPN gigabit avec IP dédiée qui va permettre de relier les 2 serveurs (pour la synchro DRBD) via un lien “dédié” et performant.
La configuration du reseau privé est décrit dans : https://documentation.online.net/fr/serveur-dedie/tutoriel/rpn-by-online.net
RPN -> Groupe RPN -> créer un groupe
Côté hyperviseur*, il faut ajouter cette seconde interface dans /etc/network/interfaces
#seconde interface RPN
auto eth1
iface eth1 inet dhcp
puis
ifup eth1
et verif MTU
Création de la définition de la VM
Ref. pour mise en place Drbd
https://www.drbd.org/en/doc/users-guide-83/ch-lvm
https://www.drbd.org/en/doc/users-guide-84/s-lvm-lv-as-drbd-backing-dev
Conf. DRBD
Voici mon exemple de conf DRBD simple mono-volume :
root@hyperviseur1:~# vim /etc/drbd.d/serveur1.res
resource serveur1 {
net {
cram-hmac-alg "sha1";
shared-secret "*************";
# Si pas de lien dédié 10G, passer en protocol A
# Et desactiver allow-two-primaries;
protocol A;
#allow-two-primaries;
# Tuning perf.
max-buffers 8000;
max-epoch-size 8000;
sndbuf-size 0;
}
# A utiliser si RAID HW avec cache + batterie
#disk {
# disk-barrier no;
# disk-flushes no;
#}
volume 0 {
device minor 0;
disk /dev/vg0/serveur1;
meta-disk internal;
}
on hyperviseur1 {
address $IP_reseauRPN_hyperviseur1:7788;
}
on hyperviseur2 {
address $IP_reseauRPN_hyperviseur2:7788;
}
}
Je ne détaille pas les différentes options (cf http://trac.evolix.net/infogerance/wiki/HowtoDRBD), mais bien penser dans le /etc/hosts à avoir une correspondance pour hyperviseur1 et hyperviseur2
Création volume DRBD
root@hyperviseur1:~# drbdadm create-md serveur1
md_offset 10737414144
al_offset 10737381376
bm_offset 10737053696
Found some data
==> This might destroy existing data! < ==
Do you want to proceed?
[need to type ‘yes’ to confirm] yes
initializing activity log
NOT initializing bitmap
Writing meta data…
New drbd meta data block successfully created.
Idem sur hyperviseur2 !
/etc/init.d/drbd start
sur les 2 hyperviseurs
root@hyperviseur1:~# drbdadm attach serveur1
Device '0' is configured!
Command 'drbdmeta 0 v08 /dev/vg0/serveur1 internal apply-al' terminated with exit code 20
Idem sur hyperviseur2 !
Initialisation volume DRBD
Sur l’un des 2 hyperviseur, initialiser le volume DRBD.
drbdadm -- --overwrite-data-of-peer primary serveur1
On voit l’avancée dans
root@hyperviseur1:~# cat /proc/drbd
On a maintenant notre volume DRBD utilisable pour installer notre VM !
Remarque : pour supprimer un volume DRBD
drbdadm down XX
drbdadm disconnect XX
lvremove -v /dev/vg0/XX
Utilisation du volume DRBD pour y mettre une VM
Dans mon cas un peu tordu, je veux mettre (sans réinstaller/prendre de temps) une VM existante qui a été créé via Proxmox/KVM en .qcow2 … et tout ça sans gaspiller d’espace car je n’ai donc dans cette nouvelle infra que 1To de stockage !
Exemple :
root@hyperviseur1:/var/lib/libvirt/images# qemu-img info vm-101-disk-1.qcow2
image: vm-101-disk-1.qcow2
file format: qcow2
virtual size: 150G (161061273600 bytes)
disk size: 7.4G
cluster_size: 65536
Format specific information:
compat: 0.10
Si on transformait en raw, pas possible de faire rentrer dans les 20Go ces 150Go ! (plus de format à trou sur lvm+drbd)
Astuce : Monter avec qemu-nbd l’image qcow2 et faire un copie par block (commande dd) qui ne se terminera pas
J’ai testé le resize de la partition LVM dans la VM pour mettre toutes les chances de mon coté pour faire tenir dans mon volume DRBD 20Go (intéressant pour les étapes, pas vital a priori) :
Resize partitions LVM dans la VM
Il faut se logguer dans la VM
root@vm_amigrer_sur_ancienhyperviseur:~# dmsetup ls
serveur1-home (253:5)
serveur1-root (253:0)
serveur1-swap_1 (253:1)
serveur1-tmp (253:4)
serveur1-usr (253:2)
serveur1-var (253:3)
En root au sein de la machine virtuelle à migrer (sur l’ancien hyperviseur) (sans se logguer en user)
umount /home
Verif pas d’erreur
e2fsck -f /dev/mapper/serveur1-home
Redimensionnement
resize2fs /dev/mapper/serveur1-home 5000M
Réduction du LV :
lvresize -L -130G /dev/mapper/serveur1-home
Reduction partition active
resize2fs /dev/mapper/serveur1-home
Remonte /home
mount /home
On a :
image: vm-101-disk-1.qcow2
file format: qcow2
virtual size: 150G (161061273600 bytes)
disk size: 8.0G
cluster_size: 65536
donc
Lancement de gparted
Resize partition lvm
puis Resize partition etendue
120Go en free space
!!ATTENTION le dd doit etre fait sur le volume DRBD et pas le volume LVM!!
On monte le qcow2 optimisé
modprobe nbd max_part=16
qemu-nbd -c /dev/nbd0 /var/lib/libvirt/images/vm-101-disk-1.qcow2
On copie ensuite
root@hyperviseur1# dd if=/dev/nbd0 of=/dev/drbd0 bs=64k
dd: error writing ‘/dev/drbd0’: No space left on device
mais pas grave vu que c’était du free space
et quand dd se termine, on demonte l’image
qemu-nbd -d /dev/nbd0
rmmod nbd
Forcer le resync du secondary (suite au dd)
drbdadm secondary serveur1
drbdadm invalidate serveur1
drbdadm disconnect serveur1
drbdadm connect serveur1
Et enfin magie : La VM démarre 🙂
Migration machine principale
Vu la taille de ma machine principale (900Go) et les services critiques en place dessus, une migration comme plus haut n’est pas tentable.
Par ailleurs l’idée est de repartir sur un partitionnement propre sans cumuler deux niveaux de LVM.
J’ai donc préféré le scénario de recréer une VM “propre” sur deux volumes DRBD (un dédié à /home). À l’inverse je ne souhaitais pas repartir dans de la configuration de serveur mail et l’objectif était de transposer à l’identique côté système/data ma VM existante.
Voici les étapes utilisées :
Création du double volume DRBD
vim /etc/drbd.d/serveurprincipal.res
resource serveurprincipal {
net {
cram-hmac-alg "sha1";
shared-secret "*******************";
# Si pas de lien dedié 10G, passer en protocol A
# Et desactiver allow-two-primaries;
protocol A;
#allow-two-primaries;
# Tuning perf.
max-buffers 8000;
max-epoch-size 8000;
sndbuf-size 0;
}
# A utiliser si RAID HW avec cache + batterie
#disk {
# disk-barrier no;
# disk-flushes no;
#}
volume 0 {
device minor 2;
disk /dev/vg0/serveurprincipal;
meta-disk internal;
}
volume 1 {
device minor 3;
disk /dev/vg0/serveurprincipalhome;
meta-disk internal;
}
on hyperviseur1 {
address $IP_reseauRPN_hyperviseur1:7790;
}
on hyperviseur2 {
address $IP_reseauRPN_hyperviseur2:7790;
}
}
rem : attention à bien utiliser des device minor différents et des ports différents (7790, etc)
root@hyperviseur1:~# lvcreate -n serveurprincipal -L 40g vg0
root@hyperviseur1:~# lvdisplay --units B /dev/mapper/vg0-serveurprincipal
root@hyperviseur1:~# lvcreate -n serveurprincipalhome -L 750g vg0
root@hyperviseur1:~# lvdisplay --units B /dev/mapper/vg0-serveurprincipalhome
root@hyperviseur2:~# lvcreate -L 42949672960B -n serveurprincipal vg0
Logical volume “serveurprincipal” created
root@hyperviseur2:~# lvcreate -L 805306368000B -n serveurprincipalhome vg0
Logical volume “serveurprincipalhome” created
root@hyperviseur1:~# drbdadm create-md serveurprincipal
root@hyperviseur2:~# drbdadm create-md serveurprincipal
root@hyperviseur1:~# drbdadm create-md serveurprincipalhome
‘serveurprincipalhome’ not defined in your config (for this host)
Création du second volume
root@hyperviseur1:~# drbdadm create-md serveurprincipal/1
root@hyperviseur2:~# drbdadm create-md serveurprincipal/1
You want me to create a v08 style flexible-size internal meta data block.
There appears to be a v08 flexible-size internal meta data block
already in place on /dev/vg0/serveurprincipalhome at byte offset 805306363904
Do you really want to overwrite the existing meta-data?
[need to type ‘yes’ to confirm] yes
initializing activity log
NOT initializing bitmap
Writing meta data…
New drbd meta data block successfully created.
Puis sur 2 machines
/etc/init.d/drbd reload
et
drbdadm attach serveurprincipal
puis serveurprincipal/1 sur 2 hyperviseurs
drbdadm up serveurprincipal
puis serveurprincipal/1
drbdadm -- --overwrite-data-of-peer primary serveurprincipal
puis serveurprincipal/1 sur hyperviseur primaire
On voit que tout est OK :
root@hyperviseur1:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
sda 8:0 0 931.5G 0 disk
├─sda1 8:1 0 190M 0 part /boot
├─sda2 8:2 0 17.7G 0 part /
├─sda3 8:3 0 977M 0 part [SWAP]
└─sda4 8:4 0 912.7G 0 part
├─vg0-serveur1 254:0 0 20G 0 lvm
├─vg0-serveur2 254:1 0 21G 0 lvm
├─vg0-serveurprincipal 254:2 0 40G 0 lvm
└─vg0-serveurprincipalhome 254:3 0 750G 0 lvm
drbd0 147:0 0 20G 0 disk
drbd1 147:1 0 21G 1 disk
drbd2 147:2 0 40G 1 disk
drbd3 147:3 0 750G 1 disk
On fait l’install de la VM (iso version Debian ;)) sur /dev/drbd2 [avec une autre IP/mac adress]
et dans la définition de la VM on ajoute le disque /dev/drbd3
root@serveurprincipal2:~# lsblk
NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
vda 254:0 0 40G 0 disk
├─vda1 254:1 0 4,7G 0 part /
├─vda2 254:2 0 9,3G 0 part /usr
├─vda3 254:3 0 2,7G 0 part [SWAP]
├─vda4 254:4 0 1K 0 part
├─vda5 254:5 0 9,3G 0 part /var
└─vda6 254:6 0 4,7G 0 part /tmp
vdb 254:16 0 750G 0 disk
sr0 11:0 1 1024M 0 rom
(en ayant ajouté dans /etc/fstab
/dev/vdb /home ext4 defaults 0 2
)
Installation à l’identique
sur serveurprincipal : aptitude -F "%p" search '~i!~M' > /tmp/mes_paquets.txt
sur serveurprincipal2 : aptitude install $(cat mes_paquets.txt)
(après avoir transféré mes_paquets.txt ;))
Première synchro des données
important : On commence par /etc (car par la suite important pour avoir les bons user/group lié au UID de /etc/passwd) et on exclue /etc/fstab et /etc/network/interfaces !
Depuis serveurprincipal :
rsync --progress -avz --numeric-ids --exclude /etc/network/interfaces --exclude /etc/fstab --delete /etc/ root@serveurprincipal2.sdubois.net:/etc/
Puis :
rsync --progress -avz --numeric-ids --delete /usr/ root@serveurprincipal2.sdubois.net:/usr/
et
rsync --progress -avz --numeric-ids --delete /var/ root@serveurprincipal2.sdubois.net:/var/
et bien sûr idem avec le /home (vu le volume … faut être patient et vérifier le bon déroulement)
dans mon cas j’ai aussi du adapter /etc/hosts.allow et qq spécificité (genre cd /;ln -s /home srv
)
Une fois cela fait, on peut forcer les DNS et valider que apache/mysql OK. Plus dur pour les mails :p
Bascule finale
Il faut avoir en tête chez Online que les IP failover son attachée à un mac adress qui n’est pas modifiable mais peut-être regénéré. Une fois bascule l’IP sur le bon hyperviseur avec l’interface web Online, il faut donc jouer le jeu de modifier avec virt-manager ou virsh la mac adress sur l’interface réseau (il faut dans les faits recréer une nouvelle interface et supprimer l’ancienne)
Etapes :
* Coupure service sur serveurprincipal + Suppression crontab
* Dernier rsync (principalement /var/lib/mysql/ et /home)
* Bascule IP
* Retouche /etc/network/interfaces sur serveurprincipal2
* Test
* Redémarrge des services + Réactiviation crontab
* Vérification
Et voilà, tout est en place sur ce Cloud Privé low cost !
root@hyperviseur1:~# cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
srcversion: 1A9F77B1CA5FF92235C2213
0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate A r-----
ns:109797229 nr:0 dw:67855890 dr:42606988 al:4838 bm:2594 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate A r-----
ns:0 nr:30198054 dw:68123174 dr:0 al:0 bm:2693 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
2: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate A r-----
ns:63187560 nr:0 dw:21245836 dr:47163454 al:1489 bm:2560 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
3: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate A r-----
ns:1200886668 nr:0 dw:414478704 dr:831195436 al:36859 bm:47999 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
root@hyperviseur1:~# virsh list
Id Name State
----------------------------------------------------
5 serveur1 running
8 serveurprincipal running
root@hyperviseur2:~# virsh list
Id Name State
----------------------------------------------------
3 serveur2 running
On se fait une migration à Chaud ?
On va le faire avec serveur1 (volume drbd0)
Il est en Primary/Secondary pour l’instant et en Protocol A, il faut être en primary/primary
http://trac.evolix.net/infogerance/wiki/HowtoKVM#Migrerunemachine
On passe en Protocol C (sur les 2 hyperviseurs)
protocol C;
allow-two-primaries;
et on reload drbd (sur les 2 hyperviseurs)
/etc/init.d/drbd reload
root@hyperviseur2:~# drbdadm primary cyther
root@hyperviseur2:~# cat /proc/drbd
version: 8.4.3 (api:1/proto:86-101)
srcversion: 1A9F77B1CA5FF92235C2213
0: cs:Connected ro:Primary/Primary ds:UpToDate/UpToDate C r-----
ns:0 nr:42661565 dw:88851375 dr:912 al:0 bm:1315 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
1: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate A r-----
ns:7363878 nr:0 dw:29155134 dr:22400973 al:3153 bm:1349 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
2: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate A r-----
ns:0 nr:63278804 dw:63278804 dr:0 al:0 bm:2560 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
3: cs:Connected ro:Secondary/Primary ds:UpToDate/UpToDate A r-----
ns:0 nr:1200891548 dw:1200891548 dr:0 al:0 bm:47999 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0
Voilà on va pouvoir faire la migration à chaud :
virsh migrate --live --unsafe serveur1 qemu+ssh://hyperviseur2/system tcp://$IP_reseauRPN_hyperviseur2
(le second argument le force à passer par le réseau DRBD dédié)
Bug rencontré
error: internal error: Attempt to migrate guest to the same host 12341234-1234-1234-1234-1234123412341234
Lié au fait que même system-uuid !! (dmidecode -s system-uuid
)
Astuce : éditer /etc/libvirt/libvirtd.conf et ajouter un autre uuid
service libvirtd restart
[pour eviter de vraiment changer le system-uuid comme décrit sur https://onapp.zendesk.com/entries/33781277-VS-Hot-Migration-Fail-with-error-error-internal-error-Attempt-to-migrate-guest-to-the-same-host-uuid]
On refait :
virsh migrate --live --unsafe serveur1 qemu+ssh://hyperviseur2/system tcp://$IP_reseauRPN_hyperviseur2
root@hyperviseur1:~# virsh list
Id Name State
----------------------------------------------------
8 serveurprincipal running
root@hyperviseur2:~# virsh list
Id Name State
----------------------------------------------------
3 serveur2 running
5 serveur1 running
Petite bascule IP de l’IP failover et pour être propre un “virsh undefine serveur1” sur hyperviseur1 et “virsh define serveur1” sur hyperviseur2 c’est bon !
😀
Récupérer d’un split-brain
Sur le serveur en Standalone qu’on veut réinitialiser :
# drbdadm secondary r0
# drbdadm invalidate r0
# drbdadm disconnect r0
# drbdadm connect r0
Sur le serveur “master”
# drbdadm connect r0
autre point important, bien copier les définition des VMs d’un hyperviseur (/etc/libvirt/qemu/*.xml) à l’autre pour pouvoir redémarrer une VM en cas de crash de son hyperviseur initial !
pour mettre en place une VM debian 9, la configuration du réseau change un peu avec l’utilisation de la commande ip (et non route)
Configuration réseau du bridge sur l’hyperviseur
auto br0
iface br0 inet static
address IPHOST
netmask 255.255.255.0
network IPHOST.0
broadcast IPHOST.255
gateway IPGATEWAY
bridge_ports eth0
Passage de Debian 8 à 9 en terme de configuration du réseau (sans avoir besoin du paquet debian vlan)
auto eth0
iface eth0 inet static
address IPFAILOVER
netmask 255.255.255.255
broadcast IPFAILOVER
post-up route add IPGATEWAY dev eth0
post-up route add default gw IPGATEWAY
post-down route del IPGATEWAY dev eth0
post-down route del default gw IPGATEWAY
vers
auto ens3
iface ens3 inet static
address IPFAILOVER
netmask 255.255.255.255
broadcast IPFAILOVER
post-up ip route add IPGATEWAY dev ens3
post-up ip route add default via IPGATEWAY
post-down ip route del IPGATEWAY dev ens3
post-down ip route del default via IPGATEWAY