J'ai eu besoin de partager un disque entre deux serveurs et j'ai décidé de tenter l'utilisation de GFS2 bien qu'il ne soit pas encore réputé assez stable pour la production.
Pour effectuer les tests j'ai utilisé deux machines virtuelles (tournant sur un serveur XEN) installées en Debian 5.0 AMD64 dotées d'un processeur et 640Mo de RAM.
L'utilisation de GFS2 suppose de :
Tout noyau supérieur à 2.6.27 doit convenir parfaitement, ici j'ai utilisé un 2.6.30 (standard de Debian AMD64 en "unstable").
J'ai decidé d'utiliser le système le plus simple, ici CMAN.
L'installation de CMAN a été réalisée par un simple " aptitude install cman".
Toutefois la version installée de CMAN m'a posé un petit problème car elle tente de charger un module de gesion du lock DLM qui n'existe plus en 2.6.30 (c'est devenu une simple option de compilation du noyau). Quelques détails à ce sujet un peu plus loin.
Il m'a donc fallu modifier légèrement le script de démarrage ( /etc/init.d/cman ) afin de l'adapter.
Dans le cas de CMAN la défnition du "cluster" est assez simple si l'on n'utilise pas d'options de "fencing", ce que nous ferons ici.
Remarque : Le fencing est pratiquement obligatoire sur des sites de production mais cela suppose en général de disposer du hardware adéquat (fencing device ou cartes ILO sur les serveurs).
Le cluster se configure à l'aide d'un fichier de configuration en XML, la structure du fichier est assez simple tant que l'on n'utilise pas des options de "fencing" évoluées.
Fichier utilisé pour les tests :
| <?xml version="1.0"?> <cluster name="clusgfs2" config_version="1"> <!-- post_join_delay: number of seconds the daemon will wait before fencing any victims after a node joins the domain post_fail_delay: number of seconds the daemon will wait before fencing any victims after a domain member fails clean_start : prevent any startup fencing the daemon might do. It indicates that the daemon should assume all nodes are in a clean state to start. --> <fence_daemon clean_start="0" post_fail_delay="0" post_join_delay="3"/> <clusternodes> <clusternode name="amdx2-deb65" votes="1" nodeid="1"> ------ PREMIER NOEUD <fence> <!-- Handle fencing manually --> ------ FENCING "MANUEL" ! <method name="human"> <device name="human" nodename="amdx2-deb65"/> ------ Ouin, je ne suis qu'un device </method> </fence> </clusternode> <clusternode name="amdx2-deb66" votes="1" nodeid="2"> ------ DEUXIEME NOEUD <fence> <!-- Handle fencing manually --> ------ FENCING "MANUEL" ! <method name="human"> <device name="human" nodename="amdx2-deb66"/> </method> </fence> </clusternode> </clusternodes> <!-- cman two nodes specification --> <cman expected_votes="1" two_node="1"/> <fencedevices> <!-- Define manual fencing --> <fencedevice name="human" agent="fence_manual"/> </fencedevices> </cluster> |
Ce fichier doit, bien sûr être identique sur les deux serveurs puisque nous avons défini deux noeuds. On peut définir des clusters à trois, quatre noeuds ou plus.
Le lancement du cluster fonctionne sans problèmes avec un noyau 2.6.26 et échoue lamentablement sur un noyau 2.6.30 car le mode de gestion de la partie "DLM_LOCK" a changé :
Le script de démarrage fourni effectue un "modprobe" sur les modules nécessaires (il faut donc qu'ils soient compilés en modules et non intégrés au noyau !
Pour le fonctionnement en 2.6.30 un petit hack simple dans le script de démarrage "/etc/init.d/cman" :
avant :
errmsg=$( modprobe lock_dlm 2>&1 ) || true
Après :
| kernel_version=` uname -r ` case "$kernel_version" in 2.6.3?) ;; *) errmsg=$( modprobe lock_dlm 2>&1 ) || true ;; esac |
Comme cela le fonctionnement est OK en 2.6.26 et en 2.6.30 (il se replantera en 2.6.40).
Il existe quelques paramètres ajustables (temps de TIMEOUT ... temps de SYNCHRO au démarrage) accessibles en Debian dans "/etc/default/cman".
Je vous épargne la définition coté "fournisseur" iSCSI, le disque en iSCSI de 4GB est attaché (l) ou détaché (u) par le script suivant :
| TARGETNAME=' -T iqn.fr.jpp.xxxxxxx:storage.TESTGFS' IPPORT=' -p xxx.xxx.xxx.xxx:3260' case "$1" in l) echo 'l ' iscsiadm -m node $TARGETNAME $IPPORT -l ;; u) echo 'u' iscsiadm -m node $TARGETNAME $IPPORT -u ;; *) echo 'login (l) ou logout (u) ' ;; esac |
Le script suivant valorise les variables nécessaires aux scripts de formatage et de montage du système de fichier GFS2 :
| # "lock_nolock" --> local FS, "lock_dlm" --> shared FS LockProtoName='lock_dlm' # "Nom du cluster" LockTableName="clusgfs2:gfs2_A" # nb journal files -j NumberJournals=2 # taille journal en MBytes -J JournalSize=64 # taille de blocs du filesystem -b BlockSize=4096 # nom du device BlockDevice='/dev/sda1' |
La création du FS est alors simple :
mkfs -t gfs2 -b $BlockSize -p $LockProtoName -t $LockTableName -j $NumberJournals -J $JournalSize $BlockDevice
Le device étant initialisé on peut passer à l'étape suivante : le montage.
On réutilise les variables précédentes dans le script de montage :
mount -t gfs2 $BlockDevice /GFSDISK -o lockproto=$LockProtoName -o locktable=$LockTableName -o data=ordered -o relatime
Après un temps variable (il faut que le deuxième serveur du cluster soit démarré ou "fencé" manuellement) le montage est effectif. Se les deux serveurs sont présents (et lancés en même temps) la synchronisation est rapide, sinon le plus rapide "attends" le deuxième
et vous pouvez "voir" les fichiers présents sur les deux serveurs, écrire sur ce disque depuis les deux serveurs sans risque de corruption des données.