Les environnements d’initialisation – Boot Environment (BE) – est une fonctionnalité backportée de Solaris et liée au portage de ZFS sur FreeBSD. Son intérêt est de créer différentes versions du filesystem racine afin de garantir un démarrage sûr du système suite à une opération de maintenance comme l’installation, la mise à jour ou tout simplement une reconfiguration. Elle s’appuie intégralement sur des snapshots ZFS.

Techniquement, le pool racine ZFS doit respecter une organisation du type : <nom du pool>/ROOT/<nom du BE>. Ainsi pour un pool nommé rpool et le BE default, le fileystem racine est rpool/ROOT/default. La gestion des BE est ensuite effectuée grâce à la commande beadm qui permet de les créer et de sélectionner le BE à utiliser au prochain démarrage.

Cet article vise à présenter l’installation et l’utilisation d’un système supportant les BE.

Installation du système

Toute la procédure s’effectue depuis le CD de FreeBSD en mode live.

# gpart create -s gpt ada0
# gpart add -b 34 -s 94 -t freebsd-boot ada0
# gpart add -s 4G -t freebsd-swap -l swap0 ada0
# gpart add -t freebsd-zfs -l disk0 ada0
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0
# gpart create -s gpt ada1
# gpart add -b 34 -s 94 -t freebsd-boot ada1
# gpart add -s 4G -t freebsd-swap -l swap1 ada1
# gpart add -t freebsd-zfs -l disk1 ada1
# gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada1
# kldload geom_mirror.ko
# gmirror label -F -h -b round-robin swap /dev/gpt/swap0 /dev/gpt/swap1
# kldload opensolaris.ko
# kldload zfs.ko
# gnop create -S 4096 /dev/gpt/disk0
# gnop create -S 4096 /dev/gpt/disk1
# zpool create -o altroot=/mnt -o cachefile=/var/tmp/zpool.cache rpool mirror /dev/gpt/disk0.nop /dev/gpt/disk1.nop
# zpool export rpool
# gnop destroy /dev/gpt/disk0.nop
# gnop destroy /dev/gpt/disk1.nop
# zpool import -o altroot=/mnt -o cachefile=/var/tmp/zpool.cache rpool
# zfs set checksum=fletcher4 rpool
# zfs set atime=off rpool
# zfs create rpool/ROOT
# zfs create -o mountpoint=/ rpool/ROOT/default
# zfs set freebsd:boot-environment=1 rpool/ROOT/default
# zpool set bootfs=rpool/ROOT/default rpool
# zfs create -o mountpoint=/usr/local rpool/local
# zfs create -o mountpoint=/var rpool/var
# zfs create -o compression=lzjb -o exec=off -o setuid=off rpool/var/crash
# zfs create -o exec=off -o setuid=off rpool/var/db
# zfs create -o compression=lzjb -o exec=on -o setuid=off rpool/var/db/pkg
# zfs create -o exec=off -o setuid=off rpool/var/empty
# zfs create -o compression=lzjb -o exec=off -o setuid=off rpool/var/log
# zfs create -o compression=gzip -o exec=off -o setuid=off rpool/var/mail
# zfs create -o exec=off -o setuid=off rpool/var/run
# zfs create -o compression=lzjb -o exec=on -o setuid=off rpool/var/tmp
# zfs create -o mountpoint=/tmp -o compression=on -o exec=on -o setuid=off rpool/tmp
# zfs create -o mountpoint=/home rpool/home
# chmod 1777 /mnt/tmp
# chmod 1777 /mnt/var/tmp
# sh
# cd /usr/freebsd-dist
# export DESTDIR=/mnt
# for file in base.txz lib32.txz kernel.txz doc.txz;
> do (cat $file | tar --unlink -xpJf - -C ${DESTDIR:-/}); done
# zfs set readonly=on zroot/var/empty
# cp /var/tmp/zpool.cache /mnt/ROOT/default/boot/zfs/zpool.cache
# ee /mnt/etc/fstab
/dev/mirror/swap none swap sw 0 0
# ee /mnt/boot/loader.conf
geom_mirror_load="YES"
zfs_load="YES"
vfs.root.mountfrom="zfs:rpool/ROOT/default"
# ee /mnt/etc/rc.conf
hostname="freebsd9"
keymap="fr.iso.acc"
zfs_enable="YES"

network_interfaces="lo0 em0"
defaultrouter="192.168.0.1"
ipv6_defaultrouter="fdcb:9921:3552:afd7::1"
ifconfig_em0="inet 192.168.0.2 netmask 255.255.255.0 polling"
ifconfig_em0_ipv6="inet fdcb:9921:3552:afd7::2 prefixlen 64"

