Mon NAS, depuis quelques années, c'est un serveur NetBSD 6.1/amd64. Pas un foudre de guerre, un petit Intel Core 2 muni de 4Gi de RAM, qui me sert également de machine centrale de développement. Cette machine est relativement « sûre », comprendre que le système d'exploitation et le volume de stockage sont tous deux sur des grappes en RAID1. Le volume système est muni de deux disques de 500Gi, et le stockage sur deux disques de 2Ti à faible coût. J'ai souhaité doubler la quantité de données que je pouvais sauvegarder sur le volume de stockage afin d'amener mon réseau local à utiliser de plus en plus des facilités de boot-on-nas et éliminer ainsi les pannes potentielles de disques uniques dans les machines de mon LAN.
1 RAIDframe
Mes machines d' « infrastructure perso » sont généralement sous NetBSD. À part l'affection particulière que je voue à l'ancestral UNIX Libre, c'est un système compact, fiable, sans surprises et respectant les standards de façon quasi religieuse. Les possibilités pour se construire un NAS performant articulé autour d'un système UNIX Libre sont multiples. Citons par exemple les capacités de GNU/Linux avec mdadm ou encore FreeNAS [2], solution dédiée et de niveau professionnel architecturée autour de FreeBSD et ZFS. Ici nous allons utiliser une fonctionnalité du noyau NetBSD intégrée il y a plus de 10 ans : RAIDframe [3].
RAIDFrame n'est pas un projet spécifique à NetBSD : initialement, il s'agit d'un logiciel de prototypage de structures RAID développé par le Parallel Data Laboratory à l'Université de Carnegie Mellon. L'objectif était de créer un simulateur de RAID pour un grand nombre d'architectures et un pilote pour Digital UNIX (Tru64) [4]. Ce dernier a été porté sous NetBSD par GregOster et fait partie des fonctions supportées par le noyau depuis les versions 1.4 (mai 1999 !).
Le driverRAIDframe supporte les niveaux de RAID suivants :
- RAID 0, ou striping, permettant d'agréger des disques entre eux et ainsi augmenter capacité et performances ;
- RAID 1, ou mirroring, dans lequel tous les disques contiennent les mêmes données, répliquées ;
- RAID 4, striping avec un disque dédié à la parité ;
- RAID 5, striping dans lequel la parité est répartie sur différents composants.
Le pilote est inclus dans le noyau par défaut depuis des années, on s'en assure grâce à la commande :
$ grep -i raidframe /var/run/dmesg.boot
Kernelized RAIDframe activated
L'outil permettant de manipuler ce driver est raidctl et fait partie du basesystem : inutile d'installer un quelconque paquet tiers.
2 Les équipes du RAID 1
2.1 Préparation de la grappe
Des 1001 scénarios imaginables dans la mise en place d'un système RAID, j'ai pris le parti de considérer une installation initiale mono-disque que l'on va transformer en système RAID. Il m'apparaît que c'est la probabilité la plus élevée, et elle nous fera manipuler plusieurs briques essentielles que vous pourriez être amené à rencontrer dans vos aventures NetBSDiennes.
En premier lieu, et considérant que les deux disques sont effectivement branchés, nous les identifions à l'aide de la séquence de démarrage suivante :
$ dmesg|grep ^wd
wd0 at atabus5 drive 0
wd0: <WDC WD5000AADS-00L4B1>
wd0: drive supports 16-sector PIO transfers, LBA48 addressing
wd0: 465 GB, 969021 cyl, 16 head, 63 sec, 512 bytes/sect x 976773168 sectors
wd0: 32-bit data port
wd0: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 6 (Ultra/133)
wd1 at atabus6 drive 0
wd1: <WDC WD5000AADS-00L4B1>
wd1: drive supports 16-sector PIO transfers, LBA48 addressing
wd1: 465 GB, 969021 cyl, 16 head, 63 sec, 512 bytes/sect x 976773168 sectors
wd1: 32-bit data port
wd1: drive supports PIO mode 4, DMA mode 2, Ultra-DMA mode 6 (Ultra/133)
Nos deux disques sont bien pris en charge par le noyau : il s'agit de deux disques SATA, identifiés par le nom du pilote wd et un numéro. S'il s'était agi de disques SCSI, ils auraient été détectés avec un identifiant sd[0-9].
Nous considérerons que le système d'exploitation est installé sur le premier disque (ce qui est très probablement le cas) wd0, et glanons quelques informations le concernant à l'aide de la commande fdisk :
# fdisk /dev/wd0
Disk: /dev/wd0d
NetBSD disklabel disk geometry:
cylinders: 969021, heads: 16, sectors/track: 63 (1008 sectors/cylinder)
total sectors: 976773168
BIOS disk geometry:
cylinders: 1024, heads: 81, sectors/track: 63 (5103 sectors/cylinder)
total sectors: 976773168
Partitions aligned to 5103 sector boundaries, offset 63
Partition table:
0: NetBSD (sysid 169)
start 63, size 976773105 (476940 MB, Cyls 0-191411/44/63), Active
1: <UNUSED>
2: <UNUSED>
3: <UNUSED>
Bootselector disabled.
First active partition: 0
Comme on peut le constater, NetBSD est installé sur la première partition du disque wd0 ; aussi, nous allons effacer tout contenu potentiel de la table de partitions du disque 2, wd1.
Comme rwd1d représente l'ensemble du disque en mode characterdevice, il faut exécuter :
# dd if=/dev/zero of=/dev/rwd1d bs=8k count=1
Puis créer et activer la même partition sur ce dernier :
# fdisk -0ua /dev/wd1
Les paramètres passés ici sont :
- 0 : nous allons agir sur la partition 0;
- u (update) : nous allons mettre à jour la partition indiquée ;
- a (activate) : nous « activons » la partition indiquée, si cela n'est pas fait notre système ne pourra pas démarrer.
Dès lors, les deux disques doivent être partitionnés de la même façon, on s'en assurera à l'aide de la même commande :
# fdisk /dev/wd1
Disk: /dev/wd1d
NetBSD disklabel disk geometry:
cylinders: 969021, heads: 16, sectors/track: 63 (1008 sectors/cylinder)
total sectors: 976773168
BIOS disk geometry:
cylinders: 1024, heads: 81, sectors/track: 63 (5103 sectors/cylinder)
total sectors: 976773168
Partitions aligned to 5103 sector boundaries, offset 63
Partition table:
0: NetBSD (sysid 169)
start 63, size 976773105 (476940 MB, Cyls 0-191411/44/63), Active
1: <UNUSED>
2: <UNUSED>
3: <UNUSED>
Bootselector disabled.
First active partition: 0
Reste maintenant à invoquer diskabel(8) afin de déclarer un volume RAID sur ce nouveau disque :
# disklabel -r -e -I wd1
# /dev/rwd1d:
type: ESDI
disk: WDC WD5000AADS-0
label: Disk1
flags:
bytes/sector: 512
sectors/track: 63
tracks/cylinder: 16
sectors/cylinder: 1008
cylinders: 969021
total sectors: 976773168
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0
16 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 976773105 63 RAID # (Cyl. 0*- 969020)
c: 976773105 63 unused 0 0 # (Cyl. 0*- 969020)
d: 976773168 0 unused 0 0 # (Cyl. 0 - 969020)
Les paramètres utilisés sont :
- -e qui fait apparaître un éditeur, celui spécifié dans la variable ${EDITOR} de votre environnement. Si aucun éditeur n'est spécifié, c'est le vénérable vi qui apparaîtra ;
- -r qui permet de manipuler le disque directement plutôt que de passer par des requêtes ioctl(2) ;
- -I implique que si l'on ne détecte pas de label, on utilisera celui par défaut, fourni par le noyau.
Après avoir quitté l'éditeur, les changements seront inscrits dans le label du disque. Notre secteur d'amorce étant maintenant prêt, nous allons pouvoir passer à la préparation du volume RAID à proprement parler. Cette dernière prend tout d'abord la forme d'un fichier de configuration qu'on nommera de façon arbitraire /var/tmp/raid0.conf. Le nôtre ressemble à ceci :
START array
1 2 0
START disks
absent
/dev/wd1a
START layout
128 1 1 1
START queue
fifo 100
Quelques explications s'imposent. Chaque section du fichier de configuration démarre par le mot clé START suivi du nom de la section. Dans la première section, array, on définit le nombre de lignes, colonnes, et disques de spare (rechange) dans l'agrégat. Ici, nous définissons une ligne munie de deux disques sans disque de rechange. C'est une configuration RAID 1 assez classique.
Dans la section suivante, on déclare les disques qui composeront notre grappe. Notez la subtilité : le premier disque est déclaré absent, c'est à cette place que viendra s'insérer le disque wd0 lorsque notre RAID sera fonctionnel et que nous pourrons définitivement migrer dessus.
La section layout est la plus complexe. La première valeur décrit (traduction libre du man raidctl) :
« le nombre de secteurs par unités de stripe (bande). Comprendre, le nombre de secteurs contigus sur lesquels ont peut écrire dans chaque membre du RAID pour un seul stripe. »
Vous avez rien compris, pas vrai ? :)
Au début, moi non plus. Et je me suis contenté de copier bêtement le raid0.conf jeté en pâture dans la documentation officielle. Seulement voilà, ce paramètre peut influer de façon dramatique sur les performances de votre grappe ; en ayant fait les frais, j'ai épluché minutieusement les multiples fils sur le sujet.
Revoyons la scène au ralenti : disklabel(8) nous informe qu'un secteur est composé de 512 octets (0.5 Kibioctet, donc). Une valeur de 128 suppose donc 64k pour un seul disque. Dans le cas présent, nous ciblons un système de mirroring, et cette valeur n'influera pas les performances, car aucun calcul de parité ne viendra ralentir la réplication des données. Cependant, lors de la mise en place d'un système articulé autour du standard RAID5, l'impact est tout autre ; en effet, un mauvais alignement du premier bloc ou un mauvais choix de taille de bloc lors de la création du système de fichiers impliqueraient un chevauchement des données sur plusieurs bandes et donc des recalculs de parité permanents.
Les deux valeurs suivantes, stripe units per parity unit et stripe units per reconstruction sont normalement toujours placées à 1. Enfin, le dernier paramètre, le moins abscons, définit le type de RAID que nous mettons en place, ici 1.
La dernière section de notre fichier de configuration décrit la méthode de file d'attente. Dans le cas présent, ainsi que dans tous les exemples qu'il m'a été donné de lire, la méthode est fifo avec une file d'attente limitée à 100 requêtes.
Munis de ces paramètres, nous allons pour la première fois invoquer raidctl(8) :
# raidctl -v -C /var/tmp/raid0.conf raid0
Cette commande configurera le périphérique raid0 avec la configuration précédemment écrite. Lorsqu'une nouvelle grappe est déclarée, il est nécessaire de lui fournir un numéro de série qui sera utilisé afin de savoir si un composant fait partie d'une grappe. On peut par exemple utiliser la date du jour :
# raidctl -v -I 20140301 raid0
Puis nous instruisons le périphérique qui doit s'auto-configurer au démarrage de la machine, sans présence de fichier raid[0-9].conf :
# raidctl -A yes raid0
Enfin, nous initialisons notre grappe :
# raidctl -v -i raid0
On peut à tout moment s'enquérir du statut des opérations ainsi que de l'état de notre grappe à l'aide de la commande suivante :
# raidctl -v -s raid0
2.2 Création du système de fichiers
Notre nouveau périphérique est désormais en ligne, et comme avec un disque physique, nous devons créer un label avec disklabel(8). Son partitionnement est évidemment à votre discrétion. Voici par exemple l'allure de mon système :
# disklabel raid0
# /dev/rraid0d:
type: RAID
disk: raid
label: fictitious
flags:
bytes/sector: 512
sectors/track: 128
tracks/cylinder: 8
sectors/cylinder: 1024
cylinders: 953879
total sectors: 976772992
rpm: 3600
interleave: 1
trackskew: 0
cylinderskew: 0
headswitch: 0 # microseconds
track-to-track seek: 0 # microseconds
drivedata: 0
16 partitions:
# size offset fstype [fsize bsize cpg/sgs]
a: 20971520 0 4.2BSD 0 0 0 # (Cyl. 0 - 20479)
b: 8388608 20971520 swap # (Cyl. 20480 - 28671)
d: 976772992 0 unused 0 0 # (Cyl. 0 - 953879*)
e: 104857600 29360128 4.2BSD 0 0 0 # (Cyl. 28672 - 131071)
f: 20971520 134217728 4.2BSD 0 0 0 # (Cyl. 131072 - 151551)
g: 821583744 155189248 4.2BSD 0 0 0 # (Cyl. 151552 - 953879*)
Ici :
- a: correspond à / et pèse 10GB ;
- b: est la partition de swap et pèse 4GB ;
- c: et d: sont réservés et ne peuvent être utilisés ;
- e: correspond à /usr et pèse 50GB ;
- f: correspond à /var et pèse 10GB ;
- g: correspond à /home et pèse 400GB.
Notez que les tailles, dans disklabel(8) sont spécifiées en bloc, ces derniers faisant 512 octets chacun, il faut multiplier par deux la valeur souhaitée. Par exemple, 10GB correspond à 10*2*1024*1024, soit 20 971 520 blocs.
Une fois le périphérique labellisé, on crée tout naturellement un système de fichiers en invoquant la commande newfs(8) :
# newfs -O 2 -b 8192 -f 1024 /dev/raid0a
# newfs -O 2 -b 8192 -f 1024 /dev/raid0e
# newfs -O 2 -b 8192 -f 1024 /dev/raid0f
# newfs -O 2 -b 8192 -f 1024 /dev/raid0g
# newfs -O 2 -b 8192 -f 1024 /dev/raid0h
Le système de fichiers choisi est FFSv2, avec une taille de bloc de 8k et une taille de fragment conseillée de 8:1, soit 1k.
Le premier disque de la grappe raid0 est prêt à être monté :
# mount /dev/raid0a /mnt
# mount /dev/raid0e /mnt/usr
# mount /dev/raid0f /mnt/var
# mount /dev/raid0g /mnt/home
Et l'on peut commencer à le peupler de données qu'il partagera bientôt de façon synchrone avec son voisin. Nous allons dans un premier temps synchroniser manuellement les données présentes sur le disque dans lequel est actuellement posé le système en cours d'utilisation vers le second disque que nous venons de configurer. J'utilise personnellement pour réaliser ce type de copie en masse le couteau suisse rsync, mais des logiciels comme pax(1) ou encore le couple dump(8) / restore(8) conviendraient tout à fait. On trouve d'ailleurs dans la littérature en ligne de nombreux exemples d'utilisation des outils en question dans le même contexte.
Le nom du périphérique ne sera plus le même, il est donc indispensable de modifier le fichier /etc/fstab afin d'y remplacer wd0 par raid0.
Afin d'éviter les erreurs de parité sur le périphérique RAID, nous faisons en sorte que le swap soit déconfiguré au moment de l'arrêt de la machine. Ceci est fait par une simple directive dans le fichier /etc/rc.conf :
# cat >> /etc/rc.conf << EOF
swapoff=YES
EOF
L'ultime étape à effectuer pour rendre notre premier disque système RAID parfaitement opérationnel est de l'affubler d'un secteur d'amorce, i.e. de rendre ce disque bootable. On réalise ceci à l'aide de la commande installboot(8) (oui, dans le monde BSD on aime bien les noms compliqués) :
# /usr/sbin/installboot -o timeout=30 -v /dev/rwd1a /usr/mdec/bootxx_ffsv2
Notez que la partition accueillant le noyau a bien été formatée en FFSv2, le système de fichiers par défaut depuis NetBSD6.
Le moment est venu de démarrer notre système sur le nouveau disque RAID. ATTENTION, ne redémarrez pas votre système RAID à l'aide de la commande reboot(8), : celle-ci n'appelle pas correctement les RC scripts. Préférez-lui la commande UNIX shutdown -r now.
Afin de démarrer sur le second disque RAID, il sera nécessaire de temporairement modifier l'ordre de boot dans votre BIOS/UEFI et de déclarer le disque numéro deux comme disque de boot.
2.3 L'ajout du second disque
Vous devez avoir démarré sur le second disque, et en particulier sur le périphérique RAID logiciel. On s'en assure à l'aide de la commande :
# grep -Ei 'raid|root' /var/run/dmesg.boot
raid0: RAID Level 1
raid0: Components: component0[**FAILED**] /dev/wd1a
raid0: Total Sectors: Total Sectors: 976772992 (476939 MB)
boot device: raid0
root on raid0a dumps on raid0b
root file system type: ffs
On peut constater que le composant 0 est marqué FAILED, ce qui est tout à fait normal, puisque pour le moment notre RAID 1 ne dispose que d'un seul disque. Nous allons remédier à cela immédiatement.
En premier lieu, il s'agit de relabelliser le disque numéro un avec strictement les mêmes informations que le disque deux. Ceci est très simplement fait par disklabel(8) :
# disklabel /dev/wd1 > disklabel.wd1
# disklabel -R -r /dev/wd0 disklabel.wd1
# disklabel /dev/wd0
Dans l'ordre :
- On exporte le fichier de label du disque #2.
- On l'inscrit directement dans le disque #1.
- On vérifie que les informations correspondent.
On ajoute alors le disque un dans le RAID set en tant que remplacement à chaud (hot spare) :
# raidctl -v -a /dev/wd0a raid0
Et on commande une reconstruction sur un hot spare disponible :
# raidctl -F component0 raid0
Cette dernière opération va prendre... plusieurs heures. Notez que votre système est parfaitement utilisable pendant cette période, mais plus vous y apporterez des modifications, plus la reconstruction sera longue !
Vous pouvez à tout moment vous enquérir de l'évolution de la reconstruction à l'aide de la commande suivante :
# raidctl -S raid0
Reconstruction is 0% complete.
Parity Re-write is 100% complete.
Copyback is 100% complete.
Reconstruction status:
14% |***** | ETA: 04:02 -
Lorsque la reconstruction est terminée, il sera judicieux d'installer également un secteur d'amorce sur le premier disque :
# /usr/sbin/installboot -o timeout=15 -v /dev/rwd0a /usr/mdec/bootxx_ffsv2
Et de remodifier l'ordre des périphériques de boot dans votre BIOS.
N'oubliez pas : pas de reboot ni de shutdown -r now !
Félicitations, votre système d'exploitation est maintenant (un peu plus) sécurisé à l'aide d'un RAID 1.
3 Et mes films de vacances qualité HD ?
Par souci de flexibilité, j'ai souhaité distinguer système et données, aussi ne vais-je pas transformer notre système RAID 1 en RAID 5. Cela, à l'aide de nos nouveaux disques, ne serait pas plus complexe que ce que nous avons mis en œuvre dans le paragraphe précédent.
Mon setup initial était composé de deux disques de 500Gi dédiés au système ainsi qu'à mon home directory, et de deux disques de 2Ti destinés à accueillir des médias (musique libre, films de vacances, documentations sous Creative Commons...) également configurés en mode RAID 1. Finalement, la qualité des caméras équipant les téléphones mobiles devenant incroyablement bonne, nos photos et autres panoramiques de plage occupent une place de plus en plus grande et nos 2Ti se remplissent bien plus vite que je ne le prévoyais. Aussi ai-je demandé à Noël non pas un, mais deux disques de même marque et de même taille afin de transformer mon simple volume média RAID 1 en RAID 5.
Afin d'assurer une certaine sécurité dans mon NAS, j'ai décidé de dédier trois disques aux données effectives et un hot spare, inutilisé donc, simplement présent en cas de défaillance de l'un de ses compères. Trois disques en RAID 5 cela nous donne 4Ti utiles. Cette taille nous posera un problème un peu plus tard, nous y reviendrons.
Le disque hot spare n'étant pas réellement utilisé, je m'en suis servi comme tampon. En effet, ce dernier a servi de stockage temporaire des données présentes sur la grappe média en RAID 1 le temps de sa transformation en RAID 5. Là encore, c'est le logiciel rsync qui m'a permis de faire l'aller-retour des données.
Une fois nos données transférées dans ce stockage tampon, nous pouvons procéder à la préparation de la nouvelle grappe.
De façon identique à notre précédente manipulation, nous écrasons un éventuel label précédent et créons un nouveau label sur les trois disques afin de les déclarer comme volumes RAID :
# dd if=/dev/zero of=/dev/rwd2d bs=8k count=1
# disklabel -r -e -I wd2
# # on remplace le type de système de fichiers 4.2BSD par RAID
# # on répète ces deux opérations pour tous les disques à inclure
Nous n'aurons pas besoin ici de déclarer de table de partitions sur les disques physiques puisque nous ne démarrerons jamais sur cette grappe destinée au stockage brut.
On poursuit la mise en place avec la création d'un fichier de configuration que nous appellerons par exemple raid1.conf :
START array
# numRow numCol numSpare
1 3 0
START disks
/dev/wd2a
/dev/wd3a
/dev/wd4a
START layout
# sectPerSU SUsPerParityUnit SUsPerReconUnit RAID_level_5
32 1 1 5
START queue
fifo 100
Notons quelques changements par rapport à notre précédente configuration :
- Cette fois nous disposons de trois disques, déclarés comme trois colonnes.
- Les trois disques sont décrits dans la section disks.
- Le layout précise qu'il s'agit de RAID 5 et on notera avec attention la valeur de la fameuse variable sectPerSU. Pour cette dernière valeur, il est important de comprendre que le calcul est le suivant : 32+32+0. Soit deux fois 32 secteurs : un par disque contenant de la donnée d'une bande puisque le troisième, pour la même bande, contiendra uniquement les informations de parité. Finalement, ce sont 64 secteurs, donc 32k, qui seront occupés.
Notez que la valeur du paramètre sectPerSu n'est pas une vérité absolue, il est de bon aloi de réaliser quelques tests de performance avant de graver cette valeur dans le marbre. Il est cependant globalement établi que pour un stockage RAID 5 composé de 3 disques, une valeur de 32 ou 64 est généralement conseillée.
De façon tout à fait similaire au disque système, nous créons la nouvelle grappe :
# raidctl -v -C /var/tmp/raid1.conf raid1
# raidctl -v -I 20140306 raid1
# raidctl -A yes raid1
# raidctl -v -i raid1
Il est temps de créer la table de partitions du périphérique RAID. Un périphérique d'un fort beau gabarit, puisque ce dernier pèse 4Ti, donc plus de 2Ti. Et il se passe quoi à plus de 2Ti ? Il se passe que disklabel(8), tout comme l'ancestral fdisk sont impuissants, bridés qu'ils sont par la limitation introduite par IBM en 1981 pour qui dépasser des unités de stockage de 2Ti paraissait inconcevable. Il existe bien heureusement un outil permettant de contourner cette limitation et utiliser une norme plus récente, GPT [5], qui repousse les possibilités de stockage à 9.4Zi. Faites pas les malins, on y arrivera tôt ou tard.
L'outil en question se nomme - attention on a fait fort - gpt(8). Oui je sais ça fait beaucoup de commandes aux noms très compliqués à retenir.
Son utilisation est relativement triviale. On crée une table de partitions vide :
# gpt create raid1
Et on ajoute une partition qui commence au secteur qui suit le flag -b, comme vous l'aurez deviné, la valeur qui suit ce flag est le premier secteur de la partition, dont nous souhaitons évidemment qu'elle démarre sur un multiple de notre fameux sectPerSU, soit 128 :
# gpt add -b 128 raid1
La sortie de gpt(8) vous indiquera la taille de la partition. Copiez-la. Ici, elle vaut 7814058015.
Afin de nommer et typer notre partition de stockage, nous utilisons le programme dkctl(8) et créons un wedge (traduction anglaise de morceau) :
# dkctl raid1 addwedge export 128 7814058015 ffs
Ici on spécifie le nom du périphérique, l'action à y mener, le bloc de démarrage, le nombre de blocs et le type de partition.
Pour rendre ce nouveau média utilisable, on l'affuble d'un système de fichiers dont on s'assure que la taille de blocs correspond à la valeur sectPerSu définie dans le fichier raid1.conf, soient 64 secteurs fois 512 octets :
# newfs -O2 -b32k -I dk0
Nous pouvons alors tenter de monter cette nouvelle grappe :
# mkdir /export
# mount /dev/dk0 /export
Et si tout se passe correctement, l'ajouter à votre fichier /etc/fstab avec quelques options bien senties :
/dev/dk0 /export ffs rw,log,noatime 0 0
Attention : ne jamais cumuler l'option log (journalisation) avec l'option async, les deux sont parfaitement antagonistes et leur juxtaposition pourrait simplement amener à un état totalement instable de votre système de fichiers.
Un shutdown -r now plus loin, votre monstre à données est fin prêt à accueillir un nombre de bits difficile à concevoir.
4 « Et là, c'est moi à la plage »
Quatre téraoctets sous le coude, il va en falloir des documents à forte teneur multimédia pour en venir à bout. Et justement, comment allons-nous mettre cette débauche d'inodes à disposition de notre réseau local ? Plusieurs options s'offrent à nous, toutes bien évidemment supportées par NetBSD depuis des lustres :
- Présenter un fichier brut comme périphérique de type bloc au réseau via iSCSI [6], en mode SAN donc ;
- Exposer un ou plusieurs répertoires en CIFS/SMB [7] via Samba [8], en mode NAS ;
- Exposer un ou plusieurs répertoires via NFS [9], également en mode NAS.
Pour la première option, une longue prose est inutile, la mise en place d'une cible iSCSI sous NetBSD est triviale. On renseigne le fichier /etc/iscsi/targets de cette façon :
# extent file or device start length
extent0 /export/iscsi/target0 0 1000MB
# target flags storage netmask
target0 rw extent0 192.168.1.0/24
On active le service dans le fichier /etc/rc.conf :
# echo "iscsi_target=YES" >> /etc/rc.conf
Et on démarre le service :
$ sudo /etc/rc.d/iscsi_target start
Starting iscsi_target.
Reading configuration from `/etc/iscsi/targets'
target0:rw:192.168.1.0/24
extent0:/export/iscsi/target0:0:1048576000
DISK: 1 logical unit (2048000 blocks, 512 bytes/block), type iscsi fs
DISK: LUN 0: 1000 MB disk storage for "target0"
TARGET: iSCSI Qualified Name (IQN) is iqn.1994-04.org.netbsd.iscsi-target
Le « disque » est créé automatiquement, on vérifie la disponibilité du disque distant, par exemple sur un poste GNU/Linux, en ayant préalablement installé le paquet open-iscsi et démarré le service /etc/init.d/open-iscsi :
imil@tatooine:~$ sudo iscsiadm -m discovery -t sendtargets -p 192.168.1.2:3260
192.168.1.2:3260,1 iqn.1994-04.org.netbsd.iscsi-target:target0
On ouvre alors une session sur la cible :
imil@tatooine:~$ sudo iscsiadm -m node --targetname "iqn.1994-04.org.netbsd.iscsi-target:target0" --portal 192.168.1.2 --login
Logging in to [iface: default, target: iqn.1994-04.org.netbsd.iscsi-target:target0, portal: 192.168.1.2,3260] (multiple)
Login to [iface: default, target: iqn.1994-04.org.netbsd.iscsi-target:target0, portal: 192.168.1.2,3260] successful.
Ce qui provoquera l'apparition d'un nouveau périphérique de type bloc :
Mar 8 20:50:30 coruscant iscsi-target: > iSCSI Discovery login successful from iqn.1993-08.org.debian:01:9137d4d18f9d on 192.168.1.1 disk -1, ISID 9613344768, TSIH 8
Mar 8 20:54:11 coruscant iscsi-target: > iSCSI Normal login successful from iqn.1993-08.org.debian:01:9137d4d18f9d on 192.168.1.1 disk 0, ISID 9613410304, TSIH 9
Mar 8 20:56:42 tatooine kernel: [4862352.226463] scsi78 : iSCSI Initiator over TCP/IP
Mar 8 20:56:42 tatooine kernel: [4862352.480458] scsi 78:0:0:0: Direct-Access NetBSD NetBSD iSCSI 0 PQ: 0 ANSI: 3
Mar 8 20:56:42 tatooine kernel: [4862352.480604] sd 78:0:0:0: Attached scsi generic sg5 type 0
Mar 8 20:56:42 tatooine kernel: [4862352.481600] sd 78:0:0:0: [sdf] 2048000 512-byte logical blocks: (1048 MB/1000 MiB)
Mar 8 20:56:42 tatooine kernel: [4862352.481957] sd 78:0:0:0: [sdf] Write Protect is off
Mar 8 20:56:42 tatooine kernel: [4862352.486505] sdf: unknown partition table
Mar 8 20:56:42 tatooine kernel: [4862352.488948] sd 78:0:0:0: [sdf] Attached SCSI disk
Ce dernier est alors manipulable de la même façon qu'un classique disque physiquement attaché à votre station. Il est ici identifié comme /dev/sdf et automatiquement logiquement lié à : /dev/disk/by-path/ip-192.168.1.2:3260-iscsi-iqn.1994-04.org.netbsd.iscsi-target:target0-lun-0. Il faudra, pour utiliser ce disque SCSI en réseau, le manipuler avec les outils habituels : fdisk et mkfs.<système de fichiers>.
La seconde option de partage consiste en la mise en place du mode NAS/CIFS. Elle se traduit par l'installation du paquet samba sur la machine de stockage. On ajoute naturellement les directives de démarrage automatique du service dans le fichier /etc/rc.conf :
# cat >> /etc/rc.conf << EOF
smbd=YES
nmbd=YES
EOF
Puis on démarre le serveur Samba ainsi que le serveur de noms NetBIOS :
# /etc/rc.d/nmbd
# /etc/rc.d/smbd
Le logiciel étant livré avec l'interface SWAT, la création des partages peut se faire aisément en se connectant sur le port 901 de votre serveur de stockage à l'aide d'un navigateur quelconque comme le montre la figure 2.
Fig. 2: Interface Web SWAT
Le fichier de configuration produit par l'interface Web pour la déclaration basique d'un partage non protégé est le suivant (fichier /usr/pkg/etc/samba/smb.conf) :
# Samba config file created using SWAT
# from UNKNOWN (192.168.1.1)
# Date: 2013/02/24 00:24:29
[global]
workgroup = EMPIRE
realm = CORUSCANT.HOME.IMIL.NET
server string = Samba %v (%h)
idmap config * : range =
idmap config * : backend = tdb
[homes]
comment = Home Directories
read only = No
browseable = No
[media]
comment = Media files
path = /export/imil/media
guest ok = Yes
locking = No
On peut s'assurer du bon fonctionnement du partage à l'aide de la commande smbclient exécutée sur un poste quelconque du réseau :
imil@tatooine:~$ smbclient //coruscant/media
Anonymous login successful
Domain=[EMPIRE] OS=[Unix] Server=[Samba 3.6.22]
smb: \> pwd
Current directory is \\coruscant\media\
Attention, il s'agit ici d'une configuration très épurée, sans authentification. Il sera souhaitable de placer au minimum quelques listes d'accès relatives à votre réseau local.
Enfin, mon choix de prédilection (c'est la méthode que j'utilise à profusion sur mon réseau), la troisième option consiste à exposer des points de montage NFS. NetBSD dispose dans son noyau GENERIC ainsi que dans son système de base de tous les outils nécessaires à le transformer en serveur de fichiers NFS : aucun paquet particulier à installer, il suffit comme à l'accoutumée de démarrer les bons services et de les configurer correctement. Ici, nous aurons besoin des démons rpcbind, mountd, nfsd, lockd et statd. On commande l'exécution automatique de ces serveurs au démarrage en ajoutant ceci au fichier /etc/rc.conf :
# cat >> /etc/rc.conf << EOF
rpcbind=YES
mountd=YES
nfs_server=YES
lockd=YES
statd=YES
EOF
On configure les points de montage à exposer, par exemple dans mon cas :
# j'exporte pkgsrc ainsi que les sources du système sur le réseau
/usr/pkgsrc -maproot=root:wheel -network 192.168.1.0/24
/usr/src -maproot=root:wheel -network 192.168.1.0/24
# je rend accessible en lecture seule les backups réguliers de mes machines
/home/backup -alldirs -ro -mapall=nobody -network 192.168.1.0/24
# j'exporte mon home directory pour ma station de travail
/home/imil tatooine
# et enfin, l'ensemble du volume RAID 5 contenant mes photos de vacances.
# L'option "-noresvport" est là pour satisfaire l'osx de ma femme qui
# bloque lamentablement les transactions NFS lorsqu'on lui demande de
# faire parvenir ses requêtes RPC depuis des ports réservés, ce qui
# devrait être son comportement normal...
/export -alldirs -noresvport -maproot=root:wheel -network 192.168.1.0/24
Reste à démarrer les démons déclarés précédemment :
# /etc/rc.d/rpcbind start
# /etc/rc.d/mountd start
# /etc/rc.d/nfsd start
# /etc/rc.d/nfslocking start
Et de s'assurer que les exports NFS sont bien accessibles depuis le réseau :
imil@tatooine:~$ showmount -e coruscant
Export list for coruscant:
/export 192.168.1.0
/home/imil tatooine.home.imil.net
/home/backup 192.168.1.0
/usr/pkgsrc 192.168.1.0
/usr/src 192.168.1.0
Toujours côté client, j'ai opté, sur mes machines GNU/Linux, pour le très pratique autofs qui me permet de monter les exports NFS à la volée, la configuration se traduit ainsi :
imil@tatooine:~$ cat /etc/auto.master
/net /etc/auto.net
Après avoir redémarré le service autofs, on dispose sans plus de précautions de nos exports NFS dans le répertoire /net :
imil@tatooine:~$ ls /net/coruscant
export home usr
imil@tatooine:~$ ls /net/coruscant/export
imil iscsi netboot
Bien. Il est l'heure de vider les sdcard de nos mobiles.
5 Et pour quelques kilos de plus
Comme je l'annonçais au début de cet article, le stockage de masse n'était pas l'unique finalité de cette orgie de disques. En effet, ayant récemment migré mon réseau 100BaseT en réseau Gigabit, je nourrissais l'envie de me passer de disques locaux dans les machines de mon réseau domestique. Disposant désormais de toute la place et des protocoles nécessaires pour accueillir différents systèmes sur un montage NFS, il ne manque plus pour réaliser ce fantasme que d'un simple serveur DHCP/PXE qui indiquera aux machines leur adresse IP, leur fournira un noyau ainsi qu'un rootfilesystem. J'utilise pour cela le minuscule, mais très puissant Dnsmasq [10]. On installe le logiciel sur le NAS à l'aide de pkgin :
# pkgin in dnsmasq
Et l'on produit un fichier de configuration de quelques lignes :
interface=re1
dhcp-ignore=tag:!known
dhcp-range=192.168.1.1,192.168.1.254,255.255.255.0,1h
dhcp-host=00:0a:22:Ce:13:A2,krayt,192.168.1.200,set:netbsd32
dhcp-host=00:21:16:ee:56:a0,openbox,192.168.1.201,set:openbox
dhcp-boot=tag:netbsd32,pxelinux.0
dhcp-boot=tag:openbox,NB6-MAIN-R3.3.4-OPEN
dhcp-option=tag:netbsd32,17,/export/netboot/krayt/root
enable-tftp
tftp-root=/tftpboot
Dans cet exemple, je fais démarrer deux machines via PXE/NFS, j'ignore les machines inconnues de la configuration grâce à la directive dhcp-ignore=tag:!known pour laisser le réel serveur DHCP de mon réseau prendre le relais. Je donne un tag aux machines connues, ici une station qui démarre NetBSD en 32 bits et une NeufBoite dont j'ai fait l'acquisition à des fins de bidouillage. C'est grâce à ce tag que nous choisirons l'amorce de nos machines diskless. Enfin, toujours grâce à l'identification par tag, nous passons l'option 17 (root path) qui indiquera à la station krayt où se situe la racine de son système de fichiers à monter en NFS.
Bien évidemment, on peut ici déclarer tout type de système sans disque. Il faudra malgré tout garder à l'esprit que les transferts seront limités à la capacité de la carte réseau ainsi que des équipements connectés, capacité qu'il est possible de décupler si le commutateur sur lequel sont branchées les machines supporte le protocole LACP (802.3ad) [11] permettant, entre autres, l'agrégation de plusieurs liens physiques en un lien logique.
6 La solution du pauvre ? plutôt celle de l'ourson malin
J'ai récemment été confronté à une panne disque : ce dernier était branché sur un contrôleur RAID matériel, le constructeur importe peu, mais j'ai lutté pendant plusieurs heures pour juste comprendre qu'un disque était simplement défectueux. En effet, il est regrettable de constater qu'encore aujourd'hui, les outils fournis par les constructeurs sont au mieux des binaires propriétaires qu'il faut aller chercher au fin fond d'un lien obscur dans la section « support » cachée derrière 28 formulaires, et au pire inexistants pour votre système. Je ne parlerai que très succinctement de la convivialité des outils en question, jugez plutôt :
# MegaCli64 -PDList -aALL
Cette commande affiche les informations concernant la santé des disques physiques branchés au contrôleur dont vous devinerez le nom. Intuitif, hein.
Trêve de bave inutile, un tweet que je recevais récemment résume bien la situation : « @iMilnb après avoir lu ça et les 1001 pbs des contrôleurs RAID, autant passer au software raid ... »
Oui, très clairement, car au vu de l'évolution des pilotes RAID logiciels, des capacités de branchement à chaud du matériel récent et de la puissance disponible dans une machine de bureau basique, les différenciateurs qui favorisaient le RAIDhardware ne semblent plus vraiment d'actualité.
D'ailleurs, précisons que le setup que nous venons de balayer n'est pas exactement original puisque la société Wasabi systems [12] fournit des SAN/NAS professionnels articulés autour du système NetBSD, lequel doit justement son système de journalisation à la société Wasabi, employeur d'un certain nombre de développeurs officiels du Projet.
Sur ce, joyeux backups ;)
Références
[1] Définition de NAS : http://fr.wikipedia.org/wiki/Serveur_de_stockage_en_r%C3%A9seau
[2] FreeNAS : http://www.freenas.org/
[3] RAIDFrame : http://www.pdl.cmu.edu/RAIDframe/
[4] Digital UNIX : http://en.wikipedia.org/wiki/Tru64_UNIX#Digital_UNIX
[5] GUID Partition Table : http://fr.wikipedia.org/wiki/GUID_Partition_Table
[6] iSCSI : http://fr.wikipedia.org/wiki/ISCSI
[7] Server Message Block : http://fr.wikipedia.org/wiki/Server_Message_Block
[8] Samba : http://fr.wikipedia.org/wiki/Samba_%28informatique%29
[9] Network File System : http://fr.wikipedia.org/wiki/Network_File_System
[10] Dnsmasq : http://dnsmasq.org/
[11] IEEE 802.3ad : http://fr.wikipedia.org/wiki/IEEE_802.3ad
[12] Wasabi Systems : http://wasabisystems.com/