Dans un article de février 2008 j'avais testé nbd et en décembre 2008 j'avais testé glusterfs. Ce dernier permettait de monter des ressources réseaux de différentes manières (via fuse) et se comportait un peu comme du raid en réseau. Redhat a de son côté développé gnbd (GFS's Network Block Device) et il est disponible sur debian.

Un man de gnbd nous apprend que:

The  GFS  Network Block Device has two parts, the client (which includes the gnbd.ko module and  gnbd_import, gnbd_recvd, and
       gnbd_monitor programs) and the server (which include the gnbd_serv,  gnbd_clusterd,  and  gnbd_export  programs).   The  GNBD
       server  allows  a  computer  to  export multiple block devices or files (GNBDs).  The GNBD client allows a computer to import
       these GNBDs, and use them as if they were local block devices.  The primary difference between  GNBD  and  NBD  (the  network
       block device distributed with the Linux kernel) is GNBD’s ability to have multiple clients all accessing the same served file
       or block device at the same time.

Donc avantage de gnbd par rapport a nbd : on peut connecter plusieurs clients sur le même export.

Il s'agira là d'une config de base (sans cluster) mais qui utilisera un raid logiciel sur la machine cliente, raid composé d'un disque local et du périphérique nbd exporté depuis le serveur. Ce billet s'inspire de l'article de Fabien Germain paru dans Linux Mag 118.

L'install a été réalisée sur 2 machines debian s'exécutant sur un vmware-server-2.0.1-x86_64 (hôte : ubuntu 8.04.3 LTS noyau perso : 2.6.30)


Environnement:

Le serveur

isp:~# hostname --fqdn
isp.domaine.isp

isp:~# uname -a
Linux isp 2.6.26-2-686 #1 SMP Mon May 11 19:00:59 UTC 2009 i686 GNU/Linux

isp:~# ifconfig|grep 192
          inet adr:192.168.0.65  Bcast:192.168.0.255  Masque:255.255.255.0

isp:~# cat /etc/issue.net
Debian GNU/Linux 5.0

isp:~# free
             total       used       free     shared    buffers     cached
Mem:        256340     251744       4596          0       3512     224732
-/+ buffers/cache:      23500     232840
Swap:       409616         72     409544

isp:~# df -hT
Sys. de fich. Type     Tail. Occ. Disp. %Occ. Monté sur
/dev/sda1     ext3    7,5G  1,0G  6,2G  15% /
tmpfs        tmpfs    126M     0  126M   0% /lib/init/rw
udev         tmpfs     10M   80K   10M   1% /dev
tmpfs        tmpfs    126M     0  126M   0% /dev/shm

Le client:

clientgnbd:~# hostname --fqdn
clientgnbd.net.caen

clientgnbd:~# uname -a
Linux clientgnbd 2.6.26-2-686 #1 SMP Sun Jun 21 04:57:38 UTC 2009 i686 GNU/Linux

clientgnbd:~# ifconfig|grep 192
          inet adr:192.168.0.137  Bcast:192.168.0.255  Masque:255.255.255.0

clientgnbd:~# cat /etc/issue.net
Debian GNU/Linux 5.0

clientgnbd:~# free
             total       used       free     shared    buffers     cached
Mem:        256400     146036     110364          0       6804     126356
-/+ buffers/cache:      12876     243524
Swap:       176672          0     176672

clientgnbd:~# df -hT
Sys. de fich. Type     Tail. Occ. Disp. %Occ. Monté sur
/dev/sda1     ext3    2,3G  935M  1,3G  42% /
tmpfs        tmpfs    126M     0  126M   0% /lib/init/rw
udev         tmpfs     10M   80K   10M   1% /dev
tmpfs        tmpfs    126M     0  126M   0% /dev/shm


Installation du serveur:

isp:~# mkdir /gnbdshare

Comme je n'avais pas envie de recréer des disques virtuels pour cette petite expérience, je vais me contenter de périphériques loop auxquels j'attacherais des fichiers créés par dd .

Je crée donc un premier fichier de 100 Mo.

isp:~# dd if=/dev/zero of=/gnbdshare/disk bs=100M count=1
1+0 enregistrements lus
1+0 enregistrements écrits
104857600 bytes (105 MB) copied, 0,626201 s, 167 MB/s

Je recherche le premier loop disponible:

isp:~# losetup -f
/dev/loop0

J'attache ensuite mon fichier disk à ce périphérique:

isp:~# losetup /dev/loop0 /gnbdshare/disk

Et je le formatte comme un disque dur normal:

isp:~# mkfs -t ext3 /dev/loop0
mke2fs 1.41.3 (12-Oct-2008)
Étiquette de système de fichiers=
Type de système d'exploitation : Linux
Taille de bloc=1024 (log=0)
Taille de fragment=1024 (log=0)
25688 i-noeuds, 102400 blocs
5120 blocs (5.00%) réservés pour le super utilisateur
Premier bloc de données=1
Nombre maximum de blocs du système de fichiers=67371008
13 groupes de blocs
8192 blocs par groupe, 8192 fragments par groupe
1976 i-noeuds par groupe
Superblocs de secours stockés sur les blocs :
    8193, 24577, 40961, 57345, 73729

Écriture des tables d'i-noeuds : complété                       
Création du journal (4096 blocs) : complété
Écriture des superblocs et de l'information de comptabilité du système de
fichiers : complété

Le système de fichiers sera automatiquement vérifié tous les 34 montages ou
après 180 jours, selon la première éventualité. Utiliser tune2fs -c ou -i
pour écraser la valeur.
isp:~#

Maintenant passons à l'install de gnbd-server:

isp:~# apt-cache search gnbd
gnbd-client - Red Hat cluster suite - global network block device client tools
gnbd-server - Red Hat cluster suite - global network block device server tools
redhat-cluster-modules-2.6-486 - Redhat Cluster infrastructure for Linux 2.6 on x86
redhat-cluster-modules-2.6-686 - Redhat Cluster infrastructure for Linux 2.6 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6-686-bigmem - Redhat Cluster infrastructure for Linux 2.6 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6-amd64 - Redhat Cluster infrastructure for Linux 2.6 on AMD64
redhat-cluster-modules-2.6-openvz-686 - Redhat Cluster infrastructure for Linux 2.6 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6-vserver-686 - Redhat Cluster infrastructure for Linux 2.6 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6-vserver-686-bigmem - Redhat Cluster infrastructure for Linux 2.6 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6-xen-686 - Redhat Cluster infrastructure for Linux 2.6 on i686
redhat-cluster-modules-2.6.26-2-486 - Redhat Cluster infrastructure for Linux 2.6.26 on x86
redhat-cluster-modules-2.6.26-2-686 - Redhat Cluster infrastructure for Linux 2.6.26 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6.26-2-686-bigmem - Redhat Cluster infrastructure for Linux 2.6.26 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6.26-2-amd64 - Redhat Cluster infrastructure for Linux 2.6.26 on AMD64
redhat-cluster-modules-2.6.26-2-openvz-686 - Redhat Cluster infrastructure for Linux 2.6.26 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6.26-2-vserver-686 - Redhat Cluster infrastructure for Linux 2.6.26 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6.26-2-vserver-686-bigmem - Redhat Cluster infrastructure for Linux 2.6.26 on PPro/Celeron/PII/PIII/P4
redhat-cluster-modules-2.6.26-2-xen-686 - Redhat Cluster infrastructure for Linux 2.6.26 on i686
redhat-cluster-source - Red Hat cluster suite - kernel modules source


isp:~# apt-get install gnbd-server
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances      
Lecture des informations d'état... Fait
Les paquets suivants ont été installés automatiquement et ne sont plus nécessaires :
  libterm-readkey-perl
Veuillez utiliser « apt-get autoremove » pour les supprimer.
Les paquets supplémentaires suivants seront installés :
  libcman2
Paquets recommandés :
  fence-gnbd
Les NOUVEAUX paquets suivants seront installés :
  gnbd-server libcman2
0 mis à jour, 2 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de prendre 60,0ko dans les archives.
Après cette opération, 197ko d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer [O/n] ? O

.....
Paramétrage de gnbd-server (2.20081102-1) ...

Je vérifie le contenu du paquet:

isp:~# dpkg -L gnbd-server
/.
/etc
/etc/cluster
/etc/cluster/gnbdexports.conf
/etc/default
/etc/default/gnbd-server
/etc/init.d
/etc/init.d/gnbd-server
/usr
/usr/sbin
/usr/sbin/gnbd_clusterd
/usr/sbin/gnbd_export
/usr/sbin/gnbd_get_uid
/usr/sbin/gnbd_serv
/usr/share
/usr/share/man
/usr/share/man/man8
/usr/share/man/man8/gnbd.8.gz
/usr/share/man/man8/gnbd_export.8.gz
/usr/share/man/man8/gnbd_serv.8.gz
/usr/share/doc
/usr/share/doc/gnbd-server
/usr/share/doc/gnbd-server/README.Debian
/usr/share/doc/gnbd-server/README.source
/usr/share/doc/gnbd-server/copyright
/usr/share/doc/gnbd-server/changelog.Debian.gz

Et je paramètre:

isp:~# cat /etc/cluster/gnbdexports.conf
# <device> <exportname> <options>
/dev/loop0    gnbdisp  -c

isp:~# cat /etc/default/gnbd-server   (option -n pour indiquer qu'il ne faut pas rechercher un cluster)
GNBD_OPTIONS="-n"

isp:~# /etc/init.d/gnbd-server start
Starting global network block device server: gnbd_serv: startup succeeded
Exporting device(s):
gnbd_export: created GNBD gnbdisp serving file /dev/loop0
done.

Ca parait correct: vérifions tout de même:

isp:~# netstat -tpan|grep gnbd
tcp6       0      0 :::14567                :::*                    LISTEN      7600/gnbd_serv 

isp:~# gnbd_export
Server[1] : gnbdisp
--------------------------
      file : /dev/loop0
   sectors : 204800
  readonly : no
    cached : yes
   timeout : no



Installation du client:

Comme le conseille l'auteur de l'article sur LinuxMag, il est fortement déconseillé de laisser le port d'écoute du serveur (14567/tcp) ouvert sur internet. Ici je suis en réseau local derrière un routeur/pare-feu donc pas de soucis. Je vais quand même faire "comme si" et me connecter au serveur via un tunnel ssh.
Pour éviter les demandes de mot de passe à la connexion client->serveur, je copie ma clé ssh sur le serveur:

clientgnbd:~# ssh-keygen -t rsa

clientgnbd:~# ssh-copy-id root@isp.domaine.isp

clientgnbd:~# ssh root@isp.domaine.isp
Linux isp 2.6.26-2-686 #1 SMP Mon May 11 19:00:59 UTC 2009 i686

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jul 11 15:11:08 2009 from clientgnbd.net.caen
isp:~#
CTRL^D

C'est bon. Passons à l'install des paquets:

clientgnbd:~# apt-get install gnbd-client redhat-cluster-modules-2.6.26-2-686
Lecture des listes de paquets... Fait
Construction de l'arbre des dépendances      
Lecture des informations d'état... Fait
Les paquets supplémentaires suivants seront installés :
  libcman2 linux-image-2.6.26-2-486 redhat-cluster-modules-2.6.26-2-486
Paquets suggérés :
  linux-doc-2.6.26
Paquets recommandés :
  fence-gnbd redhat-cluster-modules
Les NOUVEAUX paquets suivants seront installés :
  gnbd-client libcman2 linux-image-2.6.26-2-486 redhat-cluster-modules-2.6.26-2-486 redhat-cluster-modules-2.6.26-2-686
0 mis à jour, 5 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de prendre 20,6Mo dans les archives.
Après cette opération, 60,7Mo d'espace disque supplémentaires seront utilisés.
Souhaitez-vous continuer [O/n] ? O

Le jeu des dépendances va également installer un noyau 2.6.26-2-486 (??!).


...
Paramétrage de libcman2 (2.20081102-1) ...
Paramétrage de gnbd-client (2.20081102-1) ...
Paramétrage de redhat-cluster-modules-2.6.26-2-486 (2.6.26+2.20081102-6+lenny1) ...
Paramétrage de redhat-cluster-modules-2.6.26-2-686 (2.6.26+2.20081102-6+lenny1) ...
clientgnbd:~#

Je charge le module gnbd et vérifie:

clientgnbd:~# modprobe gnbd

clientgnbd:~# lsmod|grep gnbd
gnbd                   68864  0

clientgnbd:~# tail -1 /var/log/kern.log
Jul 11 15:25:15 clientgnbd kernel: [ 3248.404829] gnbd: registered device at major 253

Maintenant je vais connecter mon serveur gnbd sur localhost via un tunnel ssh:

clientgnbd:~# ssh -C -L 14567:127.0.0.1:14567 -N root@isp.domaine.isp &
[1] 6914

-C : active la compression
-L : port local
-N : ne pas exécuter de commande sur le distant mais simplement activer le forwarding de port.
& : en tâche de fond pour reprendre la main (je pourrais supprimer ce forwarding en repassant le process au premier plan par fg  suivi d'un simple CTRL^C)

Maintenant voyons comment se connecter au prériphérique gnbd:

clientgnbd:~# gnbd_import -h

Usage:

gnbd_import [options]

Options:
  -a               validate all imported GNBDs, and remove the invalid ones
  -c <server>      list all nodes currently IO fenced from the server
  -e <server>      list all GNBDs exported by the server
  -h               print this help message
  -i <server>      import all GNBDs from the server
  -l               list all imported GNBDs [default action]
  -n               No cluster. Do not contact the cluster manager
  -O               Override prompts
  -p <port>        change the port to check on the GNBD server [default 14567]
  -q               quiet mode.
  -R               remove all imported GNBDs
  -r [GNBD | list] remove specified GNBD(s)
  -s <host>        IO fence the host (from known servers by default)
  -t <server>      specify a server for the IO fence (with -s or -u)
  -u <host>        unfence the host (from known servers by default)
  -U <GNBD>        get the Universal Identifier for the specified GNBD
  -V               version information
  -v               verbose output


clientgnbd:~# gnbd_import -e 127.0.0.1 -n
gnbdisp

Le client "voit" bien la ressource. On peut donc l'importer et la monter:

clientgnbd:~# gnbd_import -i 127.0.0.1 -n
gnbd_import: created directory /dev/gnbd
gnbd_import: created gnbd device gnbdisp
gnbd_recvd: gnbd_recvd started

clientgnbd:~# ls -ld /dev/gnbd
drwxr-xr-x 2 root root 60 jui 11 15:31 /dev/gnbd
clientgnbd:~# ls -l /dev/gnbd
total 0
brw-r--r-- 1 root root 253, 0 jui 11 15:31 gnbdisp

clientgnbd:~# mount /dev/gnbd/gnbdisp /mnt

clientgnbd:~# df -hT
Sys. de fich. Type     Tail. Occ. Disp. %Occ. Monté sur
/dev/sda1     ext3    2,3G 1020M  1,2G  46% /
tmpfs        tmpfs    126M     0  126M   0% /lib/init/rw
udev         tmpfs     10M   80K   10M   1% /dev
tmpfs        tmpfs    126M     0  126M   0% /dev/shm
/dev/gnbd/gnbdisp
              ext3     97M  5,6M   87M   7% /mnt


clientgnbd:~# cd /mnt

clientgnbd:/mnt# ls -la
total 17
drwxr-xr-x  3 root root  1024 jui 11 15:08 .
drwxr-xr-x 22 root root  4096 jui 11 15:23 ..
drwx------  2 root root 12288 jui 11 15:08 lost+found

clientgnbd:/mnt# touch essai

clientgnbd:/# for i in $(seq 2 5);do echo TEST > essai$i;done

clientgnbd:/mnt# ls
essai  essai2  essai3  essai4  essai5  lost+found


Le périphérique /dev/gnbd/gnbdisp est également accessible via gnbd0 (en clair mount /dev/gnbd0 fonctionne également).
Nous utiliserons d'ailleurs ce nom lors de la déclaration des périphériques raid.


Je vais maintenant configurer un raid logiciel utilisant un disque local (là encore ça sera un périphérique loop) et la ressource gnbd.

Je recrée donc un disque local comme je l'ai fait pour le serveur:

clientgnbd:~# losetup -f
/dev/loop0

clientgnbd:~# mkdir /gnbdshare

clientgnbd:~# dd if=/dev/zero of=/gnbdshare/disk bs=100M count=1
1+0 enregistrements lus
1+0 enregistrements écrits
104857600 bytes (105 MB) copied, 8,86013 s, 11,8 MB/s

clientgnbd:~# losetup /dev/loop0 /gnbdshare/disk

clientgnbd:~# mkfs -t ext3 /dev/loop0
mke2fs 1.41.3 (12-Oct-2008)
....
Superblocs de secours stockés sur les blocs :
    8193, 24577, 40961, 57345, 73729
....
Écriture des tables d'i-noeuds : complété                       
Création du journal (4096 blocs) : complété
Écriture des superblocs et de l'information de comptabilité du système de
fichiers : complété

Le système de fichiers sera automatiquement vérifié tous les 26 montages ou
après 180 jours, selon la première éventualité. Utiliser tune2fs -c ou -i
pour écraser la valeur.


Puis j'installe les outils pour la gestion du raid:

clientgnbd:~# apt-get install mdadm
....


Configuration de mdadm
...
Ensembles MD requis par le système de fichiers racine : none
Faut-il démarrer automatiquement les ensembles RAID ? NON

Je crée mon périphérique raid1 comme ceci:

clientgnbd:/# mdadm -Cv /dev/md0 -l1 -n2 /dev/loop0 missing
mdadm: /dev/loop0 appears to contain an ext2fs file system
    size=102400K  mtime=Thu Jan  1 01:00:00 1970
mdadm: size set to 102336K
Continue creating array? y
mdadm: array /dev/md0 started.

missing sera le périphérique gnbd qui contient pour l'instant les données (essai, essai2, essai3....)

clientgnbd:/# mkfs -t ext3 /dev/md0

clientgnbd:/# mount /dev/md0 /srv

Je vais maintenant recopier les données stockées sur gnbd sur mon raid:

clientgnbd:/# mount /dev/gnbd0 /mnt

clientgnbd:/# cd /mnt
clientgnbd:/mnt# ll
total 21
drwxr-xr-x  3 root root  1024 jui 11 15:53 .
drwxr-xr-x 23 root root  4096 jui 11 15:35 ..
-rw-r--r--  1 root root     0 jui 11 15:52 essai
-rw-r--r--  1 root root     5 jui 11 15:53 essai2
-rw-r--r--  1 root root     5 jui 11 15:53 essai3
-rw-r--r--  1 root root     5 jui 11 15:53 essai4
-rw-r--r--  1 root root     5 jui 11 15:53 essai5
drwx------  2 root root 12288 jui 11 15:50 lost+found

clientgnbd:/mnt# cp essai* /srv


Petite récap pour y voir clair:

clientgnbd:/# mount     
/dev/sda1 on / type ext3 (rw,errors=remount-ro)
tmpfs on /lib/init/rw type tmpfs (rw,nosuid,mode=0755)
proc on /proc type proc (rw,noexec,nosuid,nodev)
sysfs on /sys type sysfs (rw,noexec,nosuid,nodev)
udev on /dev type tmpfs (rw,mode=0755)
tmpfs on /dev/shm type tmpfs (rw,nosuid,nodev)
devpts on /dev/pts type devpts (rw,noexec,nosuid,gid=5,mode=620)
/dev/md0 on /srv type ext3 (rw)
/dev/gnbd0 on /mnt type ext3 (rw)

Je démonte ensuite mon périphérique gnbd pour le rattacher à la grappe raid:

clientgnbd:/# umount /mnt

clientgnbd:/# mdadm --add /dev/md0 /dev/gnbd0      
mdadm: added /dev/gnbd0
clientgnbd:/# cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 gnbd0[1] loop0[0]
      102336 blocks [2/2] [UU]
     
unused devices: <none>


Maintenant envisageons la tuile: le disque local (ici /dev/loop0 donc) lâche.

clientgnbd:~# mdadm /dev/md0 --set-faulty /dev/loop0
mdadm: set /dev/loop0 faulty in /dev/md0

clientgnbd:~# cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 gnbd0[1] loop0[2](F)
      102336 blocks [2/1] [_U]
     
unused devices: <none>

clientgnbd:~# mdadm /dev/md0 --remove /dev/loop0
mdadm: hot removed /dev/loop0

clientgnbd:~# cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 gnbd0[1]
      102336 blocks [2/1] [_U]
     
unused devices: <none>


Côté fichiers pas de problèmes ils sont toujours là:

clientgnbd:/srv# ls
essai  essai2  essai3  essai4  essai5  lost+found

On imagine donc un arrêt de la machine, changement de disque puis redémarrage.

clientgnbd:~# losetup -d /dev/loop0

clientgnbd:~# losetup -f
/dev/loop0

clientgnbd:~# losetup /dev/loop0 /gnbdshare/disk

Je réintegre le périph loop0 sur la grappe raid:

clientgnbd:~# mdadm /dev/md0 --add /dev/loop0
mdadm: re-added /dev/loop0

clientgnbd:~# cat /proc/mdstat
Personalities : [raid1]
md0 : active raid1 loop0[0] gnbd0[1]
      102336 blocks [2/2] [UU]
     
unused devices: <none>

Et je vérifie:

clientgnbd:~# ll /srv
total 21
drwxr-xr-x  3 root root  1024 jui 11 15:57 .
drwxr-xr-x 23 root root  4096 jui 11 15:35 ..
-rw-r--r--  1 root root     0 jui 11 15:57 essai
-rw-r--r--  1 root root     5 jui 11 15:57 essai2
-rw-r--r--  1 root root     5 jui 11 15:57 essai3
-rw-r--r--  1 root root     5 jui 11 15:57 essai4
-rw-r--r--  1 root root     5 jui 11 15:57 essai5
drwx------  2 root root 12288 jui 11 15:56 lost+found


Evidemment tout ceci a été réalisé en réseau local sur des disques de tailles ridiculement petites. Dans le cadre d'une utilisation wan, il faudrait probablement utiliser les fonctionnalités de cluster de gnbd pour éviter une dégradation des perfs.

A noter une autre utilisation des périphs blocs: vous avez lancé un gros traitement sur une machine et celle-ci arrive à cours de mémoire et d'espace disque (donc pas question de monter via un loop un fichier de swap). Vous pouvez ajouter du swap via un périph gnbd:

clientgnbd:~# free
             total       used       free     shared    buffers     cached
Mem:        256400     119820     136580          0      20088      84676
-/+ buffers/cache:      15056     241344
Swap:       176672          0     176672

clientgnbd:~# mkswap /dev/gnbd0
Setting up swapspace version 1, size = 104853 kB
no label, UUID=a6e18622-1ae3-4d5c-adb2-9296b655b19e

clientgnbd:~# swapon -a /dev/gnbd0
clientgnbd:~# free
             total       used       free     shared    buffers     cached
Mem:        256400     119940     136460          0      20116      84692
-/+ buffers/cache:      15132     241268
Swap:       279064          0     279064

clientgnbd:~# swapon -s          
Filename                Type        Size    Used    Priority
/dev/sda5                               partition    176672    0    -1
/dev/gnbd0                              partition    102392    0    -2