Introduction Link to heading

J’ai récemment fait l’acquisition d’une nouvelle machine pour mon homelab. Cette machine, plus puissante que celles que j’avais pu acheter par le passé, aura pour vocation de remplacer plusieurs petits appareils de ma baie, libérant ainsi de l’espace et quelques ports de mon onduleur.

C’est une machine que j’ai choisie pour son faible encombrement, ses multiples ports réseaux et ses 3 slots m.2 me permettant d’y mettre une quantité raisonnable de stockage.

Ce sont aussi ces trois slots qui m’ont donnés envie de gérer mon stockage de la « bonne manière ». Là où habituellement je chiffre seulement mes disques et pose du lvm dessus, j’ai décidé cette fois d’ajouter de la fiabilité à mon installation en configurant deux des disques en miroir.

Il existe différentes solutions permettant de faire cette configuration en miroir (via ZFS, LVM, etc.), j’ai choisi de le faire via mdadm pour la simplicité de sa mise en place et de son utilisation.

Configuration du RAID Link to heading

Sur chacun des deux disques, j’ai créé une partition dont la taille est <espace complet du plus petit disque>-100M. En cas de problème ou si je décidais de rajouter un disque dans l’array, il faudrait que la partition sur le nouveau disque ait exactement la même taille que celles des autres disques et il peut arriver qu’entre deux disques de même capacité chez un même constructeur, l’espace disponible soit légèrement différent, d’où les 100M de marge.

# sgdisk -o -n 1:0:+1862900M -t 1:FD00 /dev/nvme0n1
# sgdisk -o -n 1:0:+1862900M -t 1:FD00 /dev/nvme1n1

FD00 est le code hexadécimal correspondant à une partition de type Linux RAID pour gdisk.

La commande pour créer l’array est ensuite

# mdadm --create --verbose --level=1 --metadata=1.2 --raid-devices=2 /dev/md/gullintanni /dev/nvme0n1p1 /dev/nvme1n1p1

Il faut ensuite ajouter l’array à la configuration de mdadm :

# mdadm --detail --scan
ARRAY /dev/md/gullintanni metadata=1.2 name=heimdallr:gullintanni UUID=abeec7d2:221a1c72:528275a5:5984f735

# mdadm --detail --scan >> /etc/mdadm.conf

Vous pouvez suivre l’état de la réplication des disques via la commande : watch -n 30 cat /proc/mdstat.

Configuration de luks Link to heading

Il s’agit maintenant de chiffrer ce nouveau disque :

# cryptsetup luksFormat /dev/md/gullintanni

Je souhaite aussi qu’il soit déchiffré au démarrage de son hôte. Il faut pour ça que je crée une clef à ajouter au luks pour déchiffrer le volume :

# mkdir -p /etc/cryptsetup-keys.d/
# chmod 700 /etc/cryptsetup-keys.d/
# dd if=/dev/random bs=512 count=1 of=/etc/cryptsetup-keys.d/gullintanni.key
# chmod 600 /etc/cryptsetup-keys.d/gullintanni.key
# cryptsetup luksAddKey /dev/md/gullintanni /etc/cryptsetup-keys.d/gullintanni.key

Je n’ai plus qu’à ajouter au fichier /etc/crypttab une entrée correspondante à ce volume, sous la forme <nom> UUID=<uuid>. Je peux récupérer l’uuid du volume via la commande lsblk -f.

# echo "gullintanni UUID=06331d26-0f0c-4a40-9672-06bfe4d7d5ae" >> /etc/crypttab 

Pas besoin de renseigner le chemin de la clef : au démarrage systemd-cryptsetup cherchera dans le dossier /etc/cryptsetup-keys.d/ une clef au nom de <nom du volume>.key.

Il est conseillé de faire une sauvegarde des entêtes luks (et de la stocker hors du volume chiffré dont elle est issue) :

# cryptsetup luksHeaderBackup /dev/md/gullintanni --header-backup-file ~vianney/gullintanni-luks-headers.img

Pour le déchiffrer manuellement cette première fois :

# cryptsetup luksOpen /dev/md/gullintanni gullintanni

Configuration de lvm Link to heading

La configuration de lvm est simple : il suffit de créer un PV (physical volume) depuis /dev/mapper/gullintanni, de l’associer à un VG (Volume Group) et de tailler selon son besoin des LV (Logical Volume) dedans.

# pvcreate /dev/mapper/gullintanni
# vgcreate gullintanni /dev/mapper/gullintanni

Dans ce VG, je compte utiliser des LV en thin provisioning comme disques pour mes machines virtuelles. Ici par exemple pour une VM nommée paperless :

