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 :

freebsd9# 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.