Ce HOWTO utilise une carte SD physique entière.
Sauvegarder les données. Toutes les données existantes seront perdues.
Le cryptage n'a pas encore été testé sur le Raspberry Pi.
Ce guide prend en charge trois options de cryptage différentes : non crypté, cryptage natif ZFS et LUKS. Avec n'importe quelle option, toutes les fonctionnalités ZFS sont entièrement disponibles.
Les commandes de cette étape sont exécutées sur le système autre que le Raspberry Pi.
Ce guide vous propose un travail supplémentaire afin que la partition stock ext4 puisse être supprimée.
Télécharger et décompresser l'image officielle :
curl -O https://cdimage.ubuntu.com/releases/20.04.2/release/ubuntu-20.04.2-preinstalled-server-arm64+raspi.img.xz xz -d ubuntu-20.04.2-preinstalled-server-arm64+raspi.img.xz # ou combiner-les pour décompresser au fur et à mesure du téléchargement : curl https://cdimage.ubuntu.com/releases/20.04.2/release/ubuntu-20.04.2-preinstalled-server-arm64+raspi.img.xz | \ xz -d > ubuntu-20.04.2-preinstalled-server-arm64+raspi.img
Vider la table de partition pour l'image :
sfdisk -d ubuntu-20.04.2-preinstalled-server-arm64+raspi.img
Cela affichera ceci :
label: dos label-id: 0x4ec8ea53 device: ubuntu-20.04.2-preinstalled-server-arm64+raspi.img unit: sectors <name>.img1 : start= 2048, size= 524288, type=c, bootable <name>.img2 : start= 526336, size= 5839840, type=83
Les nombres importants sont 524288 et 5839840. Stocker-les dans des variables :
export BOOT=524288 export ROOT=5839840
Créer un script de partition :
vi partitions.sh
avec le contenu suivant :
cat << EOF label: dos unit: sectors 1 : start= 2048, size=$BOOT, type=c, bootable 2 : start=$((2048+BOOT)), size=$ROOT, type=83 3 : start=$((2048+BOOT+ROOT)), size=$ROOT, type=83 EOF
Connecter la carte SD :
Connecter la carte SD à une machine autre que le Raspberry Pi cible. Si des systèmes de fichiers sont montés automatiquement (par exemple par GNOME), démonter-les. Déterminer le nom du périphérique (qui est presque certainement comme indiqué ci-dessous) et définisser-le dans une variable :
DISK=/dev/mmcblk0
Effacer les anciennes étiquettes ZFS :
sudo zpool labelclear -f ${DISK}
Si une étiquette ZFS existe toujours à partir d'un système/d'une tentative précédente, l'extension du pool entraînera un système non amorçable.
si les utilitaires ZFS ne sont pas déjà installé , on peut les installer avec : sudo apt install zfsutils-linux
Alternativement, on peut mettre à zéro toute la carte SD avec : sudo dd if=/dev/zero of=${DISK} bs=1M status=progress
Supprimer les partitions existantes :
echo "label: dos" | sudo sfdisk ${DISK} sudo partprobe ls ${DISK}*
S'assurer qu'il n'y a pas de partitions, juste le fichier pour le disque lui-même. Cette étape n'est pas strictement nécessaire ; il existe pour attraper les problèmes.
Créer les partitions :
sh -u partitions.sh | sudo sfdisk $DISK
Monter l'image en loop :
IMG=$(sudo losetup -fP --show \ ubuntu-20.04.2-preinstalled-server-arm64+raspi.img)
Copier les données du chargeur de démarrage :
sudo dd if=${IMG}p1 of=${DISK}p1 bs=1M
Effacer les anciennes étiquettes de la partition 2 :
sudo wipefs -a ${DISK}p2
Si un système de fichiers avec l'étiquette inscriptible de l'image Ubuntu est toujours présent dans la partition 2, le système ne démarrera pas initialement.
Copier les données du système de fichiers racine :
# la destination est p3, pas p2. sudo dd if=${IMG}p2 of=${DISK}p3 bs=1M status=progress conv=fsync
Démonter l'image :
sudo losetup -d $IMG
Démarrer le Raspberry Pi.
Placer la carte SD dans le Raspberry Pi. Démarrer et se connecter (par exemple via SSH) avec ubuntu comme nom d'utilisateur et mot de passe. Lorsqu'on utilise SSH, il faut un peu de temps à cloud-init pour activer les connexions par mot de passe au premier démarrage. Définir un nouveau mot de passe lorsque on y est invité et se connecter à nouveau en utilisant ce mot de passe. Si le SSH local est configuré pour utiliser ControlPersist, il faudra tuer le processus SSH existant avant de se connecter pour la deuxième fois.
Devenir root :
sudo -i
Définir une variable avec le nom du disque :
DISK=/dev/mmcblk0
Sur le Pi, c'est toujours mmcblk0.
Installer ZFS :
mise à jour appropriée
apt install pv zfs-initramfs
Étant donné qu'il s'agit du premier démarrage, on peut obtenir En attente du verrouillage du cache car les mises à niveau sans surveillance s'exécutent en arrière-plan. Attender qu'il se termine.
Créer le pool racine :
Choisisser l'une des options suivantes :
zpool create \ -o ashift=12 \ -O acltype=posixacl -O canmount=off -O compression=lz4 \ -O dnodesize=auto -O normalization=formD -O relatime=on \ -O xattr=sa -O mountpoint=/ -R /mnt \ rpool ${DISK}p2
Le cryptage n'a pas encore été testé sur le Raspberry Pi.
zpool create \ -o ashift=12 \ -O encryption=aes-256-gcm \ -O keylocation=prompt -O keyformat=passphrase \ -O acltype=posixacl -O canmount=off -O compression=lz4 \ -O dnodesize=auto -O normalization=formD -O relatime=on \ -O xattr=sa -O mountpoint=/ -R /mnt \ rpool ${DISK}p2
cryptsetup luksFormat -c aes-xts-plain64 -s 512 -h sha256 ${DISK}p2 cryptsetup luksOpen ${DISK}-part4 luks1 zpool create \ -o ashift=12 \ -O acltype=posixacl -O canmount=off -O compression=lz4 \ -O dnodesize=auto -O normalization=formD -O relatime=on \ -O xattr=sa -O mountpoint=/ -R /mnt \ rpool /dev/mapper/luks1
L'utilisation de ashift=12
est recommandée ici car de nombreux disques ont aujourd'hui 4 KiB (ou plus) de secteurs physiques, même s'ils présentent 512 B de secteurs logiques. De plus, un futur disque de remplacement peut avoir 4 secteurs physiques de Ko (auquel cas ashift=12
est souhaitable) ou des secteurs logiques de 4 Ko (auquel cas ashift=12 est requis).
La définition de -O acltype=posixacl
active les ACL POSIX globalement. Si on ne le souhaite pas, supprimer cette option, mais ajouter plus tard -o acltype=posixacl
(« o » minuscule) à la création de zfs pour /var/log, car journald nécessite des ACL. De plus, la désactivation des ACL interrompt apparemment la gestion d'umask avec NFSv4.
La définition de normalisation=formD élimine certains cas de coin liés à la normalisation des noms de fichiers UTF-8. Cela implique également utf8only=on, ce qui signifie que seuls les noms de fichiers UTF-8 sont autorisés. Si on souhaite prendre en charge les noms de fichiers non UTF-8, ne pas utiliser pas cette option.
recordsize
n'est pas défini (en le laissant à la valeur par défaut de 128 Ko). Si on veut le régler (par exemple, -o recordsize=1M
), consulter ces différents articles de blog.
Définir relatime=on
est un juste milieu entre le comportement atime
classique de POSIX (avec son impact significatif sur les performances) et atime=off
(qui offre les meilleures performances en désactivant complètement les mises à jour atime). Depuis Linux 2.6.30, relatime
est la valeur par défaut pour les autres systèmes de fichiers. Voir la documentation de RedHat pour plus d'informations.
La définition de xattr=sa
améliore considérablement les performances des attributs étendus. Dans ZFS, les attributs étendus sont utilisés pour implémenter les ACL POSIX. Les attributs étendus peuvent également être utilisés par les applications de l'espace utilisateur. Ils sont utilisés par certaines applications GUI de bureau. Ils peuvent être utilisés par Samba pour stocker les ACL Windows et les attributs DOS ; ils sont requis pour un contrôleur de domaine Samba Active Directory. xattr=sa
est spécifique à Linux. Si on déplace le pool xattr=sa
vers une autre implémentation OpenZFS en plus de ZFS-on-Linux, les attributs étendus ne seront pas lisibles (bien que les données le soient). Si la portabilité des attributs étendus est importante, omettre le -O xattr=sa
ci-dessus. Même si on ne veut pas de xattr=sa
pour l'ensemble du pool, on peut probablement l'utiliser pour /var/log.
S'assurer d'inclure la partie -part4
du chemin du lecteur. Omettre cela, spécifie le disque entier, que ZFS repartitionnera ensuite, et on perd la ou les partitions du chargeur de démarrage.
Le chiffrement natif ZFS est par défaut aes-256-ccm
, mais la valeur par défaut a été modifiée en amont par aes-256-gcm
. AES-GCM semble être généralement préféré à AES-CCM, est plus rapide maintenant et le sera encore plus à l'avenir.
Pour LUKS, la taille de clé choisie est de 512 bits. Cependant, le mode XTS nécessite deux clés, la clé LUKS est donc divisée en deux. Ainsi, -s 512
signifie AES-256.
Le mot de passe sera probablement le maillon le plus faible. Il faut le choisir avec rigueur.
zfs create -o canmount=off -o mountpoint=none rpool/ROOT
UUID=$(dd if=/dev/urandom bs=1 count=100 2>/dev/null | tr -dc 'a-z0-9' | cut -c-6) zfs create -o canmount=noauto -o mountpoint=/ \ -o com.ubuntu.zsys:bootfs=yes \ -o com.ubuntu.zsys:last-used=$(date +%s) rpool/ROOT/ubuntu_$UUID zfs mount rpool/ROOT/ubuntu_$UUID
Avec ZFS, il n'est normalement pas nécessaire d'utiliser une commande de montage (soit mount, soit zfs mount). Cette situation est une exception en raison de canmount=noauto.
zfs create -o com.ubuntu.zsys:bootfs=no \ rpool/ROOT/ubuntu_$UUID/srv zfs create -o com.ubuntu.zsys:bootfs=no -o canmount=off \ rpool/ROOT/ubuntu_$UUID/usr zfs create rpool/ROOT/ubuntu_$UUID/usr/local zfs create -o com.ubuntu.zsys:bootfs=no -o canmount=off \ rpool/ROOT/ubuntu_$UUID/var zfs create rpool/ROOT/ubuntu_$UUID/var/games zfs create rpool/ROOT/ubuntu_$UUID/var/lib zfs create rpool/ROOT/ubuntu_$UUID/var/lib/AccountsService zfs create rpool/ROOT/ubuntu_$UUID/var/lib/apt zfs create rpool/ROOT/ubuntu_$UUID/var/lib/dpkg zfs create rpool/ROOT/ubuntu_$UUID/var/lib/NetworkManager zfs create rpool/ROOT/ubuntu_$UUID/var/log zfs create rpool/ROOT/ubuntu_$UUID/var/mail zfs create rpool/ROOT/ubuntu_$UUID/var/snap zfs create rpool/ROOT/ubuntu_$UUID/var/spool zfs create rpool/ROOT/ubuntu_$UUID/var/www zfs create -o canmount=off -o mountpoint=/ \ rpool/USERDATA zfs create -o com.ubuntu.zsys:bootfs-datasets=rpool/ROOT/ubuntu_$UUID \ -o canmount=on -o mountpoint=/root \ rpool/USERDATA/root_$UUID
Si on veut un ensemble de données séparé pour /tmp :
zfs create -o com.ubuntu.zsys:bootfs=no \ rpool/ROOT/ubuntu_$UUID/tmp chmod 1777 /mnt/tmp
L'objectif principal de cette disposition de jeu de données est de séparer le système d'exploitation des données utilisateur. Cela permet de restaurer le système de fichiers racine sans restaurer les données utilisateur.
Si on ne fait rien de plus, /tmp sera stocké dans le système de fichiers racine. on peut également créer un ensemble de données distinct pour /tmp, comme indiqué ci-dessus. Cela empêche les données /tmp des instantanés du système de fichiers racine. Il vous permet également de définir un quota sur rpool/tmp, si vous souhaiter limiter l'espace maximum utilisé. Sinon, on peut utiliser un tmpfs (système de fichiers RAM) plus tard.
Les cartes SD sont relativement lentes. Si vous souhaiter augmenter les performances (en particulier lors de l'installation de packages) au prix d'une certaine sécurité, on peut désactiver le vidage des requêtes synchrones (par exemple, fsync(), O_[D]SYNC) :
Choisir l'une des options suivantes :
zfs set sync=disabled rpool/ROOT
zfs set sync=disabled rpool
ZFS est transactionnel, il sera donc toujours cohérent en cas de plantage. Cependant, il faut laisser la synchronisation à sa valeur par défaut si ce système doit garantir la persistance (par exemple, s'il s'agit d'une base de données ou d'un serveur NFS).
(cd /; tar -cf - --one-file-system --warning=no-file-ignored .) | \ pv -p -bs $(du -sxm --apparent-size / | cut -f1)m | \ (cd /mnt ; tar -x)
Remplacer HOSTNAME par le nom d'hôte souhaité :
echo HOSTNAME > /mnt/etc/hostname vi /mnt/etc/hosts
127.0.1.1 HOSTNAME
127.0.1.1 HOSTNAME FQDN
systemctl stop zed
Lier les systèmes de fichiers virtuels de l'environnement en cours d'exécution au nouvel environnement ZFS et se chrooter dedans :
mount --rbind /boot/firmware /mnt/boot/firmware mount --rbind /dev /mnt/dev mount --rbind /proc /mnt/proc mount --rbind /run /mnt/run mount --rbind /sys /mnt/sys chroot /mnt /usr/bin/env DISK=$DISK UUID=$UUID bash --login
apt update
Même si on préfére une langue système autre que l'anglais, S'assurer toujours que en_US.UTF-8
est disponible :
dpkg-reconfigure locales dpkg-reconfigure tzdata
Pour les installations LUKS uniquement, configurer /etc/crypttab :
# cryptsetup est déjà installé, mais cela le marque comme manuellement # installé afin qu'il ne soit pas automatiquement supprimé. apt install --yes cryptsetup echo luks1 UUID=$(blkid -s UUID -o value ${DISK}-part4) none \ luks,discard,initramfs > /etc/crypttab
L'utilisation d'initramfs est une solution de contournement car cryptsetup ne prend pas en charge ZFS.
Si on a choisi de créer un ensemble de données /tmp ci-dessus, ignorer cette étape, car ce sont des choix mutuellement exclusifs. Sinon, on peut mettre /tmp sur un tmpfs (système de fichiers RAM) en activant l'unité tmp.mount.
cp /usr/share/systemd/tmp.mount /etc/systemd/system/ systemctl enable tmp.mount
curl https://launchpadlibrarian.net/478315221/2150-fix-systemd-dependency-loops.patch | \ sed "s|/etc|/lib|;s|\.in$||" | (cd / ; sudo patch -p1)
Ce correctif provient du bogue #1875577 L'échange crypté ne se chargera pas le 20.04 avec la racine zfs.
Il faut activer zfs-mount-generator. Cela rend systemd conscient des points de montage séparés, ce qui est important pour des choses comme /var/log et /var/tmp. À son tour, rsyslog.service dépend de var-log.mount via local-fs.target et les services utilisant la fonction PrivateTmp de systemd utilisent automatiquement After=var-tmp.mount.
mkdir /etc/zfs/zfs-list.cache touch /etc/zfs/zfs-list.cache/rpool ln -s /usr/lib/zfs-linux/zed.d/history_event-zfs-list-cacher.sh /etc/zfs/zed.d zed -F &
Forcer une mise à jour du cache :
zfs set canmount=noauto rpool/ROOT/ubuntu_$UUID
Vérifier que zed a mis à jour le cache en vous assurant qu'il n'est pas vide, ce qui prendra quelques secondes :
cat /etc/zfs/zfs-list.cache/rpool
Arrêter zed :
fg Press Ctrl-C.
Corriger les chemins pour éliminer /mnt :
sed -Ei "s|/mnt/?|/|" /etc/zfs/zfs-list.cache/*
Supprimer l'ancien système de fichiers de /etc/fstab :
vi /etc/fstab # Supprimer l'ancienne ligne du système de fichiers racine : # LABEL=writable / ext4 ...
Configurer la ligne de commande du noyau :
cp /boot/firmware/cmdline.txt /boot/firmware/cmdline.txt.bak sed -i "s|root=LABEL=writable rootfstype=ext4|root=ZFS=rpool/ROOT/ubuntu_$UUID|" \ /boot/firmware/cmdline.txt sed -i "s| fixrtc||" /boot/firmware/cmdline.txt sed -i "s|$| init_on_alloc=0|" /boot/firmware/cmdline.txt
Le script fixrtc n'est pas compatible avec ZFS et entraînera un blocage du démarrage pendant 180 secondes.
L'initonalloc=0 est destiné à traiter les régressions de performances.
sed -i "s|$| nosplash|" /boot/firmware/cmdline.txt
exit reboot
Attendre que le système nouvellement installé démarre normalement. Se connecter en tant qu'ubuntu et devenir root avec sudo -i
.
sfdisk /dev/mmcblk0 --delete 3 echo ", +" | sfdisk --no-reread -N 2 /dev/mmcblk0
cela n'étend pas automatiquement le pool. Cela se produira au redémarrage.
Remplacer le nom d'utilisateur par le nom d'utilisateur souhaité :
UUID=$(dd if=/dev/urandom bs=1 count=100 2>/dev/null | tr -dc 'a-z0-9' | cut -c-6) ROOT_DS=$(zfs list -o name | awk '/ROOT\/ubuntu_/{print $1;exit}') zfs create -o com.ubuntu.zsys:bootfs-datasets=$ROOT_DS \ -o canmount=on -o mountpoint=/home/username \ rpool/USERDATA/username_$UUID adduser username cp -a /etc/skel/. /home/username chown -R username:username /home/username usermod -a -G adm,cdrom,dip,lxd,plugdev,sudo username
reboot
Attendre que le système démarre normalement. Se connecter avec son nom d'utilisateur et devenir root avec sudo -i
.
Vérifier que le pool a été étendu :
zfs liste rpool
S'il ne s'est pas développé automatiquement, essayer de le développer manuellement :
zpool online -e rpool mmcblk0p2
deluser --remove-home ubuntu
vi /etc/netplan/01-netcfg.yaml network: version: 2 ethernets: eth0: dhcp4: true rm /etc/netplan/50-cloud-init.yaml apt purge --autoremove ^cloud-init
apt purge --autoremove bcache-tools btrfs-progs cloud-guest-utils lvm2 \ mdadm multipath-tools open-iscsi overlayroot xfsprogs
Mettre à niveau le système minimal :
apt dist-upgrade --yes
apt install --yes ubuntu-desktop
Si on installe un environnement GUI complet, il est préférable de supprimer cloud-init comme indiqué ci-dessus, pour gérer le réseau avec NetworkManager :
rm /etc/netplan/*.yaml
vi /etc/netplan/01-network-manager-all.yaml
network:
version: 2
renderer: NetworkManager
Comme /var/log
est déjà compressé par ZFS, la compression de logrotate va brûler les E/S du processeur et du disque pour (dans la plupart des cas) très peu de gain. De plus, si on crée des instantanés de /var/log
, la compression de logrotate gaspillera en fait de l'espace, car les données non compressées vivront dans l'instantané. on peut éditer les fichiers dans /etc/logrotate.d
à la main pour commenter la compression, ou utiliser cette boucle (copier-coller fortement recommandé) :
for file in /etc/logrotate.d/* ; do if grep -Eq "(^|[^#y])compress" "$file" ; then sed -i -r "s/(^|[^#y])(compress)/\1#\2/" "$file" fi done
reboot
Attendre que le système démarre normalement. Se connecter en utilisant le compte créé. S'assurer que le système (y compris le réseau) fonctionne normalement.
sudo cryptsetup luksHeaderBackup /dev/disk/by-id/scsi-SATA_disk1-part4 \ --header-backup-file luks1-header.dat
Stocker cette sauvegarde dans un endroit sûr. Il est protégé par votre mot de passe LUKS, mais on peut utiliser un cryptage supplémentaire.