Jul 28, 2009

Almacenamiento compartido en red: GFS2 + GNBD (I)

En el presente artículo vamos a desarrollar una arquitectura de almacenamiento compartido a la que accederán de forma concurrente un par de máquinas. Las pruebas van a ser realizadas bajo un sistema operativo de tipo CentOS 5.3.

El área de datos sobre el que se configurará el acceso compartido será un volumen lógico (LogVol00) cuyo sistema de archivos será GFS2 (Global File System 2).

GFS es un sistema de ficheros nativo creado por Red Hat y distribuido bajo licencia GNU, que puede ser utilizado de forma local (como por ejemplo ext3) o en cluster, de manera que varios nodos puedan estar trabajando simultáneamente sobre él sin peligro a que se corrompan los datos. El tamaño máximo de almacenamiento que soporta GFS2 es de 8 EB.

En la figura siguiente puede observarse que el espacio de almacenamiento compartido se instalará sobre la máquina centos01, el cual será exportado a los nodos centos02 y centos03 a través del driver GNBD (Global Network Block Device). GNBD proporciona acceso a almacenamiento en bloques a través de TCP/IP.


Cada una de las máquinas deberá tener registrado los nombres de todos los nodos en el fichero /etc/hosts.
[... ~]# cat /etc/hosts
...
192.168.1.11 centos01 centos01.local
192.168.1.12 centos02 centos02.local
192.168.1.13 centos03 centos03.local

SELinux deberá estar desactivado en los tres nodos, al igual que iptables. En el siguiente artículo veremos la forma de configurarlos correctamente para que no interfieran en el sistema de almacenamiento.
[... ~]# setenforce 0

[... ~]# service iptables stop

Lo primero que vamos a hacer es instalar el software necesario en los tres nodos (será el mismo para todos).
[... ~]# yum install lvm2-cluster rgmanager gfs2-utils gnbd kmod-gnbd

Seguidamente vamos a crear el volumen lógico que se empleará como espacio compartido en centos01, empleando para ello una partición de 64 GB que ya tendremos creada previamente y etiquetada como Linux LVM.
[root@centos01 ~]# fdisk -l
...
Disposit. Inicio Comienzo Fin Bloques Id Sistema
/dev/sdb1 1 8354 67103473+ 8e Linux LVM

Primero habrá que crear un volumen físico sobre esa partición, después el grupo de volúmenes (VolGroup01) y por último el volumen lógico (LogVol00).
[root@centos01 ~]# pvcreate /dev/sdb1

[root@centos01 ~]# vgcreate VolGroup01 /dev/sdb1

[root@centos01 ~]# lvcreate -l 100%FREE -n LogVol00 VolGroup01

Una vez que ya se tiene el volumen lógico, crearemos dentro de él un sistema de archivos GFS2. El parámetro lock_dlm indica el protocolo de bloqueo a emplear, siendo lock_dlm (DLM - Distributed Lock Manager) para el caso de acceso concurrente y lock_nolock para el caso de acceso de un único nodo. Con la opción de -t se especifica el nombre del cluster y el nombre que le queremos dar al sistema de archivos, y con la opción -j se indica el número de nodos que accederán concurrentemente al sistema de archivos.
[root@centos01 ~]# mkfs.gfs2 -p lock_dlm -t mycluster:gfs2_data -j 3 /dev/VolGroup01/LogVol00