# lvcreate --type thin-pool -n libvirt -L 250G gullintanni
# lvcreate -n libvirt-paperless -V 30G --thinpool libvirt gullintanni

Un autre LV en thin-pool me servira à stocker les dossiers des utilisateurs :

# lvcreate --type thin-pool -n home -L 50G gullintanni

# lvcreate -n home-vianney -V 30G --thinpool home gullintanni
# lvcreate -n home-<autre utilisateur> -V 30G --thinpool home gullintanni

Il s’agit maintenant de formatter ces LV et de les monter à l’endroit désiré.

# mkfs.ext4 /dev/gullintanni/home-vianney
# echo "/dev/gullintanni/home-vianney		/home/ldap/vianney	ext4	rw,relatime,discard	0 2" >> /etc/fstab
# mkdir -p /home/ldap/vianney
# mount -a
# chown vianney: /home/ldap/vianney
# chmod 700 /home/ldap/vianney

Pas besoin de rajouter de hook particulière dans l’initramfs : le volume que j’ai créé peut être déchiffré puis monté tardivement dans processus de démarrage. systemd saura gérer les dépendances entre la mise en place de l’array, le déchiffrement du disque puis le montage du LV au démarrage.

En conclusion Link to heading

Si la configuration de ce stockage a pu me demander plus de travail que d’habitude, celui-ci me fournira plus de souplesse pour la gestion des quotas de disque par application ainsi que plus de fiabilité.

# lsblk
[...]
nvme1n1                                    259:0    0  1.8T  0 disk  
└─nvme1n1p1                                259:2    0  1.8T  0 part  
  └─md127                                    9:127  0  1.8T  0 raid1 
    └─gullintanni                          254:0    0  1.8T  0 crypt 
      ├─gullintanni-libvirt_tmeta          254:1    0  128M  0 lvm   
      │ └─gullintanni-libvirt-tpool        254:3    0  250G  0 lvm   
      │   ├─gullintanni-libvirt            254:4    0  250G  1 lvm   
      │   └─gullintanni-libvirt--paperless 254:5    0   30G  0 lvm   
      ├─gullintanni-libvirt_tdata          254:2    0  250G  0 lvm   
      │ └─gullintanni-libvirt-tpool        254:3    0  250G  0 lvm   
      │   ├─gullintanni-libvirt            254:4    0  250G  1 lvm   
      │   └─gullintanni-libvirt--paperless 254:5    0   30G  0 lvm   
      ├─gullintanni-home_tmeta             254:6    0   52M  0 lvm   
      │ └─gullintanni-home-tpool           254:8    0   50G  0 lvm   
      │   ├─gullintanni-home               254:9    0   50G  1 lvm   
      │   └─gullintanni-home--vianney      254:10   0   30G  0 lvm   /home/ldap/vianney
      └─gullintanni-home_tdata             254:7    0   50G  0 lvm   
        └─gullintanni-home-tpool           254:8    0   50G  0 lvm   
          ├─gullintanni-home               254:9    0   50G  1 lvm   
          └─gullintanni-home--vianney      254:10   0   30G  0 lvm   /home/ldap/vianney
nvme0n1                                    259:1    0  1.8T  0 disk  
└─nvme0n1p1                                259:3    0  1.8T  0 part  
  └─md127                                    9:127  0  1.8T  0 raid1 
    └─gullintanni                          254:0    0  1.8T  0 crypt 
      ├─gullintanni-libvirt_tmeta          254:1    0  128M  0 lvm   
      │ └─gullintanni-libvirt-tpool        254:3    0  250G  0 lvm   
      │   ├─gullintanni-libvirt            254:4    0  250G  1 lvm   
      │   └─gullintanni-libvirt--paperless 254:5    0   30G  0 lvm   
      ├─gullintanni-libvirt_tdata          254:2    0  250G  0 lvm   
      │ └─gullintanni-libvirt-tpool        254:3    0  250G  0 lvm   
      │   ├─gullintanni-libvirt            254:4    0  250G  1 lvm   
      │   └─gullintanni-libvirt--paperless 254:5    0   30G  0 lvm   
      ├─gullintanni-home_tmeta             254:6    0   52M  0 lvm   
      │ └─gullintanni-home-tpool           254:8    0   50G  0 lvm   
      │   ├─gullintanni-home               254:9    0   50G  1 lvm   
      │   └─gullintanni-home--vianney      254:10   0   30G  0 lvm   /home/ldap/vianney
      └─gullintanni-home_tdata             254:7    0   50G  0 lvm   
        └─gullintanni-home-tpool           254:8    0   50G  0 lvm   
          ├─gullintanni-home               254:9    0   50G  1 lvm   
          └─gullintanni-home--vianney      254:10   0   30G  0 lvm   /home/ldap/vianney