Ziirish's Home :: Blog

Ziirish's Pub

 
 

Contrairement à ce titre, je suis de moins en moins "collé" à mon PC comme vous avez pu le remarquer.

Mais bon, j'essaie de vous réserver quelques contenus que j'espère poilus rien que pour vous ;)

De quels poils collant vais-je bien pouvoir vous parler ?

Éh bien laissez-moi vous présenter glusterfs . Il s'agit d'un système de fichiers distribué. C'est à dire qu'il vous permet de faire grosso-modo ce que vous faites avec LVM mais réparti sur plusieurs machines.

J'ai du vaguement vous parler il y a quelques temps des backups que j'ai mis en place chez moi (ou peut-être pas). Comme vous le savez, je suis quand même assez geek sur les bords, mais surtout, très TRÈS TRÈS flemmard. Du coup, les solutions de backups artisanales à coup de scripts/cron/etc. ne me convenaient pas. Il me fallait un truc un peu plus robuste et simple dans ses fondements (mais cela ne veut pas forcément dire simple dans sa configuration).

Avant d'entrer dans les détails, je vais quand même vous faire un petit "speech" sur la sauvegarde. Oui, chez moi j'ai un RAID 1, mais NON, ça ne suffit pas. Le RAID n'est en rien une sauvegarde ! La sauvegarde est là pour palier en cas d'erreur le plus souvent humaine. Par exemple, la suppression accidentelle de fichiers. Elle peut (mais ne doit pas forcément) servir pour l'historisation, afin de revenir en arrière sur une conf qui se montrerait défectueuse après modification. Bref, la sauvegarde c'est BON, mangez-en !

Mais la sauvegarde à elle seule ne suffit pas. Ce serait effectivement déjà pas mal d'avoir une sauvegarde sur mon RAID, mais si mon serveur prend feu (ou si ma femme décide un jour de le balancer aux encombrants) ces sauvegardes ne me serviraient pas à grand chose.

On en arrive donc au coeur du sujet : GlusterFS. Ce système de fichiers distribué va me permettre de façon ULTRA simple (dans son fonctionnement toujours, pas forcément dans sa configuration) de répliquer mes données (ici les sauvegardes) sur différentes machines hébergées ici et là.

On réduit donc un peu plus les risques de pertes de données puisque si les 2 disques de mon RAID lâchent, que mon PC se retrouve aux encombrants, etc. Je vais pouvoir retrouver mes données sur un autre serveur hébergé ailleurs !

Voici donc les ingrédients :

  • 1 serveur à la maison en RAID 1
  • 1 serveur chez OVH

Ces serveurs tournent sur debian. La version de glusterfs présente dans les dépôts étant anté-diluvienne, j'ai récupéré une version à jour ici (sauf que mon installation commence à dater, donc je suis en 3.2.5).