clear_tmp_enable="YES"
tcp_drop_synfin="YES"

moused_enable="NO"
sendmail_enable="NONE"
sshd_enable="YES"
syslogd_flags="-ss"
# ee /mnt/etc/resolv.conf
nameserver 192.168.0.254
search my.domain
# echo 'daily_status_gmirror_enable="YES"' >> /mnt/etc/periodic.conf
# echo 'daily_status_zfs_enable="YES"'' >> /mnt/etc/periodic.conf
# echo 'daily_status_smart_devices="/dev/ada0 /dev/ada1"' >> /mnt/etc/periodic.conf
# echo 'daily_status_mail_rejects_enable="NO"' >> /mnt/etc/periodic.conf
# echo 'daily_status_include_submit_mailq="NO"' >> /mnt/etc/periodic.conf
# echo 'daily_submit_queuerun="NO"' >> /mnt/etc/periodic.conf
# echo 'WRKDIRPREFIX=/usr/obj' >> /mnt/etc/make.conf
# chroot /mnt
# passwd
# tzsetup
# cd /etc/mail
# nano aliases
# make aliases
# exit
# zfs umount -a
# zfs set mountpoint=/rpool rpool
# zfs set mountpoint=/rpool/ROOT rpool/ROOT
# zfs set mountpoint=legacy rpool/ROOT/default
# shutdown -r now

Démarrage du système

# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
rpool                687M  14.7G   152K  /rpool
rpool/ROOT           683M  14.7G   144K  /rpool/ROOT
rpool/ROOT/default   683M  14.7G   683M  legacy
rpool/home           144K  14.7G   144K  /home
rpool/local          144K  14.7G   144K  /usr/local
rpool/tmp            176K  14.7G   176K  /tmp
rpool/var           1.89M  14.7G   564K  /var
rpool/var/crash      148K  14.7G   148K  /var/crash
rpool/var/db         388K  14.7G   244K  /var/db
rpool/var/db/pkg     144K  14.7G   144K  /var/db/pkg
rpool/var/empty      144K  14.7G   144K  /var/empty
rpool/var/log        188K  14.7G   188K  /var/log
rpool/var/mail       144K  14.7G   144K  /var/mail
rpool/var/run        204K  14.7G   204K  /var/run
rpool/var/tmp        152K  14.7G   152K  /var/tmp
# zfs snapshot rpool/ROOT/default@clean

Création d’un nouvel environnement

On commence par installer la commande beadm :

# cd /usr/ports/sysutils/beadm
# make install

On peut dès lors vérifier que le BE default est bien détecté :

# beadm list
BE      Active Mountpoint  Space Created
default NR     /            1.8G 2012-10-08 04:33

La création d’un BE nécessite uniquement de spécifier son nom :

# beadm create upgrade
Created successfully
# beadm list
BE      Active Mountpoint  Space Created
default NR     /            1.8G 2012-04-19 15:05
upgrade -      -          136.0K 2012-10-08 06:25

Il est également possible de cloner un BE existant en spécifiant son nom.

Au niveau du pool ZFS, le BE se matérialise par un nouveau clone :

# zfs list
NAME                 USED  AVAIL  REFER  MOUNTPOINT
rpool               1.83G  13.6G   152K  /rpool
rpool/ROOT          1.68G  13.6G   144K  /rpool/ROOT
rpool/ROOT/default  1.68G  13.6G  1.68G  legacy
rpool/ROOT/upgrade   144K  13.6G  1.68G  legacy
rpool/home           144K  13.6G   144K  /home
rpool/local         4.14M  13.6G  4.14M  /usr/local
rpool/tmp            184K  13.6G   184K  /tmp
rpool/var            146M  13.6G   564K  /var
rpool/var/crash      148K  13.6G   148K  /var/crash
rpool/var/db         145M  13.6G   144M  /var/db
rpool/var/db/pkg     196K  13.6G   196K  /var/db/pkg
rpool/var/empty      144K  13.6G   144K  /var/empty
rpool/var/log        192K  13.6G   192K  /var/log
rpool/var/mail       144K  13.6G   144K  /var/mail
rpool/var/run        204K  13.6G   204K  /var/run
rpool/var/tmp        152K  13.6G   152K  /var/tmp

Reste enfin à activer ce BE et redémarrer le système :

# beadm activate upgrade
Activated successfully
# shutdown -r now

A présent, l’ensemble des opérations affecte le BE upgrade. En cas d’erreur, une réactivation du BE default permettra un redémarrage du système.