Chronique d'une greffe un tantinet précipitée | Chronicle of a slightly rushed disk graft
Le second disque du poivron étant rayé, nous nous sommes empressés de le changer comme annoncé [1]. Quelques heures d'autostop la nuit tombée, une traversée de Paris en métro, un contrôle de ticket tout juste évité, et nous voilà face au placard dans lequel le poivron est enfermé, ronronnant jour et nuit au milieu des câbles, switches, et des quelques autres machines qui lui tiennent compagnie.
Dernier avertissement sur IRC [2], `wall` à l'intention des dernier·e·s utilisateurs/trices connecté·e·s, extinction progressive des serveurs virtuels, puis du poivron tout entier. Nous extirpons alors la machine de son abri, et en profitons pour la dépoussiérer. Le disque dur fautif est retiré, et son successeur installé. Remise sur rails 10 minutes plus tard, câbles rebranchés, et ré-initialisation du potager.
Première mauvaise surprise: le système se refuse à démarrer. Explication: depuis le changement de disque précédent, le système était amorcé sur le second disque dur, sur lequel 'grub' était installé. Or, il s'agit précisément du disque que nous venons de retirer; l'autre disque contenant nos données ne dispose pas de "boot loader" [3] dans son secteur d'amorçage, ni, bien entendu, le disque vierge que nous venons d'insérer...
Il nous faut alors démarrer le système depuis une autre source que le disque dur, pour pouvoir y installer le "boot loader" désiré. Deux options s'offrent à nous: une image d'installation de Debian sur clef USB (c'est ainsi que nous avions installé le poivron, qui n'a pas de lecteur CD), ou, plus rapide et plus sexy, un "netboot" (démarrage par réseau, les fichiers nécessaires au système se trouvant sur une machine connectée à proximité). Par chance, l'un des voisins du poivron se trouve être un serveur de boot Debian, dont la fonction est justement de distribuer et exécuter un système fonctionnel par le réseau. Un tour par le BIOS pour activer le mode PXE des cartes réseau, puis définir ces interfaces comme média de démarrage prioritaire, et nous voyons défiler devant nous les premières lignes d'initialisation du système, en provenance directe d'une machine située ailleurs dans le bâtiment!
À partir de ce système d'emprunt, nous pouvons piloter les périphériques du poivron. Nous pouvons donc accéder à son premier disque, contenant ses programmes et ses données, et en faire la racine de notre système, simulant ainsi un véritable démarrage à partir de celui-ci:
# montons d'abord la partition racine..
mount -o ro /dev/sda1 /target
# ..et faisons de celle-ci notre racine actuelle
chroot /target
Pour continuer, nous avons également besoin de monter la partition '/usr' contenant les programmes. Note: nos disques étant configurés en RAID-1 (j'y reviendrai), toutes les partitions sont montées en "lecture-seule" ('-o ro'), pour ne pas risquer d'en corrompre les données. C'est que nous aurions du utiliser les volumes RAID ('/dev/md*') comme point d'accès, mais le support du RAID se trouvant absent du noyau distant que nous utilisons, il nous a fallu bidouiller :)
mount -o ro /dev/sda5 /usr
Au passage, un proc pour empêcher certains programmes de gueuler:
mount -t procfs /proc
...et nous pouvons alors réparer notre disque flanqué d'un secteur d'amorçage vide. Lançons ensuite un shell grub, et dialoguons avec ce dernier. Il s'agit de dire à grub quel disque utiliser, quelle est la partition racine sur laquelle démarrer, et d'y installer sa configuration, construire à partir du fichier '/boot/grub/menu.lst' (que nous n'avons pas à toucher dans le cas présent, puisque nous souhaitons seulement réactiver notre configuration d'avant):
grub
grub: device (hd0) /dev/sda
grub: root (hd0,0)
grub: setup (hd0)
grub: quit
Là où cette astuce devient géniale, c'est qu'elle permet d'écrire un secteur d'amorçage sur n'importe quel disque, en faisant passer le périphérique de son choix ('/dev/sda' dans notre cas, mais cela peut être n'importe quoi) pour le premier disque ('hd0'), et d'y installer un "boot-loader" fonctionnel. Pour que notre mauvaise surprise ne puisse se reproduire, nous nous empresserons de renouveler l'opération sur notre second disque, '/dev/sdb', une fois celui-ci repartionné. De la sorte, nous pourrons démarrer invariablement sur le disque de notre choix, si l'un d'eux venait à s'éteindre une nouvelle fois.
Un mot de rappel sur la configuration du poivron, et la distribution de ses données. Pour garantir leur intégrité, et prévenir toute perte inopinée (au hasard, en cas de décès d'un disque dur, comme cela nous est arrivé deux fois en une année ;P), nos deux disques sont réunis en un volume de type RAID-1 [4]. Cela signifie que nous n'utilisons qu'une moitié de notre capacité de stockage totale (sur 160go, seuls 80 nous sont accessibles), chaque disque contenant une copie intégrale du système. En cas de défaillance de l'un des disques, l'autre assure donc la continuité des services, et aucune donnée n'est perdue (à moins d'une mort subite des deux disques au même moment, ce qui, espérons-le, n'arrive pas trop souvent!). Le RAID suppose généralement l'acquisition d'une carte spécifique, souvent onéreuse. GNU/Linux offre cependant la possibilité de faire du "Software RAID", un pilote du noyau prenant alors l'affaire en charge, sans matériel spécifique, au prix d'un peu de mémoire et de quelques cycles processeur.
Avant de lancer la reconstruction du RAID-1 (réplication des données d'un disque sur l'autre, ni plus ni moins), il nous faut cependant partitionner [5] le nouveau disque (dans notre cas, '/dev/sdb'), selon un schéma analogue au disque "maître" (ici, '/dev/sda/'). Pour ce faire, nous utilisons l'outil 'sfdisk'. Il nous suffit alors d'extraire la table de partitions du disque maître, et de la donner en entrée à sfdisk pour qu'il l'écrive sur le second disque.
sfdisk --dump /dev/sda | sfdisk /dev/sdb
Ceci fait, nous relancer le poivron, et démarrer le système à partir du disque maître, désormais muni d'un 'grub' opérationnel. Nous avons donc un disque contenant toutes les données, et un disque vierge, prêt à les réceptionner, tous deux semblablement partitionnés, et réunis au sein d'un RAID-1. Affichons d'abord la liste des partitions liées en RAID:
cat /proc/mdstat
Et lançons, pour chacune d'entre elles, la reconstruction:
mdadm --manage /dev/md0 --add /dev/sdb1
mdadm --manage /dev/md1 --add /dev/sdb2
...
...où '/dev/md0' regroupe '/dev/sda1' et '/dev/sdb1' (varie selon chaque configuration).
Un à un, les ensembles RAID sont reconstruits, le système, sans être interrompu pour autant, tournant un peu au ralenti, pendant quelques dizaines de minutes, le temps que les transferts soient finis.
Nous relançons les serveurs virtuels, remontons ce qu'il faut, et voilà. L'interruption de service est certes passée de 10 minutes à plus d'une heure. mais vous savez désormais pourquoi, et comment éviter pareil désagrément, sur un serveur distant comme chez soi! Sans oublier, moralité, que si personne n'a perdu de données malgré deux disques décédés, c'est que le RAID-1... c'est bien!
Sur ce, à la prochaine!
Notes:
[1] voir notre brève précédente.
[2] canal #poivron sur irc.indymedia.org (connexion sécurisée SSL sur le port 994).
[3] un "boot loader", ou "gestionnaire d'amorçage", est un petit programme qui s'installe dans le MBR (Master Boot Record), espace réservé en début de disque, dans lequel l'ordinateur lit ses instructions de démarrage à l'initialisation. L'installation d'un "boot loader" (tel que 'grub' ou 'lilo') permet notamment de choisir entre divers systèmes d'exploitation au démarrage, si le disque dur dispose de plusieurs systèmes ('GNU/Linux', 'Windows', 'OpenBSD', etc.) se trouvant sur des partitions séparées. Sous 'GNU/Linux', l'installation d'un "boot loader" est nécessaire, pour choisir le noyau Linux que le système va utiliser.
[4] voir ces extraits du "Software RAID HOWTO for Linux". Le document original, en anglais, se trouve là. Une traduction française, mais fort datée, est disponible ici.
[5] partitionner un disque dur, c'est le compartimenter, et créer des cloisons étanches entre divers blocs de données. Cela permet notamment d'installer divers systèmes d'exploitation sur un même disque, ou, sous GNU/Linux, de faire en sorte que la corruption ou la perte d'une partie des contenus soit circonscrite, et n'affecte pas l'entièreté du disque, ou d'appliquer une configuration spécifique (en termes de permissions, par exemple) à une portion du système de fichiers. Sur un serveur sous GNU/Linux, il est coutume de créer des partitions séparées pour '/', '/usr', '/home', '/var', '/tmp', et parfois plus.
With the digital pepper bearing a disabled hard-disk, we quickly proceeded in replacing it, as previously announced [1]. After a few hours of nightly hitch-hiking, an underground ride through Paris and a roughly avoided ticket check, we meet again with the closet in which poivron.org's locked up. Here it is, roaring night and day in between cables, switches, and a few other machines it stays together with.
A last warning is issued on IRC [2], and a `wall` is sent towards the few remaining online users, as virtual servers are being shut down one by one, soon to be followed by the server as a whole. We extract the machine out of its shelter, and take the occasion to proceed with a cleaning session, sweeping dust out of its disks, RAMs and fans. The faulty disk-drive is removed, and its successor is connected. Ten minutes later, cables are plugged back in, ready for the kitchen-garden booting.
Here comes a first bad surprise, when the system refuses to start! Here's the explanation: since the last disk-change, poivron.org was booted off the second hard-disk, onto which 'grub' had been installed. This happens to be the precise disk we've just removed, while the other disk that is filled with our data doesn't have a "boot loader" [3], nor does the new blank disk we inserted seconds ago.
We must boot the system off another source than the hard-disks, in order to setup the required "boot-loader". We are prompted with two options: using a USB-key Debian installation image (thanks to which we initially installed poivron.org, since the machine doesn't carry a CD drive), or using "netboot" (booting over the network, with required system files being downloaded from a nearby machine), which looks like the quickest and sexiest approach by far. By chance, one of the pepper's neighbours happens to be a Debian boot-server, dedicated to spreading and executing a functional system over the local network. We head towards the BIOS to turn PXE mode on for our network cards, then define those as primary boot devices, and eventually end up watching the machine start off a system coming straight from another computer, located somewhere in the basement!
From this borrowed system, we get to control the pepper's peripherals. Thus we can access its first hard-disk, which contains all programs and data, and, furthermore, make it the root of our running system, in order to emulate a true local system start-up.
# let's first mount the root partition..
mount -o ro /dev/sda1 /target
# ..and make it our current root
chroot /target
We need to mount the '/usr' partition next, which contains most program binaries. Note: since our disks are set to use RAID-1 (to be explained more thoroughly later), all our partitions are mounted in "read-only mode" ('-o ro'), to prevent any data corruption. Normally, we should have used RAID volumes ('/dev/md*') as mount sources, but we found ourselves using a kernel that lacked RAID support, and consequently had to walk around that constraint :)
mount -o ro /dev/sda5 /usr
Let's also mount a proc file-system to prevent some programs from yelling at us:
mount -t procfs /proc
We can now fix that disk which boot sector is empty, by talking together with a grub shell. This is all about telling grub which disk to use, and which partition the root file-system lays on, for it to be booted, and for grub to place its configuration in it, built upon '/boot/grub/menu.lst' (which we presently don't have to tamper with, since we're just re-enabling a previously configured setup).
grub
grub: device (hd0) /dev/sda
grub: root (hd0,0)
grub: setup (hd0)
grub: quit
This becomes a pretty amazing tip, when it comes to setting up a working boot sector on whichever disk you want. It's just a matter of defining the disk of your choice ('/dev/sda' for us here, but it could be any other) as the primary disk ('hd0'), and then install the "boot-loader" on top of it. To prevent any such bad surprise as ours in the future, we will quickly apply the same technique to our freshly inserted disk, after it has been partitioned. This way, we will be able to boot from the disk of our choice, in case one of them would die one more time.
Here's a quick reminder on the pepper's disk configuration and data distribution. To grant data redundancy, and thus prevent data loss (in case of a disk crash, like it happened to us twice in a year ;P), our two hard-disks are bound together, within a RAID-1 volume [4]. This means we are using half of our total storage space (80 gigs out of 160), since each disk carries an entire copy of the system. In case one of them fails, the other disk ensures that services are continued, and that no data is being lost (except if both disks die, which, hopefully, should not happen too often!). RAID generally implies acquiring a dedicated hardware device, which is often pretty expensive. With GNU/Linux, though, it is possible to run "Software RAID", thanks to a kernel driver taking care of the whole business. No need for costly hardware, then, but a bit of memory and a few processor cycles to spare.
Before launching the reconstruction of RAID arrays (which basically means, in case of RAID-1, replication of data from one disk to the other), we need to partition [5] the new disk ('/dev/sdb' for us) in a similar fashion as the "master disk" ('/dev/sda' here). To do this, we will use 'sfdisk'. This is as simple as one one command, which will extract the master disk's partition table, and dump it towards sfdisk's input, for it to write on the second disk:
sfdisk --dump /dev/sda | sfdisk /dev/sdb
This being done, we restart the pepper, and boot the system off its first hard-disk, which now has a functional 'grub' boot-loader. Here we are, with one disk holding all data on one side, and a blank disk on the other, ready to receive a copy. Both share the same partition scheme, and stand together within a RAID-1 setup. Let's first list RAID partitions:
cat /proc/mdstat
Then, for each of them, let's start the reconstruction process:
mdadm --manage /dev/md0 --add /dev/sdb1
mdadm --manage /dev/md1 --add /dev/sdb2
...
...where '/dev/md0' brings '/dev/sda1' and '/dev/sdb1' together (which may vary with each configuration, of course).
One by one, RAID arrays are being rebuilt, while the whole system keeps running, though a tat slowly until transfers are over and RAID is fully ready. It's just a matter of a few 10 minutes, really.
We start virtual servers again, remount what needs to be so, and that's it. The downtime did expand from ten minutes to more than an hour, but at least, you now know why, and how to avoid a similar worry, be it at home or remotely. Not to forget the reason why nobody lost data, in spite of two disks brought to the cemetery: RAID-1 rocks, buddy!
Til next time, cheers!
Notes:
[1] see our previous post.
[2] join the #poivron channel on irc.indymedia.org (secure SSL connexion available on port 994).
[3] a "boot loader" is a tiny program that lies in the MBR (Master Boot Record), a preserved space at the beginning of every disk, in which the computer reads its boot instructions upon initialisation. Installing a "boot loader" (like 'grub' or 'lilo') allows the user to choose between various operating systems upon system start-up, in case the hard-disk is setup with more than one system (that can be 'GNU/Linux', 'Windows', 'OpenBSD', etc.) on separate partitions. With 'GNU/Linux', though, it is compulsory to have a "boot-loader", to choose which Linux kernel the system will use.
[4] see the Software RAID HOWTO.
[5] partitioning a hard-disk is about splitting it in independent parts. This makes it possible to install several operating-systems on the same disk, among other things. With 'GNU/Linux', this can prevent data corruption from expending to the disk as a whole, and allows to setup a particular configuration (with specific permissions, for instance) on certain areas of the file-system. On a 'GNU/Linux' server, it is common practice to create partitions for '/', '/usr', '/home', '/var', '/tmp', and sometimes more.
Par darkveggy:: Jeudi 13 Octobre 2005 à 21:52:: Général :: #22 :: rss
Trackbacks
Aucun trackback.
Pour faire un tracback sur ce billet : http://poivron.org/blog/tb.php?id=22
Commentaires
Le Samedi 15 Octobre 2005 à 11:27, par arthur :: #
Ajouter un commentaire