Guide de suppression d’une matrice mdadm RAID1 tout en préservant les données existantes de la partition, évitant ainsi d’avoir à réinstaller ou copier des fichiers.

Si jamais vous avez un besoin similaire, voici comment je m’en suis sorti. Il va de soi que vous devriez sauvegarder les données avant de faire quoi que ce soit, à défaut vous acceptez le risque de tout perdre. Hic sunt dracones 🐉

Contexte

Un serveur dédié SoYouStart avec deux disques, pour héberger des machines virtuelles via VMware ESXi. Malheureusement VMware ESXi ne prend pas en charge le RAID logiciel : comme solution de contournement, on peut attacher deux VMDK (disque virtuel) à chaque VM, chaque VMDK étant stocké sur un datastore (disque matériel) distinct, et configurer un RAID1 logiciel directement depuis la VM via mdadm .

Cette ennuyeuse limitation fut d’ailleurs l’une des principales motivations pour migrer de VMware ESXi vers Promox VE, ce dernier prenant en charge le RAID1 logiciel via ZFS. Le RAID étant désormais géré au niveau de l’hôte, plus besoin que les machines virtuelles gèrent elles-mêmes un RAID logiciel, et on peut ne conserver qu’un seul disque pour chaque VM.

Mode facile

On va retirer des partitions de la matrice, puis faire en sorte que mdadm se satisfasse d’une matrice RAID1 composée d’une seule partition.

Tout d’abord, inspecter partitions et disques pour identifier où se trouve quoi et ce qui doit être fait :

  • Quelles partitions constituent la matrice mdadm et sur quels disques.
  • Décider quelle partition va rester.
  • S’il y a d’autres partitions sur ces mêmes disques ET qu’on souhaite se débarrasser du disque, décider si elles peuvent être supprimées ou doivent être déplacées.
# lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda       8:0    0  100G  0 disk
├─sda1    8:1    0  953M  0 part  [SWAP]
└─sda2    8:2    0 99.1G  0 part
  └─md0   9:0    0 99.1G  0 raid1 /
sdb       8:16   0  100G  0 disk
├─sdb1    8:17   0  953M  0 part  /var/tmp
└─sdb2    8:18   0 99.1G  0 part
  └─md0   9:0    0 99.1G  0 raid1 /
# cat /proc/mdstat
md0 : active raid1 sda2[0] sdb2[1]
      103872512 blocks super 1.2 [2/2] [UU]
# mdadm --detail /dev/md0
State : active

Par exemple, ici :

  • On a disque avec une partition de swap et l’autre une partition /var/tmp.
  • La partition RAID1 md0 est répartie sur sda2 et sdb2.
  • On veut se débarrasser du disque sda et conserver sdb2.

Une fois que tout est décidé :

  • Faire tout ce qui doit être fait avec les partitions hors matrice.
  • Marquer manuellement les partitions à supprimer de la matrice comme ayant échoué, puis les retirer de la matrice et supprimer leur superbloc RAID :
# mdadm /dev/md0 --fail /dev/sda2
mdadm: set /dev/sda2 faulty in /dev/md0
# mdadm /dev/md0 --remove /dev/sda2
mdadm: hot removed /dev/sda2 from /dev/md0
# mdadm --zero-superblock /dev/sda2

Dans notre cas, on a d’abord supprimé la partition de swap sda1 (non illustré ci-dessus : désactivée avec swapoff et mise à jour de /etc/fstab), puis supprimé sda2 de la matrice.

Si on s’arrêtait ici, mdadm se plaindrait que la matrice est dégradée car il lui manque une partition :

# cat /proc/mdstat
md0 : active raid1 sdb2[1]
      103872512 blocks super 1.2 [2/1] [_U]
# mdadm --detail /dev/md0
State : clean, degraded

Heureusement, on peut forcer la matrice à se satisfaire d’une seule partition pour qu’elle ne se plaigne pas d’être dégradée :

# mdadm --grow /dev/md0 --force --raid-devices=1
raid_disks for /dev/md0 set to 1
# cat /proc/mdstat
md0 : active raid1 sdb2[1]
      103872512 blocks super 1.2 [1/1] [U]
# mdadm --detail /dev/md0
State : clean

Si la partition ou disque supprimé était également la partition ou disque de démarrage, s’assurer de mettre à jour grub, initramfs et /etc/fstab si nécessaire :

# vi /etc/fstab
# grub-install /dev/sdb
# update-initramfs -u

Dans notre cas :

  • La partition RAID1 md0 est la partition de démarrage mais le bootloader n’a été installé que sur sda (vérifier la présence de GRUB avec dd if=/dev/sda bs=512 count=1 2> /dev/null | strings), on a donc dû réinstaller grub sur le disque sdb restant pour que le démarrage puisse s’effectuer depuis ce dernier.
  • initramfs fait référence à la partition de swap via sa variable RESUME, on a donc dû la supprimer de /etc/initramfs-tools/conf.d/resume et mettre à jour initramfs puisque la partition de swap a été supprimée.

La machine peut maintenant être arrêtée et le disque inutilisé détaché du matériel. Mettre à jour l’ordre de démarrage des disques si nécessaire et démarrer : voilà !

# lsblk
NAME    MAJ:MIN RM  SIZE RO TYPE  MOUNTPOINT
sda       8:0    0  100G  0 disk
├─sda1    8:1    0  953M  0 part  /var/tmp
└─sda2    8:2    0 99.1G  0 part
  └─md0   9:0    0 99.1G  0 raid1 /