A continuación se va a crear un archivo denominado cluster.conf el cual refleje la arquitectura de los tres nodos (deberá estar situado en las tres máquinas).
[... ~]# cat /etc/cluster/cluster.conf
<?xml version="1.0"?>
<cluster alias="mycluster" config_version="1" name="mycluster">
<fence_daemon clean_start="0" post_fail_delay="0" post_join_delay="3"/>
<clusternodes>
<clusternode name="centos01.local" nodeid="1" votes="1">
<fence>
<method name="1">
<device ipaddress="centos01.local" name="gnbd"/>
</method>
</fence>
</clusternode>
<clusternode name="centos02.local" nodeid="2" votes="1">
<fence>
<method name="1">
<device ipaddress="centos02.local" name="gnbd"/>
</method>
</fence>
</clusternode>
<clusternode name="centos03.local" nodeid="3" votes="1">
<fence>
<method name="1">
<device ipaddress="centos03.local" name="gnbd"/>
</method>
</fence>
</clusternode>
</clusternodes>
<cman/>
<fencedevices>
<fencedevice agent="fence_gnbd" name="gnbd" servers="centos01.local"/>
</fencedevices>
<rm>
<failoverdomains>
<failoverdomain name="failover_centos01" nofailback="0" ordered="0" restricted="1">
<failoverdomainnode name="centos01.local" priority="1"/>
</failoverdomain>
<failoverdomain name="failover_centos02" nofailback="0" ordered="0" restricted="1">
<failoverdomainnode name="centos02.local" priority="1"/>
</failoverdomain>
<failoverdomain name="failover_centos03" nofailback="0" ordered="0" restricted="1">
<failoverdomainnode name="centos03.local" priority="1"/>
</failoverdomain>
</failoverdomains>
<resources>
<script file="/etc/init.d/gnbd_client" name="gnbd_client"/>
<script file="/etc/init.d/gnbd_server" name="gnbd_server"/>
<clusterfs device="/dev/gnbd/gfs2_gnbd" force_unmount="0" fsid="45982" fstype="gfs2" mountpoint="/mnt/gfs2_gnbd/" name="resource_gfs2_gnbd" self_fence="0"/>
</resources>
<service autostart="1" domain="failover_centos01" exclusive="0" name="service_centos01">
<script ref="gnbd_server"/>
</service>
<service autostart="1" domain="failover_centos02" exclusive="0" name="service_centos02">
<script ref="gnbd_client">
<clusterfs ref="resource_gfs2_gnbd"/>
</script>
</service>
<service autostart="1" domain="failover_centos03" exclusive="0" name="service_centos03">
<script ref="gnbd_client">
<clusterfs ref="resource_gfs2_gnbd"/>
</script>
</service>
</rm>
</cluster>

En una primera sección (clusternodes) se definen los nombres de los tres nodos (clusternode name) así como su método fencing asociado. El fencing viene a ser una especie de protección o de bloqueo que hace que los nodos esperen en esa "barrera" para poder sincronizarse.

Para el caso del ejemplo anterior, se ha declarado un dispositivo (fencedevice) de tipo fence_gnbd en el nodo centos01, y a continuación se ha asociado a los tres nodos (fence). Esto significa que si por ejemplo iniciamos centos01, éste esperará a finalizar su proceso de arranque hasta que los otros dos nodos se hayan conectado al servidor GNBD, o si por ejemplo arrancamos centos02 y centos03, y centos01 todavía no está inicializado, esos dos nodos esperarán hasta que el servicio GNBD esté listo antes de lanzar el cliente.

La otra sección principal del fichero de configuración es la de los recursos. Se han definido tres recursos: un script de arranque y parada del cliente GNBD, otro script de arranque y parada para el servidor GNBD y un dispositivo (GFS2) que será montado en un directorio concreto (/mnt/gfs2_gnbd/).

A su vez se ha creado un dominio (failoverdomain) exclusivo para cada uno de los nodos. De esta forma podremos asociar posteriormente a cada uno de los dominios un determinado servicio (service), el cual iniciará y detendrá ciertos recursos (script ref, clusterfs, ...).

Así de esta forma el servicio service_centos02 hará que cuando se inicie automáticamente (autostart="1"), se lance sobre el nodo centos02 el script gnbd_client, y a continuación, se monte el recurso resource_gfs2_gnbd.

Para que el servicio GNBD (servidor) puede ser iniciado y detenido automáticamente por cman, dentro del directorio /etc/init.d/ crearemos un script denominado gnbd_server, al cual ya hemos hecho referencia en el fichero de configuración. Para ello haremos una copia del script sshd (con el objetivo de salvaguardar los contextos de SELinux) y lo cumplimentaremos con las líneas de código necesarias para gestionar el servidor GNBD.
[root@centos01 ~]# cp -a /etc/init.d/sshd /etc/init.d/gnbd_server

[root@centos01 ~]# vim /etc/init.d/gnbd_server
#!/bin/bash
#
# gnbd_server Startup script for the GNBD server
#
# chkconfig: - 23 77
# description: GNBD server

