FreeBSD : cloner un serveur en live grâce à ZFS

Cet article vise à présenter un des grand intérêts de l’utilisation de ZFS : permettre le clonage d’un serveur complet, live, à distance et de façon transparente. Le serveur cloné utilise donc un pool ZFS racine (bootable) qui sera répliqué sur un second serveur.
Le clonage proprement dit s’effectue par la création d’un snapshot ZFS, un instantané non modifiable d’un système de fichiers. La création d’un snapshot est instantanée et n’entraîne aucune charge. On parle de mécanisme copy-on-write : c’est au moment de la modification des données que la copie des fichiers est effectuée pour conserver la différence entre l’état actuel et celui de l’instantané. Il est donc important de supprimer au plus tôt un snapshot lorsqu’il n’est plus nécessaire.
Le snapshot généré est ensuite copié par le réseau - de préférence par SSH - sur le serveur cible. Ce dernier doit posséder un pool ZFS avec suffisament d’espace disque pour pouvoir y copier les données. Deux conséquences :
- la configuration du pool sur le serveur cible peut être différente : le nombre de disques durs, le type de RAID, les propriétés du pool, etc…
- l’espace disque total du pool peut être différent, au sens supérieur mais aussi inférieur, à celui du pool source, vu que c’est l’espace utilisé des données qui est pris en compte.
Bref, avec ZFS, plus aucun autre logiciel ne vous sera nécessaire pour faire vos backups systèmes.
Voici donc la procédure pour cloner un système live en ZFS.
Initalisation du serveur cible
Le démarrage du serveur cible s’effectue sur une image mfsBSD (image live minimale d’un système FreeBSD avec support ZFS). Vous pouvez également utiliser un DVD de FreeBSD en mode fixit.
On configure le réseau :
target# ifconfig em0 inet 192.168.0.101 netmask 255.255.255.0
On partitionne les disques internes (ici je fais un miroir / RAID1) :
target# gpart -s gpt ada0
target# gpart create -s gpt ada0
target# gpart -add -b 34 -s 94 -t freebsd-boot ada0
target# gpart add -b 34 -s 94 -t freebsd-boot ada0
target# gpart add -t freebsd-zfs -l disk0 ada0
target# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0
target# gpart create -s gpt ada1
target# gpart -b 34 -s 94 -t freebsd-boot ada1
target# gpart create -b 34 -s 94 -t freebsd-boot ada1
target# gpart add -b 34 -s 94 -t freebsd-boot ada1
target# gpart add -t freebsd-zfs -l disk1 ada1
target# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
Et on crée le pool ZFS en veillant à bien spécifier un répertoire de montage alternatif, tout en la marquant comme bootable :
target# zpool create -o altroot=mnt -o cachefile=/var/tmp/zpool.cache zroot mirror /dev/gpt/disk0 /dev/gpt/disk1
target# zpool set bootfs=zroot zroot
target# zpool list
NAME SIZE ALLOC FREE CAP DEDUP HEALTH ALTROOT
zroot 7.81G 120K 7.81G 0% 1.00x ONLINE /mnt
target# zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 102K 7.69G 31K /mnt
Lancement du clonage
Sur le serveur à cloner, un snapshot ZFS complet est créé par emploi du mode récursif :
server# zfs snapshot -r zroot@clone
Le snapshot complet provoque la création d’un snapshot de tous les filesystems ZFS :
server# zfs list -t snapshot
NAME USED AVAIL REFER MOUNTPOINT
zroot@clone 0 - 344M -
zroot/tmp@clone 0 - 35K -
zroot/usr@clone 0 - 308M -
zroot/usr/home@clone 0 - 31K -
zroot/usr/ports@clone 0 - 33K -
zroot/usr/ports/distfiles@clone 0 - 31K -
zroot/usr/ports/packages@clone 0 - 31K -
zroot/usr/src@clone 0 - 31K -
zroot/var@clone 0 - 154K -
zroot/var/crash@clone 0 - 31.5K -
zroot/var/db@clone 29K - 96.5K -
zroot/var/db/pkg@clone 0 - 31K -
zroot/var/empty@clone 0 - 31K -
zroot/var/log@clone 21K - 48K -
zroot/var/mail@clone 0 - 31K -
zroot/var/run@clone 20.5K - 43.5K -
zroot/var/tmp@clone 0 - 32K -
On lance une copie à destination du serveur cible :
server# zfs send -R zroot@clone | ssh root@target zfs recv -Fdv zroot
receiving full stream of zroot@clone into zroot@clone
Une fois la copie terminée, le snapshot peut être détruit sur les 2 serveurs :
server# zfs destroy -R zroot@clone
target# zfs detroy -R zroot@clone
Vérification faite le pool est bien identique au serveur cloné :
target# zfs list
NAME USED AVAIL REFER MOUNTPOINT
zroot 653M 7.05G 344M /
zroot/tmp 35K 7.05G 35K /tmp
zroot/usr 308M 7.05G 308M /usr
zroot/usr/home 31K 7.05G 31K /usr/home
zroot/usr/ports 95K 7.05G 33K /usr/ports
zroot/usr/ports/distfiles 31K 7.05G 31K /usr/ports/distfiles
zroot/usr/ports/packages 31K 7.05G 31K /usr/ports/packages
zroot/usr/src 31K 7.05G 31K /usr/src
zroot/var 568K 7.05G 154K /var
zroot/var/crash 31.5K 7.05G 31.5K /var/crash
zroot/var/db 156K 7.05G 96.5K /var/db
zroot/var/db/pkg 31K 7.05G 31K /var/db/pkg
zroot/var/empty 31K 7.05G 31K /var/empty
zroot/var/log 69K 7.05G 48K /var/log
zroot/var/mail 31K 7.05G 31K /var/mail
zroot/var/run 64K 7.05G 43.5K /var/run
zroot/var/tmp 32K 7.05G 32K /var/tmp
Finalisation de la configuration
Sur le serveur distant, il reste à créer le volume pour la swap (il n’y a pas de partition dédiée à la swap), stocker le cache du pool ZFS (il faut écraser celui qui a été copié vu qu’il est différent) et enfin modifier la configuration réseau pour éviter le pépin :
target# zfs create -V 256m zroot/swap
target# zfs export zroot
target# zfs import zroot -o altroot=/mnt -o cachefile=/var/tmp/zpool.cache zroot
target# cp /var/tmp/zpool.cache /mnt/boot/zfs/zpool.cache
target# ee /mnt/etc/rc.conf
On peut ensuite rebooter le serveur sur une copie système parfaite du serveur source.