Pré-requis :

  • Une partition de taille identique (pas obligé, mais c'est mieux pour un pseudo-RAID) sur chacune des machines
  • La possibilité pour les machines de se voir entre elles : OpenVPN dans mon cas
  • Un esprit tordu comme le miens

Avec tout ça, on est prêt pour le voyage !

On installe donc glusterfs sur nos machines, puis on démarre le démon :


% dpkg -i glusterfs_3.2.5-1_amd64.deb
Selecting previously deselected package glusterfs.
(Reading database ... 20415 files and directories currently installed.)
Unpacking glusterfs (from glusterfs_3.2.5-1_amd64.deb) ...
dpkg: dependency problems prevent configuration of glusterfs:
 glusterfs depends on libibverbs1 (>= 1.1.2); however:
  Package libibverbs1 is not installed.
 glusterfs depends on nfs-common; however:
  Package nfs-common is not installed.
dpkg: error processing glusterfs (--install):
 dependency problems - leaving unconfigured
Processing triggers for man-db ...
Errors were encountered while processing:
 glusterfs
% aptitude install libibverbs1 nfs-common
The following NEW packages will be installed:
  libevent-1.4-2{a} libgcrypt11{a} libgnutls26{a} libgpg-error0{a} libgssglue1{a} libibverbs1 libldap-2.4-2{a} libnfsidmap2{a} librpcsecgss3{a} libsasl2-2{a} 
  libsasl2-modules{a} libtasn1-3{a} nfs-common portmap{a} ucf{a} 
The following partially installed packages will be configured:
  glusterfs 
0 packages upgraded, 15 newly installed, 0 to remove and 39 not upgraded.
Need to get 1,978 kB of archives. After unpacking 4,923 kB will be used.
Do you want to continue? [Y/n/?] 
Get:1 http://mirror.ovh.net/debian/ squeeze/main libibverbs1 amd64 1.1.3-2 [33.7 kB]
Get:2 http://mirror.ovh.net/debian/ squeeze/main libevent-1.4-2 amd64 1.4.13-stable-1 [62.0 kB]
Get:3 http://mirror.ovh.net/debian/ squeeze/main libgssglue1 amd64 0.1-4 [24.1 kB]
Get:4 http://mirror.ovh.net/debian/ squeeze/main libgpg-error0 amd64 1.6-1 [43.9 kB]
Get:5 http://mirror.ovh.net/debian/ squeeze/main libgcrypt11 amd64 1.4.5-2 [282 kB]
Get:6 http://mirror.ovh.net/debian/ squeeze/main libtasn1-3 amd64 2.7-1+squeeze+1 [63.1 kB]
Get:7 http://mirror.ovh.net/debian/ squeeze/main libgnutls26 amd64 2.8.6-1+squeeze2 [564 kB]
Get:8 http://mirror.ovh.net/debian/ squeeze/main libsasl2-2 amd64 2.1.23.dfsg1-7 [115 kB]
Get:9 http://mirror.ovh.net/debian/ squeeze/main libldap-2.4-2 amd64 2.4.23-7.2 [210 kB]
Get:10 http://mirror.ovh.net/debian/ squeeze/main libnfsidmap2 amd64 0.23-2 [31.9 kB]
Get:11 http://mirror.ovh.net/debian/ squeeze/main librpcsecgss3 amd64 0.19-2 [35.7 kB]
Get:12 http://mirror.ovh.net/debian/ squeeze/main portmap amd64 6.0.0-2 [38.3 kB]
Get:13 http://mirror.ovh.net/debian/ squeeze/main ucf all 3.0025+nmu1 [69.6 kB]
Get:14 http://mirror.ovh.net/debian/ squeeze/main nfs-common amd64 1:1.2.2-4squeeze2 [250 kB]
Get:15 http://mirror.ovh.net/debian/ squeeze/main libsasl2-modules amd64 2.1.23.dfsg1-7 [155 kB]
Fetched 1,978 kB in 1s (995 kB/s)    
Preconfiguring packages ...
Selecting previously deselected package libibverbs1.
(Reading database ... 20705 files and directories currently installed.)
Unpacking libibverbs1 (from .../libibverbs1_1.1.3-2_amd64.deb) ...
Selecting previously deselected package libevent-1.4-2.
Unpacking libevent-1.4-2 (from .../libevent-1.4-2_1.4.13-stable-1_amd64.deb) ...
Selecting previously deselected package libgssglue1.
Unpacking libgssglue1 (from .../libgssglue1_0.1-4_amd64.deb) ...
Selecting previously deselected package libgpg-error0.
Unpacking libgpg-error0 (from .../libgpg-error0_1.6-1_amd64.deb) ...
Selecting previously deselected package libgcrypt11.
Unpacking libgcrypt11 (from .../libgcrypt11_1.4.5-2_amd64.deb) ...
Selecting previously deselected package libtasn1-3.
Unpacking libtasn1-3 (from .../libtasn1-3_2.7-1+squeeze+1_amd64.deb) ...
Selecting previously deselected package libgnutls26.
Unpacking libgnutls26 (from .../libgnutls26_2.8.6-1+squeeze2_amd64.deb) ...
Selecting previously deselected package libsasl2-2.
Unpacking libsasl2-2 (from .../libsasl2-2_2.1.23.dfsg1-7_amd64.deb) ...
Selecting previously deselected package libldap-2.4-2.
Unpacking libldap-2.4-2 (from .../libldap-2.4-2_2.4.23-7.2_amd64.deb) ...
Selecting previously deselected package libnfsidmap2.
Unpacking libnfsidmap2 (from .../libnfsidmap2_0.23-2_amd64.deb) ...
Selecting previously deselected package librpcsecgss3.
Unpacking librpcsecgss3 (from .../librpcsecgss3_0.19-2_amd64.deb) ...
Selecting previously deselected package portmap.
Unpacking portmap (from .../portmap_6.0.0-2_amd64.deb) ...
Selecting previously deselected package ucf.
Unpacking ucf (from .../ucf_3.0025+nmu1_all.deb) ...
Moving old data out of the way
Selecting previously deselected package nfs-common.
Unpacking nfs-common (from .../nfs-common_1%3a1.2.2-4squeeze2_amd64.deb) ...
Selecting previously deselected package libsasl2-modules.
Unpacking libsasl2-modules (from .../libsasl2-modules_2.1.23.dfsg1-7_amd64.deb) ...
Processing triggers for man-db ...
Setting up libibverbs1 (1.1.3-2) ...
Setting up libevent-1.4-2 (1.4.13-stable-1) ...
Setting up libgssglue1 (0.1-4) ...
Setting up libgpg-error0 (1.6-1) ...
Setting up libgcrypt11 (1.4.5-2) ...
Setting up libtasn1-3 (2.7-1+squeeze+1) ...
Setting up libgnutls26 (2.8.6-1+squeeze2) ...
Setting up libsasl2-2 (2.1.23.dfsg1-7) ...
Setting up libldap-2.4-2 (2.4.23-7.2) ...
Setting up libnfsidmap2 (0.23-2) ...
Setting up librpcsecgss3 (0.19-2) ...
Setting up portmap (6.0.0-2) ...
Starting portmap daemon....
Setting up ucf (3.0025+nmu1) ...
Setting up nfs-common (1:1.2.2-4squeeze2) ...

Creating config file /etc/idmapd.conf with new version

Creating config file /etc/default/nfs-common with new version
Adding system user `statd' (UID 104) ...
Adding new user `statd' (UID 104) with group `nogroup' ...
Not creating home directory `/var/lib/nfs'.
Starting NFS common utilities: statd.
Setting up glusterfs (3.2.5-1) ...
Setting up libsasl2-modules (2.1.23.dfsg1-7) ...

Current status: 0 broken [-1].
% /etc/init.d/glusterd start

Il y a également quelques dépendances "implicites" :


% aptitude install python fuse-utils rsync

Ensuite, on configure nos volumes sur l'un ou l'autre des serveurs. Les meta-données seront partagées sur tous nos noeuds, c'est magique ! On supposera pour la suite que nos serveurs ont respectivement les adresses 10.1.1.1 et 10.1.1.2. Ces adresses sont bien entendu celles sur réseau VPN.

On configure notre cluster :


server1% gluster
gluster> peer probe 10.1.1.2
Probe successful
gluster> peer status
Number of Peers: 1

Hostname: 10.1.1.2
Uuid: fcd15511-541d-4206-a2ab-4b59096b1d52
State: Peer in Cluster (Connected)

server2% gluster
gluster> peer status
Number of Peers: 1

Hostname: 10.1.1.1
Uuid: 969271a9-4886-4c80-96e7-b6839866b2c5
State: Peer in Cluster (Connected)

On crée ensuite nos volumes :


server2% mkdir /mnt/server1
server2% mkdir /mnt/server2

server1% mkdir /mnt/server1
server1% mkdir /mnt/server2
server1% gluster
gluster> volume create server1 10.1.1.1:/mnt/server1
Creation of volume server1 has been successful. Please start the volume to access data.
gluster> volume create server2 10.1.1.2:/mnt/server2
Creation of volume server2 has been successful. Please start the volume to access data.
gluster> volume start server1
Starting volume server1 has been successful
gluster> volume start server2
Starting volume server2 has been successful

server2% gluster
gluster> volume info all

Volume Name: server1
Type: Distribute
Status: Started
Number of Bricks: 1
Transport-type: tcp
Bricks:
Brick1: 10.1.1.1:/mnt/server1

Volume Name: server2
Type: Distribute
Status: Started
Number of Bricks: 1
Transport-type: tcp
Bricks:
Brick1: 10.1.1.2:/mnt/server2

Comme on peut le voir, on créée nos volumes depuis 'server1' et ces derniers sont automatiquement publiés sur 'server2'.

Nos volumes sont ainsi créés et disponibles tel des montages réseau :


server1% mount 10.1.1.1:/server1 /mnt/gluster -t glusterfs
server1% mount 10.1.1.2:/server2 /mnt/gluster2 -t glusterfs
server1% mount | grep glust
10.1.1.1:/server1 on /mnt/gluster type fuse.glusterfs (rw,allow_other,default_permissions,max_read=131072)
10.1.1.2:/server2 on /mnt/gluster2 type fuse.glusterfs (rw,allow_other,default_permissions,max_read=131072)
server1% touch /mnt/gluster/test_server1 /mnt/gluster2/test_server1 
server1% ls /mnt/gluster*
/mnt/gluster:
test_server1

/mnt/gluster2:
test_server1
server1% ls /mnt/server*
/mnt/server1:
test_server1

/mnt/server2:

server2% ls /mnt/server*
/mnt/server1:

/mnt/server2:
test_server1

OK, donc là on a un truc qui fonctionne. Avec les données qui sont bien copiées sur les devices "physiques". Sauf qu'en principe, sur un nœud local, on compose nos volumes gluster avec plusieurs machines. L'inconvénient de ça, c'est que la vitesse d'écriture sur le volume est égale à la plus faible vitesse disponible sur la grappe (c'est à dire : vitesse des disques + bande passante réseau entre les machines). Dans mon cas, j'ai souhaité utiliser glusterfs pour de la réplication distante de données. Et justement, sur les versions récentes de glusterfs, il y a ce qu'on appelle la geo-replication. C'est ce qui m'intéresse.

Le principe, c'est en quelque sorte un rsyncd. J'aurais pu tout à fait me passer de glusterfs, mais comme dit plus haut, j'ai un esprit quelque peu tordu ;) Pour commencer, comme nous le montre la configuration, nous avons besoin d'une paire de clés SSH :


server1% cat /etc/glusterd/geo-replication/gsyncd.conf 
[peersrx . %5Essh%3A]
remote_gsyncd = /usr/local/libexec/glusterfs/gsyncd

[__section_order__]
peersrx . %5essh%3a = 2
peersrx . = 3
peersrx . . = 0

[peersrx .]
log_file = /var/log/glusterfs/geo-replication-slaves/${session_owner}:${eSlave}.log
gluster_log_file = /var/log/glusterfs/geo-replication-slaves/${session_owner}:${eSlave}.gluster.log
gluster_command = /usr/sbin/glusterfs --xlator-option *-dht.assert-no-child-down=true

[__meta__]
version = 2.0

[peersrx . .]
gluster_log_file = /var/log/glusterfs/geo-replication/${mastervol}/${eSlave}.gluster.log
ssh_command = ssh -oPasswordAuthentication=no -oStrictHostKeyChecking=no -i /etc/glusterd/geo-replication/secret.pem
session_owner = 969271a9-4886-4c80-96e7-b6839866b2c5
remote_gsyncd = /usr/lib/glusterfs/glusterfs/gsyncd
state_file = /etc/glusterd/geo-replication/${mastervol}/${eSlave}.status
pid_file = /etc/glusterd/geo-replication/${mastervol}/${eSlave}.pid
log_file = /var/log/glusterfs/geo-replication/${mastervol}/${eSlave}.log
gluster_command = /usr/sbin/glusterfs --xlator-option *-dht.assert-no-child-down=true

On va donc générer puis copier nos clés sur l'ensemble des serveurs :


server1% ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /etc/glusterd/geo-replication/secret.pem
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /etc/glusterd/geo-replication/secret.pem.
Your public key has been saved in /etc/glusterd/geo-replication/secret.pem.pub.
The key fingerprint is:
89:32:3f:09:a4:84:fb:05:63:bc:0f:d8:27:ca:33:46 root@server1
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
| o               |
|. * .            |
| * *   . .       |
|oE* * . S        |
|oo * = .         |
|.=. . +          |
|. o    .         |
|                 |
+-----------------+
server1% ssh-copy-id -i /etc/glusterd/geo-replication/secret.pem.pub root@10.1.1.2
root@10.1.1.2's password: 
Now try logging into the machine, with "ssh 'root@10.1.1.2'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.
server1% ssh 10.1.1.2 -i /etc/glusterd/geo-replication/secret.pem
Linux lvs2 2.6.32-5-amd64 #1 SMP Mon Oct 3 03:59:20 UTC 2011 x86_64

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: Fri Aug  3 14:41:24 2012 from carbon.mendele.ev


server2% ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /etc/glusterd/geo-replication/secret.pem
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /etc/glusterd/geo-replication/secret.pem.
Your public key has been saved in /etc/glusterd/geo-replication/secret.pem.pub.
The key fingerprint is:
32:32:c3:5a:44:14:ce:29:f9:45:52:39:e1:93:04:8b root@lvs2
The key's randomart image is:
+--[ RSA 2048]----+
|   .*+=o         |
|   * Bo.         |
|  E * =.         |
|   = . .         |
|    B o S        |
|   o + o         |
|  .              |
|                 |
|                 |
+-----------------+
server2% ssh-copy-id -i /etc/glusterd/geo-replication/secret.pem.pub root@10.1.1.1
root@10.1.1.1's password: 
Now try logging into the machine, with "ssh 'root@10.1.1.1'", and check in:

  .ssh/authorized_keys

to make sure we haven't added extra keys that you weren't expecting.

Il ne nous reste plus qu'à configurer la geo-replication et regarder la magie opérer :)


server1% umount /mnt/gluster2
server1% gluster volume geo-replication server1 10.1.1.2:/mnt/server1 start
Starting geo-replication session between server1 & 10.1.1.2:/mnt/server1 has been successful

server2% mount 10.1.1.2:/server2 /mnt/gluster -t glusterfs
server2% gluster volume geo-replication server2 10.1.1.1:/mnt/server2 start
Starting geo-replication session between server2 & 10.1.1.1:/mnt/server2 has been successful
server2% gluster volume geo-replication status
MASTER               SLAVE                                              STATUS    
--------------------------------------------------------------------------------
server2              ssh://root@10.1.1.1:file:///mnt/server2           OK        
server1              ssh://root@10.1.1.2:file:///mnt/server1           OK        

Notre geo-replication est configurée o/ Il ne reste plus qu'à tester tout ça.


server1% dd if=/dev/zero of=/mnt/gluster/test_server1 count=20 bs=1M
20+0 records in
20+0 records out
20971520 bytes (21 MB) copied, 0.322933 s, 64.9 MB/s
server1% ls -lh /mnt/*
/mnt/gluster:
total 21M
-rw-r--r-- 1 root root 20M Aug  7 17:45 test_server1

/mnt/server1:
total 21M
-rw-r--r-- 1 root root 20M Aug  7 17:45 test_server1

/mnt/server2:
total 0

server2% dd if=/dev/zero of=/mnt/gluster/test_server2 count=20 bs=1M
20+0 records in
20+0 records out
20971520 bytes (21 MB) copied, 0.671373 s, 31.2 MB/s
server2% ls /mnt/*
/mnt/gluster:
test_server2

/mnt/server1:
test_server1

/mnt/server2:
test_server2


server1% ls /mnt/*
/mnt/gluster:
test_server1

/mnt/server1:
test_server1

/mnt/server2:
test_server2

Hé voilà, notre réplication est fonctionnelle et transparente !

Désormais, je peux configurer mes backups localement en exploitant la vitesse maximale de mes disques. Pour copier quelques Gio c'est quand même pratique plutôt que de passer des heures à cause du lien ADSL entre les serveurs ! La réplication elle est assurée de manière automatique et asynchrone grâce à glusterfs. De plus, comme il s'agit tout bonnement d'un rsync, je dispose d'une bonne tolérance aux coupures réseau (et quand on est chez un FAI comme Orange... c'est un argument de poids !).