RETVAL=0

start()
{
echo -n $"Starting gnbd_server: "
modprobe gnbd
gnbd_serv
gnbd_export -d /dev/VolGroup01/LogVol00 -e gfs2_gnbd ; RETVAL=$?
echo
return $RETVAL
}

stop()
{
echo -n $"Stopping gnbd_server: "
gnbd_export -R
gnbd_serv -k ; RETVAL=$?
rmmod gnbd
echo
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
gnbd_export -l ; RETVAL=$?
;;
*)
echo $"Usage: service gnbd_server {start stop restart status}"
esac

exit $RETVAL

[root@centos01 ~]# chkconfig --add gnbd_server

Y ya por último, en los nodos centos02 y centos03 se importará automáticamente el volumen exportado por centos01, el cual estará accesible a través del dispositivo /dev/gnbd/gfs2_gnbd (cuando un dispositivo GNBD es importado, un dispositivo con el mismo nombre con el que fue exportado será creado en el directorio /dev/gnbd/).

Dicho dispositivo importado lo tendremos que montar en algún lugar. Para ello crearemos un directorio de montaje (/mnt/gfs2_gnbd).
[... ~]# mkdir /mnt/gfs2_gnbd

A continuación se muestra el script de arranque del cliente GNBD para los nodos centos02 y centos03.
[... ~]# cp -a /etc/init.d/sshd /etc/init.d/gnbd_client

[... ~]# vim /etc/init.d/gnbd_client
#!/bin/bash
#
# gnbd_client Startup script for the GNBD client
#
# chkconfig: - 25 75
# description: GNBD client

RETVAL=0

start()
{
echo -n $"Starting gnbd_client: "
modprobe gnbd ; sleep 3
gnbd_import -i centos01.local ; RETVAL=$?
echo
return $RETVAL
}

stop()
{
echo -n $"Stopping gnbd_client: "
gnbd_import -R ; RETVAL=$?
rmmod gnbd
echo
}

case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
gnbd_import -l ; RETVAL=$?
;;
*)
echo $"Usage: gnbd_client {start stop restart status}"
esac

exit $RETVAL

[... ~]# chkconfig --add gnbd_client

Ahora sólo tendremos que reiniciar los demonios gfs2, cman, rgmanager y clvmd en cada uno de los nodos, y mediante el comando chkconfig haremos que dichos demonios se inicien automáticamente cada vez que arranque el nodo.
[... ~]# service gfs2 restart

[... ~]# service cman restart

[... ~]# service rgmanager restart

[... ~]# service clvmd restart


[... ~]# chkconfig gfs2 on

[... ~]# chkconfig cman on

[... ~]# chkconfig rgmanager on

[... ~]# chkconfig clvmd on

Si ejecutamos el comando clustat, podremos ver la configuración actual del cluster que acabamos de levantar. Por un lado se tiene la lista de miembros del cluster (Member Name) y por el otro, la lista de servicios definidos (Service Name), así como su propietario (Owner) y estado (State).
[root@centos01 ~]# clustat
Cluster Status for mycluster @ Tue Jul 28 16:12:55 2009
Member Status: Quorate

Member Name ID Status
------ ---- ---- ------
centos03.local 1 Online, rgmanager
centos02.local 2 Online, rgmanager
centos01.local 3 Online, Local, rgmanager

Service Name Owner (Last) State
------- ---- ----- ------ -----
service:service_centos01 centos01.local started
service:service_centos02 centos02.local started
service:service_centos03 centos03.local started

Si en un momento dado deseamos conocer el número de nodos asociados al sistema GFS2, podremos ejecutar el siguiente comando:
[root@centos02 ~]# gfs2_tool journals /mnt/gfs2_gnbd/
journal2 - 128MB
journal1 - 128MB
journal0 - 128MB
3 journal(s) found.

3 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. Podrias explicar la diferecias con un sistema de archivos en red como GlusterFS.

    Animo, estoy muy en estos temas. Si necesitas ayuda avisame.

    Felicidades por el blog.

    ReplyDelete
  3. Hola,

    gracias por la felicitación.

    Me parece bastante interesante tu pregunta, así que a finales de la semana haré un artículo al respecto.

    Un saludo,

    ReplyDelete