Mode Monsieur Propre

La solution ci-dessus fonctionne parfaitement. Cependant, si on souhaite aller plus loin et supprimer complètement mdadm, on doit également bidouiller le disque restant : l’idée générale est de réécrire la partition mdadm pour supprimer le superbloc RAID tout en gardant le reste intact.

Ce genre d’opération pas très nette sur les partitions est généralement effectuée à partir du mode rescue, mais dans cet article, on va le faire directement à partir du vrai système pour un maximum de sensations.

  • Inspecter les UUID des partitions actuelles :
# blkid
/dev/sda2: UUID="<sda2_uuid>" TYPE="linux_raid_member"
/dev/md0: UUID="<md0_uuid>" TYPE="ext4"

Prendre note à la fois de la partition RAID linux_raid_member (ici sda2) et de la partition sous-jacente elle-même (ici md0).

  • Inspecter la partition linux_raid_member restante et prendre note de la version et de l’offset des données :
# mdadm --examine /dev/sda2
Data Offset : 16384 sectors

D’après la man page:

The different sub-versions store the superblock at different locations on the device, either at the end (for 1.0), at the start (for 1.1) or 4K from the start (for 1.2). “1” is equivalent to “1.2” (the commonly preferred 1.x format). “default” is equivalent to “1.2”.

En version 1.2, tout ce qui précède l’offset des données dans la partition correspond au superbloc RAID, tout ce qui suit correspond à la partition sous-jacente.

  • Lancer fdisk sur le disque :
# fdisk -u /dev/sda
  • Depuis l’invite de commande fdisk, afficher les partitions avec p :
Command (m for help): p
Device     Boot   Start       End   Sectors   Size Id Type
/dev/sda1  *       2048   1953791   1951744   953M 83 Linux
/dev/sda2       1953792 209715199 207761408  99.1G fd Linux raid autodetect
  • Identifier la partition RAID et prendre note de ses offsets de début et fin.
  • Supprimer la partition avec d et son numéro de partition.
  • Créer une nouvelle partition avec n :
    • Choisir p comme primaire et réutiliser le même numéro de partition.
    • Lorsque invité à saisir le premier secteur, entrer la somme de l’offset de début et de l’offset des données (16384 + 1953792 = 1970176 en utilisant l’exemple ci-dessus).
    • Pour le dernier secteur, entrer l’offset de fin tel quel (ici 209715199).
    • Ne pas supprimer la signature du système de fichiers.
  • Enregistrer les changements avec w. Cela devrait positionner la nouvelle partition sda2 à la place de la partition sous-jacente (anciennement md0).
  • Redémarrer.

Spoiler : si la partition modifiée était également celle de démarrage, alors la sueur froide arrive maintenant 😱

C’est notre cas : on tombe grub rescue car on a détruit la partition de démarrage. Pour s’en sortir, on va pointer manuellement grub rescue vers notre toute nouvelle partition.

  • Depuis l’invite de commande grub rescue, afficher les variables de démarrage existantes avec set :
grub rescue> set
prefix=(mduuid/<sda2_uuid>)/boot/grub
root=mduuid/<sda2_uuid>

Comme on peut le voir, le problème est que grub pointe vers la partition que nous venons de détruire (<sda2_uuid>). Prendre note du chemin de fichier du prefix (ici /boot/grub).

  • Exécuter ls pour afficher les partitions existantes, nommées (hdX,msdosX) (MBR) ou (hdX,gptX) (GPT) :
grub rescue> ls
(hd0) (hd0,msdos2) (hd0,msdos1)
  • Exécuter ls sur chaque partition jusqu’à trouver celle contenant le chemin de fichier du prefix :
grub rescue> ls (hd0,msdos1)/boot/grub
error: file '/boot/grub' not found
grub rescue> ls (hd0,msdos2)/boot/grub
./ ../ unicode.pf2 i386-pc/ locale/ fonts/ grubenv grub.cfg
  • Une fois trouvée, définir manuellement les variables de démarrage :
grub rescue> set prefix=(hd0,msdos2)/boot/grub
grub rescue> set root=(hd0,msdos2)
  • Charger ensuite le module normal et le démarrer :
grub rescue> insmod normal
grub rescue> normal

Le système devrait démarrer normalement.

  • À ce stade, on peut à nouveau inspecter les partitions et voir que sda2 a correctement remplacé l’ancienne partition md0 :
# blkid
/dev/sda2: UUID="<md0_uuid>" TYPE="ext4"
  • Vérifier que mdadm a été correctement supprimé :
# lsblk
NAME   MAJ:MIN RM  SIZE RO TYPE MOUNTPOINT
sda      8:0    0  100G  0 disk
├─sda1   8:1    0  953M  0 part /var/tmp
└─sda2   8:2    0 99.1G  0 part /
# cat /proc/mdstat
Personalities : [linear] [multipath] [raid0] [raid1] [raid6] [raid5] [raid4] [raid10]
unused devices: <none>
# mdadm --detail /dev/md0
mdadm: cannot open /dev/md0: No such file or directory
# mdadm --examine /dev/sda2
mdadm: No md superblock detected on /dev/sda2.
  • Avant de redémarrer, s’assurer de réinstaller grub afin de le faire pointer vers le bon UUID et d’éviter de tomber à nouveau en grub rescue :
# grub-install /dev/sda
  • Redémarrer à nouveau. Cette fois, ça devrait démarrer sans problème.
  • Prendre une douche pour se remettre de ses émotions 😌

Article précédent Article suivant